15%

Poupe 15% em todos os serviços

Teste as suas habilidades e obtenha Desconto em qualquer plano

Utilizar o código:

Skills
Começar a trabalhar
21.10.2024

Hooks do WordPress Explicados: Actions, Filters e Padrões de Uso Avançado

Os hooks do WordPress são um mecanismo arquitetural central que permite aos desenvolvedores injetar código personalizado em pontos de execução predefinidos dentro do WordPress — sem modificar ficheiros principais, temas ou plugins de terceiros. Existem exatamente dois tipos: action hooks, que acionam funções personalizadas em eventos específicos, e filter hooks, que intercetam e transformam dados antes de serem renderizados ou persistidos. Dominar ambos é indispensável para qualquer trabalho sério de desenvolvimento WordPress.

Este guia vai além do básico. Encontrará referências de sintaxe precisas, casos extremos do mundo real, mecânicas de prioridade e padrões arquiteturais que separam o código WordPress sustentável de hacks frágeis e propensos a conflitos.

O Sistema de Hooks do WordPress: Como Funciona Internamente

O WordPress executa numa sequência previsível — inicializando o núcleo, carregando plugins, carregando o tema ativo e depois renderizando a página solicitada. Ao longo deste ciclo de vida, o motor chama do_action() e apply_filters() em centenas de pontos predefinidos. Essas chamadas são os hooks.

Quando regista um callback com add_action() ou add_filter(), o WordPress armazena-o num array global $wp_filter, indexado pelo nome do hook e prioridade. Em tempo de execução, quando o hook é acionado, o WordPress itera por cada callback registado por ordem de prioridade e executa-os sequencialmente.

Esta arquitetura significa:

  • Nunca toca nos ficheiros principais do WordPress (wp-includes/, wp-admin/)
  • As suas personalizações sobrevivem intactas às atualizações do núcleo
  • Múltiplos plugins podem anexar-se ao mesmo hook sem conflito — desde que as prioridades sejam geridas corretamente

Todos os registos de hooks devem residir num plugin personalizado ou no functions.php do seu tema. Para ambientes de produção a correr num plano de VPS Hosting, implementar personalizações como um plugin autónomo é fortemente preferível em relação ao functions.php, porque uma mudança de tema não apagará silenciosamente a sua funcionalidade.

Action Hooks vs. Filter Hooks: Diferenças Fundamentais

AtributoAction HooksFilter Hooks
Propósito principalExecutar efeitos secundários num evento específicoIntercetar e transformar dados
Valor de retorno obrigatórioNão — os callbacks não retornam nadaSim — os callbacks DEVEM retornar um valor
Função principal para acionar`do_action()``apply_filters()`
Função principal para registar`add_action()``add_filter()`
Função de remoção`remove_action()``remove_filter()`
Casos de uso típicosEnfileirar scripts, enviar emails, registar eventosModificar conteúdo, alterar títulos, transformar argumentos de query
Dados passados ao callbackArgumentos contextuais opcionaisO valor de dados a ser filtrado (obrigatório)
Comportamento de encadeamentoOs callbacks correm em sequência, independentementeCada callback recebe o resultado do anterior

O erro mais comum que os desenvolvedores cometem é esquecer de return um valor dentro de um callback de filtro. Se omitir a instrução return, o valor filtrado torna-se null, o que irá silenciosamente quebrar o output no front end — um bug notoriamente difícil de rastrear.

Action Hooks: Análise Aprofundada

Sintaxe e Parâmetros

add_action( string $hook_name, callable $callback, int $priority = 10, int $accepted_args = 1 );
  • $hook_name — O nome exato do hook ao qual se anexar.
  • $callback — Qualquer callable PHP válido: uma função nomeada, uma função anónima, um método estático (['ClassName', 'method']), ou um método de objeto ([$object, 'method']).
  • $priority — Ordem de execução relativa a outros callbacks no mesmo hook. Números mais baixos correm primeiro. O padrão é 10. Use inteiros negativos para correr antes de todos os callbacks padrão.
  • $accepted_args — Quantos argumentos o seu callback aceitará do hook. Deve corresponder ao que do_action() passa, ou receberá um aviso PHP.

