WordPress: tudo sobre Widgets

Este post faz parte de um conjunto de artigos organizados em um Curso de WordPress. Acesse o link para outros conteúdos.

Este artigo ficou tão grande que tem até índice:

O que são widgets

O resumo do resumo seria dizer que widgets são os bloquinhos usados nas sidebars ou, em uma tradução livre, barras laterais. São mais do que isso porque podem também adicionar funcionalidades complexas a essas barras e também porque nem toda sidebar é, apesar do nome, uma barra “lateral”. A verdade é que com widgets podemos apresentar um formulário de busca, a lista de categorias, um cadastro de newsletter em todas as páginas, seja na lateral, no topo ou no rodapé do site.

Para que seu tema exiba widgets é necessário que ele tenha, pelo menos, uma área definida para isso. Embora seja usada a função register_sidebar() para esta definição (note o “sidebar” ali), você não está limitado a criar áreas somente nas laterais do site. Para generalizar vamos usar então o termo área para widgets, como consta no glossário do WordPress.

Como utilizar widgets

Se seu tema tem pelo menos uma área para widgets você pode utilizá-la indo no painel em Aparência → Widgets e arrastando o widget desejado para a área correta. Outra forma é indo em Aparência → Personalizar → Widgets, selecionando a área desejada e incluindo o widget. Não se esqueça de salvar.

Como criar e exibir suas próprias áreas

Como criar uma área para widgets

Definir uma área no seu tema é relativamente simples, basta chamar uma vez a função register_sidebar para cada área que se deseja criar. Para uma área lateral localizada à esquerda do seu conteúdo você poderia usar:

register_sidebar(array(
	'name' => 'Barra Lateral Esquerda', // Nome exibido na área administrativa
	'id' => 'barra_esquerda', // ID que será utilizado para chamar a função dynamic_sidebar()
	'description'   => 'Esta é a barra lateral esquerda do seu site', // Descrição exibida na área administrativa
	'before_widget' => '<div id="%1$s" class="widget %2$s">', // Abertura de uma tag que envolverá cada widget. %1$s será um id único para cada widget, $2$s uma classe para cada tipo de widget
	'after_widget' => '</div>', // Fechamento da tag de cima
	'before_title'  => '<h4>', // Tag exibida antes do título do widget
	'after_title'   => '</h4>', // Fechamento da tag de cima
));
Tela de widgets do WordPress com a área que acabamos de definir

Tela de widgets do WordPress com a área que acabamos de definir

O parâmetro before_widget é o único que merece um esclarecimento: quando arrastamos o widget para sua área, um número único é gerado para ele e, com esse número e um prefixo que se altera com o tipo de widget, é gerado o valor que será utilizado unicamente naquele widget, substituído por %1$s. Por exemplo: ao arrastarmos um widget de busca (o “Pesquisar”) para uma área, este widget vira o search-1, ao arrastarmos outro ele será o search-2. Os dois widgets receberão widget_search como valor em %2$s, ou seja, é uma classe comum a todos os widgets daquele tipo.

Exemplo de IDs e classes de widgets

Exemplo de IDs e classes de widgets

Nota: é possível criar várias áreas ao mesmo tempo com a função register_sidebars(), mas desta forma não é possível aplicar um id diferente a cada área.

Como exibir sua área de widgets

Para exibir sua área de widgets você precisará da função dynamic_sidebar(), passando como parâmetro o identificador da área que você criou. Uma função auxiliar é a is_active_sidebar(), que também recebe o identificador da área, e serve para testar se a área está ativa ou não. Juntando as duas ficaria assim:

<?php if ( is_active_sidebar( 'barra_esquerda' ) ) : ?>
	<div id="widget-area" class="widget-area">
		<?php dynamic_sidebar( 'barra_esquerda' ); ?>
	</div>
<?php endif; ?>

Como exibir widgets no meio do conteúdo

Com o plugin amr shortcode any widget é possível exibir qualquer widget no meio do conteúdo do seu post ou página. É só seguir os seguintes passos:

  1. Instale e ative o plugin;
  2. Adicione o widget necessário na área “Widgets for Shortcodes”;
  3. Salve o widget e copie o shortcode que é exibido logo depois de “To use as shortcode with id:”
  4. Cole o shortcode no conteúdo e salve.
