Entendendo os Actions, Filters e Hooks do WordPress

Hoje vamos abordar mais uma ferramenta (ou conjunto delas) que tornam o WordPress poderoso, robusto e personalizável. São os actions, filters e hooks (em tradução literal, ações, filtros e ganchos).

O assunto pode parecer muito focado aos desenvolvedores ou aventureiros de códigos mais atirados, mas entender como esses itens funcionam nos dá uma compreensão muito mais real de como o WordPress funciona e do seu processo de carregamento. O difícil vai ser definir esses itens com exatidão e simplicidade. O próprio codex apresenta apenas uma breve descrição e direciona as pessoas para uma listagem de actions e filters.
Algo como:
“Hooks são fornecidos pelo WordPress para permitir que o seu plugin (ou alguma funcionalidade do tema) adicione ações (actions) ou filtros (filters) específicos nesses ganchos, ou seja, para ativar funções nesses pontos específicos da execução do WordPress.”
Dito isso, podemos apelidar os actions e filters de anzóis, que podem ser lançados nesses hooks em momentos específicos da execução do WordPress.

Então, vamos colocar a mão massa e conhecer esses itens de uma forma mais prática.

Hooks

Como tentei sintetizar acima em apenas um parágrafo, os hooks são momentos na execução do WordPress. Sempre que falamos de hooks, temos as duas opções que são actions e filters, e esses são diferentes entre si.

Actions

A forma mais fácil de entendermos as actions é pensando que elas acontecem quando “algo aconteceu”. E durante o processo de carregamento do WordPress, muitas dessas estão acontecendo. E aqui conseguimos olhar para alguns exemplos que definem melhor o assunto:
init é o hook que determina o início do WordPress, muito usado para inicializar plugins; segundo o codex, ele é disparado depois que o usuário logado foi autenticado;
get_header é um hook e é inicializado logo após a chamada da função get_header, para exemplificar esse hook, inclusive porque ele é uma função e um hook. Veja esse exemplo do codex:
function themeslug_header_hook( $name ) {
	if ( 'new' == $name ) {
		add_action( 'wp_enqueue_scripts', 'themeslug_header_style' );
	}
}
add_action( 'get_header', 'themeslug_header_hook' );

function themeslug_header_style(){
	wp_enqueue_style( 'header-new-style', get_template_directory_uri() . '/css/header-new.css' );
}

Podemos então comentar a função add_action(). É com ela que adicionamos nossa função em um hook. No exemplo acima adicionamos a função themeslug_header_hook() quando o hook get_header for disparado. Com isso estamos imprimindo no HTML um novo arquivo de estilo CSS.

O mesmo vale para get_sidebar e get_footer.
Continuando a lista:
plugins_loaded é disparado assim que os plugins foram carregados, e precede os hooks  setup_theme e after_setup_theme;
pre_get_posts é disparado logo após a variável do objeto ser criado, mas antes dessa atual query rodar, vamos a outro exemplo específico:
function exclude_category( $query ) {
    if ( $query->is_home() && $query->is_main_query() ) {
        $query->set( 'cat', '-1,-1347' );
    }
}
add_action( 'pre_get_posts', 'exclude_category' );
Nessa função, adicionada ao hook pre_get_posts, estamos eliminando duas categorias do loop.
E então, com essa pequena lista de hooks actions podemos observar um caminho que o WordPress segue, e que em cada momento ele deixa pontos para que possamos adicionar nossas funções e personalizar dados e o próprio comportamento do site.
E qual a diferença em relação aos actions e os filters? Vamos ver..

Filters