Exemplo Básico: Adicionar Conteúdo Após Cada Post

add_action( 'the_content', 'alexhost_append_cta', 20 );

function alexhost_append_cta( $content ) {
    if ( is_single() && in_the_loop() && is_main_query() ) {
        $content .= '<p class="post-cta">Enjoyed this article? Share it with your network.</p>';
    }
    return $content;
}

Note as proteções in_the_loop() e is_main_query(). Sem elas, o seu callback é acionado em cada chamada a the_content() — incluindo áreas de widgets, page builders e respostas da REST API — produzindo output duplicado que é extremamente difícil de depurar.

Exemplo Avançado: Enviar uma Notificação Slack ao Publicar um Post

add_action( 'transition_post_status', 'alexhost_notify_on_publish', 10, 3 );

function alexhost_notify_on_publish( $new_status, $old_status, $post ) {
    if ( 'publish' === $new_status && 'publish' !== $old_status && 'post' === $post->post_type ) {
        $webhook_url = defined( 'SLACK_WEBHOOK_URL' ) ? SLACK_WEBHOOK_URL : '';
        if ( empty( $webhook_url ) ) {
            return;
        }
        wp_remote_post( $webhook_url, [
            'body'        => wp_json_encode( [ 'text' => 'New post published: ' . get_permalink( $post ) ] ),
            'headers'     => [ 'Content-Type' => 'application/json' ],
            'data_format' => 'body',
        ] );
    }
}

Este padrão usa transition_post_status em vez de publish_post porque fornece tanto o estado antigo como o novo, permitindo distinguir uma primeira publicação de uma atualização a um post já publicado.

Remover uma Action Registada por Outro Plugin

remove_action( 'wp_footer', 'some_plugin_footer_function', 10 );

O valor de prioridade em remove_action() deve corresponder exatamente à prioridade usada na chamada original add_action(). Se não souber a prioridade, inspecione o código-fonte do plugin ou use uma ferramenta de depuração de hooks. Uma incompatibilidade significa que a remoção falha silenciosamente — a função continua a correr.

Filter Hooks: Análise Aprofundada

Sintaxe e Parâmetros

add_filter( string $hook_name, callable $callback, int $priority = 10, int $accepted_args = 1 );

A assinatura é idêntica à de add_action(). A diferença comportamental crítica: o seu callback recebe o valor atual dos dados filtrados como primeiro argumento e deve retornar um valor.

Exemplo Básico: Converter Títulos de Posts para Title Case

add_filter( 'the_title', 'alexhost_titlecase_post_title', 10, 2 );

function alexhost_titlecase_post_title( $title, $post_id ) {
    if ( is_admin() ) {
        return $title;
    }
    return mb_convert_case( $title, MB_CASE_TITLE, 'UTF-8' );
}

Usar mb_convert_case() em vez de strtoupper() é a abordagem correta para sites multilingues. strtoupper() não é seguro para multibyte e irá corromper caracteres em scripts não-latinos.

Exemplo Avançado: Modificar os Argumentos da Query Principal

add_filter( 'pre_get_posts', 'alexhost_exclude_category_from_home' );

function alexhost_exclude_category_from_home( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_home() ) {
        $query->set( 'category__not_in', [ 5, 12 ] );
    }
}

pre_get_posts é tecnicamente um action hook (não requer retorno), mas modifica o objeto WP_Query por referência — fazendo-o comportar-se como um filtro. Este é um ponto comum de confusão. Modifica $query diretamente; não o retorna.

Encadeamento de Filtros: O Que os Desenvolvedores Ignoram

Quando múltiplos callbacks se anexam ao mesmo filtro, cada um recebe o output do anterior. Se o callback A na prioridade 10 transforma $content e o callback B na prioridade 11 também transforma $content, B opera sobre o output de A — não sobre o original. Este encadeamento é poderoso mas requer planeamento deliberado de prioridades quando múltiplos plugins tocam nos mesmos dados.

Prioridade e Ordem de Execução: Referência Prática

Valor de PrioridadeQuando CorreCaso de Uso Típico
`1` – `9`Antes dos padrões do WordPressSubstituir comportamento do núcleo antecipadamente
`10`PadrãoPersonalizações padrão de plugin/tema
`11` – `19`Após o padrão, antes dos hooks tardiosPós-processar o output de outro plugin
`20` – `99`Execução tardiaLimpeza, formatação final
`PHP_INT_MAX`Absolutamente últimoExecução de último recurso garantida
Negativo (ex., `-1`)Antes de tudoTarefas de pré-inicialização

Referência de Hooks Essenciais do WordPress

Action Hooks de Alto Valor

  • init — Aciona após o WordPress carregar mas antes de os cabeçalhos serem enviados. Use-o para registar tipos de post personalizados, taxonomias e regras de reescrita. Evite usar plugins_loaded para registo de CPT — aciona demasiado cedo.
  • wp_enqueue_scripts — O único lugar correto para enfileirar CSS e JavaScript do front-end. Nunca use wp_head diretamente para injeção de scripts.
  • admin_enqueue_scripts — Enfileirar assets exclusivamente no painel de administração. Aceita um argumento $hook_suffix para direcionar páginas de administração específicas.
  • wp_footer — Aciona imediatamente antes de </body>. Ideal para snippets de análise, scripts diferidos e markup não crítico.
  • save_post — Aciona após um post ser guardado. Use-o para acionar invalidação de cache, sincronizar dados com APIs externas ou atualizar meta personalizado. Verifique sempre o nonce e verifique wp_is_post_revision() para evitar duplo acionamento.
  • template_redirect — Aciona antes de o WordPress determinar qual template carregar. Use-o para redirecionamentos personalizados ou controlo de acesso.
  • wp_login — Aciona no login bem-sucedido de um utilizador. Útil para registo de auditoria ou gestão de sessões em sites multi-utilizador.

Filter Hooks de Alto Valor

  • the_content — Filtra o conteúdo do post antes da exibição. Esteja ciente: este hook aciona em cada chamada a get_the_content(), incluindo respostas da REST API no WordPress 5.5+.
  • the_title — Filtra títulos de posts e páginas. Recebe tanto $title como $post_id como argumentos quando $accepted_args está definido como 2.
  • excerpt_length — Controla a contagem de palavras dos excertos gerados automaticamente. Retorna um inteiro.
  • upload_mimes — Filtra a lista de tipos MIME de upload permitidos. Use isto para ativar uploads SVG (com sanitização adequada) ou restringir uploads a tipos de ficheiro específicos.
  • wp_nav_menu_items — Filtra o output HTML dos menus de navegação. Útil para injetar itens dinâmicos como links de login/logout.
  • body_class — Filtra o array de classes CSS aplicadas à tag <body>. Aceita um array, não uma string — uma fonte frequente de bugs.
  • cron_schedules — Adiciona intervalos personalizados ao WP-Cron. Essencial para tarefas de processamento em segundo plano em sites alojados em Servidores Dedicados onde também pode configurar um cron de sistema verdadeiro como substituto.

Criar Hooks Personalizados em Plugins e Temas

Plugins bem arquitetados expõem os seus próprios hooks para que outros desenvolvedores os possam estender sem fazer fork do código. Esta é a marca do desenvolvimento WordPress de nível profissional.

Definir um Action Hook Personalizado

// Inside your plugin's core function
function alexhost_process_order( $order_id ) {
    // ... processing logic ...

    // Fire a custom action so other code can react
    do_action( 'alexhost_order_processed', $order_id );
}

Definir um Filter Hook Personalizado

function alexhost_get_product_price( $product_id ) {
    $base_price = get_post_meta( $product_id, '_price', true );

    // Allow other code to modify the price before returning it
    return apply_filters( 'alexhost_product_price', $base_price, $product_id );
}

Qualquer plugin ou tema pode agora ligar-se a alexhost_product_price para aplicar descontos, conversão de moeda ou cálculos de impostos — sem tocar no código-fonte do seu plugin.

Remover e Substituir Hooks: Padrões Avançados

Remover um Hook Registado Dentro de uma Classe

Este é um dos aspetos mais mal compreendidos do sistema de hooks. Se um plugin regista um método usando uma instância de objeto, não pode removê-lo com uma simples referência de string.

// Plugin registers like this:
$plugin_instance = new SomePlugin();
add_action( 'init', [ $plugin_instance, 'setup' ] );

// To remove it, you need access to the same object instance.
// One approach: hook into plugins_loaded and use the global instance if exposed.
add_action( 'plugins_loaded', function() {
    global $some_plugin;
    if ( isset( $some_plugin ) && is_a( $some_plugin, 'SomePlugin' ) ) {
        remove_action( 'init', [ $some_plugin, 'setup' ] );
    }
}, 20 );

Se o plugin não expõe a sua instância globalmente, deve iterar $GLOBALS['wp_filter'] diretamente — uma abordagem frágil que indica que o plugin alvo tem má arquitetura.

Usar has_action() e has_filter() Defensivamente

if ( has_action( 'wp_footer', 'some_third_party_function' ) ) {
    remove_action( 'wp_footer', 'some_third_party_function' );
}

has_action() retorna a prioridade do callback registado (um inteiro) se encontrado, ou false se não. Este valor de retorno é frequentemente mal utilizado — os desenvolvedores verificam if ( has_action(...) ) esperando um booleano, mas receber 0 (uma prioridade válida) avalia como falsy. Use sempre !== false para uma verificação fiável:

if ( false !== has_action( 'wp_footer', 'some_third_party_function' ) ) {
    remove_action( 'wp_footer', 'some_third_party_function', 0 );
}

Considerações de Desempenho para Ambientes de Produção

Os hooks adicionam uma sobrecarga mínima individualmente, mas callbacks mal escritos acumulam-se em latência mensurável. Padrões-chave a seguir:

  • Proteja operações dispendiosas com condicionais. Queries de base de dados, chamadas a APIs remotas e I/O de ficheiros dentro de callbacks de hooks devem ser envolvidos em verificações condicionais (is_single(), is_admin(), is_main_query()) para evitar que corram em cada carregamento de página.
  • Use cache de objetos. Se um callback de hook obtém dados da base de dados, envolva o resultado num transient ou use wp_cache_get() / wp_cache_set(). Num VPS com cPanel devidamente configurado ou num servidor a correr Redis, isto reduz dramaticamente as viagens de ida e volta à base de dados.
  • Evite funções anónimas quando precisar de remover hooks. Não pode chamar remove_action() numa função anónima porque não tem referência a ela. Use sempre funções nomeadas ou referências armazenadas para callbacks que possa precisar de desregistar.
  • Audite a carga de hooks com o Query Monitor. O plugin Query Monitor fornece um painel dedicado “Hooks & Actions” mostrando cada hook que foi acionado durante um pedido, os callbacks anexados e o seu tempo de execução. Isto é indispensável para diagnosticar regressões de desempenho em sites de alto tráfego.

Considerações de Segurança

Os hooks são uma superfície de ataque comum em plugins mal escritos. Riscos específicos a compreender:

  • Input não validado em callbacks save_post. Verifique sempre o nonce (check_admin_referer()), confirme current_user_can(), e sanitize todos os dados $_POST antes de processar.
  • Escalada de privilégios via hooks init. Código que modifica funções ou capacidades de utilizador dentro de init sem uma verificação de capacidade pode ser acionado por pedidos não autenticados.
  • Injeção de filtro. Se um callback de filtro envia dados diretamente para a página sem escape, torna-se um vetor XSS. Os filtros devem transformar dados; o escape deve acontecer no ponto de output usando esc_html(), esc_attr(), ou wp_kses_post().
  • SSRF via pedidos HTTP acionados por hooks. Callbacks que fazem chamadas wp_remote_get() baseadas em URLs fornecidos pelo utilizador (ex., em save_post) devem validar e sanitizar o URL com esc_url_raw() e idealmente restringir os hosts permitidos.

Para sites que lidam com dados sensíveis ou transações de e-commerce, combinar a sua instalação WordPress com uma configuração adequada de Certificados SSL é um requisito básico — hooks que transmitem dados para endpoints externos através de ligações não encriptadas são uma vulnerabilidade crítica.

Lista de Verificação de Boas Práticas

  • Use nomes de funções únicos e com namespace (ex., myplugin_functionname) para evitar colisões com o núcleo, temas e outros plugins.
  • Especifique sempre $accepted_args quando o seu callback precisa de mais de um argumento do hook.
  • Nunca use echo dentro de um callback de filtro — apenas return.
  • Coloque os registos de hooks dentro de uma verificação condicional ou função de inicialização, não no âmbito global de um ficheiro que possa ser incluído múltiplas vezes.
  • Documente cada hook personalizado que expõe com docblocks @hook para que outros desenvolvedores os possam descobrir.
  • Teste a remoção de hooks com correspondência exata de prioridade — uma incompatibilidade é uma falha silenciosa.
  • Use current_filter() dentro de um callback para confirmar qual hook o acionou quando uma única função está anexada a múltiplos hooks.

Matriz de Decisão Prática: Quando Usar Cada Tipo de Hook

CenárioTipo de HookHook Recomendado
Adicionar pixel de rastreamento antes de `</body>`Action`wp_footer`
Modificar conteúdo do post antes da exibiçãoFilter`the_content`
Registar um tipo de post personalizadoAction`init`
Restringir tipos de ficheiro de uploadFilter`upload_mimes`
Enviar email quando uma encomenda é concluídaActionAction personalizada na função de processamento de encomendas
Alterar contagem de palavras do excertoFilter`excerpt_length`
Redirecionar utilizadores não autenticadosAction`template_redirect`
Adicionar classe CSS à tag bodyFilter`body_class`
Enfileirar uma folha de estilos personalizadaAction`wp_enqueue_scripts`
Modificar WP_Query antes da execuçãoAction (por referência)`pre_get_posts`

FAQ

Qual é a diferença entre do_action() e apply_filters() no WordPress?

do_action() aciona um action hook — executa todos os callbacks registados nesse ponto mas não passa um valor de retorno de volta ao código chamador. apply_filters() aciona um filter hook — passa um valor por todos os callbacks registados em sequência e retorna o valor final transformado ao chamador. As actions produzem efeitos secundários; os filtros transformam dados.

Pode um filter hook do WordPress ser usado como um action hook?

Tecnicamente, add_action() é um wrapper em torno de add_filter() no núcleo do WordPress. No entanto, usar um filter hook como uma action (sem retornar um valor) fará com que o valor filtrado se torne null, quebrando os dados que estavam a ser processados. Use sempre a função semanticamente correta para o propósito pretendido.

Por que é que remove_action() às vezes falha ao remover um hook?

A causa mais comum é uma incompatibilidade de prioridade — a prioridade passada a remove_action() deve corresponder exatamente à prioridade usada na chamada original add_action(). A segunda causa comum é o timing: remove_action() deve ser chamado após o hook ter sido registado mas antes de ser acionado. Se o registo original acontece dentro de um construtor de classe ou de um hook de acionamento tardio, a sua chamada de remoção pode executar demasiado cedo.

Qual é o lugar mais seguro para adicionar hooks WordPress personalizados num ambiente de produção?

Um plugin autónomo e construído para esse propósito é o local mais seguro. Ao contrário de functions.php, um plugin persiste através de mudanças de tema e é mais fácil de controlar versões, testar e implementar independentemente. Em ambientes de VPS Hosting geridos, armazenar plugins personalizados num repositório Git privado e implementar via pipelines CI/CD é o padrão de nível de produção.

Como posso depurar quais hooks estão a ser acionados numa página WordPress específica?

Instale o plugin Query Monitor e navegue para a página alvo enquanto está autenticado como administrador. O separador “Hooks & Actions” lista cada hook que foi acionado, cada callback anexado e o tempo de execução por callback. Para depuração baseada em CLI num servidor, wp hook list --format=table via WP-CLI fornece um inventário estático de todos os hooks registados sem carregar um browser.

15%

Poupe 15% em todos os serviços

Teste as suas habilidades e obtenha Desconto em qualquer plano

Utilizar o código:

Skills
Começar a trabalhar