Área para widgets gerada pelo "amr shortcode any widget"

Área para widgets gerada pelo “amr shortcode any widget”

Exemplo de inserção de shortcode no conteúdo

Exemplo de inserção de shortcode no conteúdo

Como exibir widgets só com código

É possível exibir plugins programaticamente utilizando a função the_widget(). A função recebe três parâmetros:

  1. O nome da classe PHP do widget
  2. Os dados da instância do widget
  3. Os dados para simular a área de widgets

No link da documentação existem exemplos mais completos, mas para exibir o mesmo widget do exemplo anterior nós só precisaríamos usar

the_widget('WP_Widget_Categories', array('title' => 'Categorias', 'count' => 1), array('before_title' => '<h2 class="titulo-categorias">'));

Como criar um widget no WordPress

Widgets são classes PHP que estendem WP_Widget, definida em wp-includes\class-wp-widget.php. Embora a classe WP_Widget não seja das mais complicadas, a classe que você irá criar será mais simples ainda, tendo apenas 4 métodos.

  1. __construct: o construtor, serve para registrar o id e a classe do seu widget;
  2. widget: exibe o conteúdo;
  3. form: exibe o formulário no painel do WordPress (título, exibir quantos itens, etc.) e
  4. update: processa as opções inseridas pelo usuário no formulário.

Um widget de Tópicos recentes de uma categoria específica

Vamos criar um widget simplificado parecido com o “Tópicos recentes”, que já vem com o WordPress, mas com a opção de escolher uma categoria específica:

 class Custom_Recent_Posts extends WP_Widget {
	 
	public function __construct(){
		parent::__construct( 
			'recent-posts-cat',
			'Tópicos Recentes por Categoria', 
			array(
				'classname' => 'widget_recent_entries widget_recent_entries_cat',
				'description' => 'Tópicos recentes por categoria',
			)
		);
	}


	public function widget( $args, $instance ) {
		extract($args);
		extract($instance);


		echo $before_widget;


		if ($title) {
			echo $before_title.$title.$after_title;
		}
		$posts = get_posts(array('category' => $cat));
		if (count($posts)) { ?>
			<ul>
				<?php foreach ($posts as $post) { setup_postdata( $post ); ?>
					<li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
				<?php } ?>
			</ul>
			<?php 
			wp_reset_postdata();
		}


		echo $after_widget;
	}


	public function form( $instance ) {
		$title     = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
		$cat = isset( $instance['cat'] ) ? absint($instance['cat']) : 0; ?>
		
		<p><label for="<?php echo $this->get_field_id('title'); ?>">Título:</label>
		<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p>


		<p><label for="<?php echo $this->get_field_id('cat'); ?>">Categoria:</label>
		<?php wp_dropdown_categories(array('hide_empty' => FALSE, 'id' => $this->get_field_id('cat'), 'name' => $this->get_field_name('cat'), 'selected' => $cat));
	}


	public function update( $new_instance, $old_instance ) {
		$instance = $old_instance;
		$instance['title'] = sanitize_text_field($new_instance['title']);
		$instance['cat'] = absint($new_instance['cat']);
		return $instance;
	}
}

Entendendo o código

A função construtora aceita até 4 argumentos:

  1. Base do ID: no nosso caso recent-posts-cat, será usado para montar os IDs html para cada widget instanciado, ou seja, este é o valor usado para %1$s com algumas (poucas) modificações feitas pelo WordPress;
  2. Nome: será usado para listar o widget no painel;
  3. Opções do Widget: array onde é possível definir o que será usado como classe (%2$s lá de cima) e a descrição exibida no painel e
  4. Um array opcional que quase nunca é usado, documentado aqui.

A função widget, responsável por exibi-lo, recebe dois arrays como argumentos: o dados definidos na criação da área de widgets onde ele será exibido e os dados do próprio widget, definidos no formulário pelo usuário. As duas primeiras linhas da nossa função usam a função extract() para definir os valores do array como variáveis, tornando mais fácil o uso: $before_widget, por exemplo, seria $args['before_widget'] se não chamássemos essa função anteriormente. O que fazemos então é abrir o widget com o que foi definido pelo usuário, exibir seu título caso ele tenha sido informado, exibir os posts da categoria determinada e fechar o widget. Lembre-se sempre de abrir o widget, fechá-lo, abrir o título e fechá-lo com o que foi definido pelo usuário, assim você evita inconsistências difíceis de detectar depois.

A função form, como dito anteriormente, exibe o formulário. Ela recebe os dados já salvos do widget, possibilitando exibir o formulário já preenchido. Atenção especial para usar get_field_id e get_field_name para gerar os parâmetros. Destaque para a função wp_dropdown_categories, que facilita demais a nossa vida na montagem do select.

A função update recebe dois argumentos: os dados que acabaram de ser salvos e os dados anteriores. Na maioria das vezes o que precisamos é somente validar os dados novos e sobrescrever os antigos.

Como registrar o widget

Para que o widget seja listado no painel é preciso registrá-lo, através da função register_widget() na action widgets_init. Já falei sobre filtros, actions e hooks aqui no blog, se você tem dúvidas vale a pena dar uma olhada. Ficaria assim:

function register_custom_recent_posts() {
	return register_widget("Custom_Recent_Posts");
}
add_action('widgets_init', 'register_custom_recent_posts');

Como a função de registro de widget normalmente é pequena você pode eliminar esse intermediário. Em versões de PHP acima ou iguais a 5.3 você pode usar:

add_action('widgets_init', function() { register_widget('Custom_Recent_Posts'); });

Para versões anteriores:>

add_action('widgets_init', create_function('', 'return register_widget("Custom_Recent_Posts");'));

Como desabilitar um widget

No tópico anterior vimos a função register_widget. Para desabilitar widgets é preciso usar a unregister_widget. Para evitar que o widget de Agenda, por exemplo, seja exibido no painel poderíamos usar:

function remove_calendar_widget() {
	unregister_widget('WP_Widget_Calendar');
}
add_action('widgets_init', 'remove_calendar_widget');

A função recebe como parâmetro o nome da classe que gera o widget. Os nomes das classes que já vem com o WordPress são:

  • WP_Widget_Pages: Páginas
  • WP_Widget_Calendar: Agenda
  • WP_Widget_Archives: Arquivos
  • WP_Widget_Meta: Meta
  • WP_Widget_Search: Pesquisar
  • WP_Widget_Text: Texto
  • WP_Widget_Categories: Categorias
  • WP_Widget_Recent_Posts: Tópicos recentes
  • WP_Widget_Recent_Comments: Comentários
  • WP_Widget_RSS: RSS
  • WP_Widget_Tag_Cloud: Nuvem de tags
  • WP_Nav_Menu_Widget: Menu personalizado

Como alterar um widget já existente

Mais comum que a necessidade de criar um widget é alterar alguma pequena parte de um já existente. Como não é possível alterar os arquivos do WordPress – você pode perder tudo na próxima atualização -, é preciso analisar cada caso e utilizar um filtro se for possível. Como widgets são classes, é possível ainda usar o conceito de extensão ou herança, criando uma nova classe que estende a do widget que desejamos alterar e modificando somente o funcionamento das funções corretas.

Como alterar o widget com filtros

Vamos supor que precisemos excluir uma categoria dos posts exibidos pelo widget de “Tópicos recentes”. Este widget é definido no arquivo wp-includes/widgets/class-wp-widget-recent-posts.php e os posts são escolhidos com o seguinte código, na linha 69 (versão 4.6.1):

$r = new WP_Query( apply_filters( 'widget_posts_args', array(
			'posts_per_page'      => $number,
			'no_found_rows'       => true,
			'post_status'         => 'publish',
			'ignore_sticky_posts' => true
		) ) );

Este código significa que podemos alterar os parâmetros de escolha dos posts usando o filtro widget_posts_args. Vamos usar o parâmetro category__not_in para excluir a categoria “Sem categoria”:

function exclude_recent_posts_cat($args) {
	$args['category__not_in'] = array(get_cat_ID('Sem categoria'));
	return $args;
}
add_filter('widget_posts_args', 'exclude_recent_posts_cat');

Infelizmente, usando este método, você não permite que o usuário escolha qual categoria excluir, mas pode ser um bom começo se você está com dificuldades para alterar um pequeno comportamento de algum widget.

A dica aqui é: veja o código-fonte e procure por um filtro ou action que possa ser usado.

Como alterar um widget usando orientação a objetos

Você pode criar uma classe que, ao invés de estender WP_Widget, estenda a do próprio widget a ser alterado.

Para alterar o html da lista que exibe os tópicos recentes, por exemplo, vamos usar:

 class Custom_HTML_Recent_Posts extends WP_Widget_Recent_Posts {
	public function __construct() {
		$widget_ops = array(
			'classname' => 'widget_recent_entries',
			'description' => __( 'Your site&#8217;s most recent Posts.' ),
			'customize_selective_refresh' => true,
		);
		WP_Widget::__construct( 'recent-posts', __( 'Recent Posts' ), $widget_ops );
		$this->alt_option_name = 'widget_recent_entries';
	}

	public function widget( $args, $instance ) {
		if ( ! isset( $args['widget_id'] ) ) {
			$args['widget_id'] = $this->id;
		}


		$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'Recent Posts' );


		/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
		$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );


		$number = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 5;
		if ( ! $number )
			$number = 5;
		$show_date = isset( $instance['show_date'] ) ? $instance['show_date'] : false;


		/**
		 * Filters the arguments for the Recent Posts widget.
		 *
		 * @since 3.4.0
		 *
		 * @see WP_Query::get_posts()
		 *
		 * @param array $args An array of arguments used to retrieve the recent posts.
		 */
		$r = new WP_Query( apply_filters( 'widget_posts_args', array(
			'posts_per_page'      => $number,
			'no_found_rows'       => true,
			'post_status'         => 'publish',
			'ignore_sticky_posts' => true
		) ) );


		if ($r->have_posts()) :
		?>
		<?php echo $args['before_widget']; ?>
		<?php if ( $title ) {
			echo $args['before_title'] . $title . $args['after_title'];
		} ?>
		<ul class="lista-de-posts">
		<?php while ( $r->have_posts() ) : $r->the_post(); ?>
			<li>
				<a href="<?php the_permalink(); ?>"><?php get_the_title() ? the_title() : the_ID(); ?></a>
			<?php if ( $show_date ) : ?>
				<span class="post-date"><?php echo get_the_date(); ?></span>
			<?php endif; ?>
			</li>
		<?php endwhile; ?>
		</ul>
		<?php echo $args['after_widget']; ?>
		<?php
		// Reset the global $the_post as this query will have stomped on it
		wp_reset_postdata();


		endif;
	}
}


function register_custom_html_recent_posts() {
	unregister_widget("WP_Widget_Recent_Posts");
	register_widget("Custom_HTML_Recent_Posts");
}
add_action('widgets_init', 'register_custom_html_recent_posts');

Entendendo o código

Primeira coisa a ser notada é que a nossa classe estende WP_Widget_Recent_Posts. Logo em seguida, no método construtor existem alguns detalhes importantes:

  1. Foi copiado o código de construção da classe WP_Widget_Recent_Posts;
  2. Onde se lia parent::__construct foi necessário trocar para WP_Widget::__construct. Isto acontece porque a parent, no nosso caso, chamaria WP_Widget_Recent_Posts::__construct que não recebe nenhum argumento e, portanto, não repassaria nada do que nós configurássemos. O código no exemplo é apenas para alertar deste fato, porque na verdade não seria necessário chamar o construtor com nada diferente já que vamos desabilitar o widget original mais pra baixo. Resumindo: se você for manter o widget original ou quiser fazer qualquer alteração no que for configurado nesse método não esqueça de alterar parent:: para WP_Widget::.
  3. O método widget é exatamente o mesmo, apenas coloquei uma classe na ul.
  4. Em register_custom_html_recent_posts desabilitamos o widget original e registramos o nosso, assim o usuário só terá uma opção para utilizar.

Conclusão

Widgets são ótimas maneiras de repetir porções de conteúdo ou funcionalidades pelas páginas, centralizando a administração. Se você viu esse código todo, não se sente a vontade de mexer, e prefere que um programdor mexa para você, fala com a gente lá na duo.me. Se você leu tudo isso parabéns, fique com uma foto do wappu aí embaixo, você merece. Não se esqueça de compartilhar, comentar e etc.

wapuu

Tags:

Comentários

  • Felipe Meirelles

    excelente explicação, parabéns pelo post!

  • Lome Card

    🙂