Os filtros trabalham de uma forma bem diferente em relação aos actions. Com uma olhada rápida eles podem parecer praticamente a mesma coisa. Os filtros também são relacionados aos momentos de execução do WordPress (hooks), mas eles são responsáveis por interceptar, gerenciar e retornar os dados antes deles serem retornados ao navegador ou serem salvos no banco de dados. Simplificando, seria o momento no ciclo de execução do WordPress em que ele ainda não carregou a página ao navegador, mas que as informações vindas do banco de dados já estão disponíveis, para então serem manipuladas por esses filtros.
A lista de filters é quilométrica se comparada com a lista de hooks disponíveis, veja a lista completa de filters no codex do WordPress. Na documentação (codex) os filters são separados por áreas, são elas: Post, Pages, e Attachment (Upload) Filters; Comments, Trackback, e Ping Filters; Category e Term Filters; Link Filters; Date e Tempo Filters; Author e User Filters; Blogroll Filters; Blog Information e Opções Filters; Textos Gerais Filters; Administração Filters; Rich Text Editor Filters; Template Filters; Kubrick Filters; Registro e Login Filters; Redirect/Rewrite Filters; WP_Query Filters; Media Filters; Advanced WordPress Filters; Widgets; e Admin Bar.
Lendo apenas essas áreas é possível visualizar que a quantidade de possibilidade é praticamente infinita. Vamos a alguns exemplos e comentários sobre esses filters:
body_class é um filter que aplica classes a tag <body> do HTML, o filter usa a função get_body_class() que aceita como argumentos nomes de outras classes para adicionar ao body.
get_pre_excerpt é um filtro onde podemos aplicar ações antes do excerpt ser carregado no navegador, por exemplo para editar o final do excerpt, os […], veja esse exemplo (usado no tema TwentyEleven):
function twentyeleven_custom_excerpt_more( $output ) {
  if ( has_excerpt() && ! is_attachment() ) {
    $output .= twentyeleven_continue_reading_link();
  }
  return $output;
}
add_filter( 'get_the_excerpt', 'twentyeleven_custom_excerpt_more' );
Observamos aqui, assim como nos actions, que os filters são usados com a função add_filter(), que como argumento ela recebe um primeiro valor com o nome do filter que deseja usar e o segundo argumento o nome da função que deve ser disparada naquele momento.
private_title_format é um filter auto explicativo, usado para alterar o formato do título quando um post tem seu status marcado como Privado. Por padrão ele vem assim: Privado: Título do Post. E com esse filter é possível alterar ou remover esse Privado:.
wp_title é o filtro responsável por imprimir a tag <title> do HTML, com esse filter é possível mudar a forma como ele é apresentado. Isso é muito útil quando se está pensando a otimização SEO do site ou mesmo de deixar mais  claro o que o usuário está vendo naquela página.
login_redirect usado para redirecionar o usuários após realizar login no WordPress.
login_message aplicado para imprimir mensagens na tela de login.
sanitize_user esse faz a verificação do nome do user antes de criá-lo, para remover possíveis “sujeiras” desse campo.
registration_errors usado para criar uma lista com os erros ao adicionar uma nova pessoa como usuário.
bloginfo aplicado diretamente na configuração de opções do site quando recuperadas do banco de dados com a função bloginfo().
default_content usado para criar um texto default no content de uma nova postagem.
default_title usado para criar um texto default no título de uma nova postagem, veja um exemplo prático:
function title_text_input( $title ){
 return $title = 'Adicione um Título';
}
add_filter( 'enter_title_here', 'title_text_input' );
user_has_cap esse é um filtro um pouco mais complexo, que daria assunto para  um post completo, assim como já foi tema de uma palestra em um WordCamp de São Paulo. Com esse hook o WordPress usa algumas funções como WP_User->has_cap() para verificar, adicionar ou remover capacidades dessse usuário, fazendo com que ele possa ou não criar e editar posts ou mesmo ver alguma área da administração.
No codex possui um exemplo que pode ser mais ilustrativo para esse filter, veja:
function author_cap_filter( $allcaps, $cap, $args ) {

	// Bail out if we're not asking about a post:
	if ( 'edit_post' != $args[0] )
		return $allcaps;

	// Bail out for users who can already edit others posts:
	if ( $allcaps['edit_others_posts'] )
		return $allcaps;

	// Bail out for users who can't publish posts:
	if ( !isset( $allcaps['publish_posts'] ) or !$allcaps['publish_posts'] )
		return $allcaps;

	// Load the post data:
	$post = get_post( $args[2] );

	// Bail out if the user is the post author:
	if ( $args[1] == $post->post_author )
		return $allcaps;

	// Bail out if the post isn't pending or published:
	if ( ( 'pending' != $post->post_status ) and ( 'publish' != $post->post_status ) )
		return $allcaps;

	// Load the author data:
	$author = new WP_User( $post->post_author );

	// Bail out if post author can edit others posts:
	if ( $author->has_cap( 'edit_others_posts' ) )
		return $allcaps;

	$allcaps[$cap[0]] = true;

	return $allcaps;

}
add_filter( 'user_has_cap', 'author_cap_filter', 10, 3 );

Concluindo…

Bom, são muitas informações para serem processadas de uma só vez! O melhor aqui é parar e estudar esses filters, como eles se comportam dentro do ciclo de execução do WordPress e então tirar proveito disso.
Para quem desenvolve plugins e temas, esses itens são fundamentais e facilitam até mesmo em substituição de alguns plugins ou funções enormes no seu functions.php. Parando e pensando um pouco, podemos usar essas informações em muitas situações do cotidiano – por exemplo, disparar um e-mail para o administrador do site a cada comentário realizado ou post publicado. Outra possibilidade e que é muito recorrente nos meus trabalhos é no agendamento de ações, onde determino que de tempos em tempos o WordPress execute uma função, por exemplo fechar comentários em posts antigos, ou colocar como rascunho posts de eventos que já passaram em uma agenda, por exemplo.
Se você usa algum action/filter/hook de forma criativa em seus projetos, compartilhe nos comentários sua experiência. Em caso de dúvidas, deixe um comentário e juntos vamos encontrar uma solução.

3 comentários

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *