O WordPress é uma ferramenta poderosa, mas a sua filosofia de “um tamanho serve para todos” significa que muitas vezes traz excessos que a maioria dos projetos modernos não necessita. Ao longo dos anos, aperfeiçoei um conjunto específico de snippets para eliminar o supérfluo sem comprometer a experiência principal.
Este guia não é apenas uma lista de itens para apagar; é uma abordagem estratégica ao desempenho. Foi inspirado pela excelente lista de Terence Eden, à qual juntei as minhas próprias soluções testadas em ambiente de produção. Cada nome de hook abaixo foi conferido com o código-fonte do WordPress 7.1.3 (a versão atual a 12 de outubro de 2026, segundo a verificação de versões do api.wordpress.org), e os snippets que se revelaram desatualizados, errados ou prejudiciais estão assinalados como tal. Se preferir entregar este trabalho a outra pessoa, veja os nossos serviços de desenvolvimento WordPress.
Porquê remover o excesso de código do WordPress
Porquê preocupar-se com alguns scripts pequenos? Porque eles acumulam-se. Cada linha desnecessária é um conflito potencial, um micro-atraso na renderização ou largura de banda desperdiçada.
O que estamos a visar:
- Tamanho do DOM, Eliminar estilos inline não utilizados.
- Overhead de HTTP, Desativar scripts que não deveriam estar lá.
- Superfície de segurança, Desativar protocolos legados como o XML-RPC.
- Core Web Vitals, Impacto direto no LCP e CLS ao remover elementos que bloqueiam a renderização.
[!IMPORTANT] Use de cautela: Nem todo o “bloat” é inútil. Se depende do estilo específico do editor clássico ou dos emojis incorporados para navegadores antigos, alguns destes ajustes podem não ser adequados para si. Teste sempre primeiro em ambiente de testes (staging).
Como usar um script completo para limpar o WordPress
Adicione o seguinte ao ficheiro functions.php do seu tema, ou melhor ainda a um mu-plugin (veja a última secção), para que o código sobreviva a uma mudança de tema. Cada secção está comentada com explicações e links para fontes.
1. Remover estilos do classic theme
O WordPress adiciona “classic-theme-styles” aos temas que não têm ficheiro theme.json. O núcleo só o coloca na fila quando wp_theme_has_theme_json() devolve false, por isso um tema de blocos ou um tema clássico com theme.json nunca o carrega. Se o seu tema o carrega, remova-o:
// Remover o classic theme obrigatório.
function disable_classic_theme_styles() {
wp_deregister_style( "classic-theme-styles" );
wp_dequeue_style( "classic-theme-styles" );
}
add_action( "wp_enqueue_scripts", "disable_classic_theme_styles" );2. Remover suporte a emoji
O WordPress imprime um pequeno script de deteção e só quando o navegador não consegue mostrar emojis recentes carrega um script maior, que troca os caracteres de emoji por imagens SVG. Se o seu público usa navegadores atuais, isto é desnecessário:
// Remover WP Emoji.
// https://www.denisbouquet.com/remove-wordpress-emoji-code/
remove_action( "wp_head", "print_emoji_detection_script", 7 );
remove_action( "wp_print_styles", "print_emoji_styles" );
remove_action( "admin_print_scripts", "print_emoji_detection_script" );
remove_action( "admin_print_styles", "print_emoji_styles" );
// Esvaziar o URL base de SVG passado às definições de emoji.
add_filter( "emoji_svg_url", "__return_false" );
// Parar substituição de emoji com imagens em RSS / Atom Feeds
// https://danq.me/2023/09/04/wordpress-stop-emoji-images/
remove_filter( "the_content_feed", "wp_staticize_emoji" );
remove_filter( "comment_text_rss", "wp_staticize_emoji" );3. Desativar formatação automática de texto
O WordPress “texturiza” o conteúdo: aspas retas passam a tipográficas, e ASCII -- / --- tornam-se travessões (U+2013 / U+2014). Isso parte exemplos de código e conflita com uma política editorial de hífen ASCII (- ou --, sem glifos de travessão na origem). Desative em conteúdo técnico:
// Remover formatação automática.
// https://css-tricks.com/snippets/wordpress/disable-automatic-formatting/
remove_filter( "the_content", "wptexturize" );
remove_filter( "the_excerpt", "wptexturize" );
remove_filter( "comment_text", "wptexturize" );
remove_filter( "the_title", "wptexturize" );
// Mais filtros de formatação.
add_action("init", function() {
remove_filter( "the_content", "convert_smilies", 20 );
foreach ( array( "the_content", "the_title", "wp_title", "document_title" ) as $filter ) {
remove_filter( $filter, "capital_P_dangit", 11 );
}
remove_filter( "comment_text", "capital_P_dangit", 31 );
// APENAS em sites com editor clássico: esta linha trava toda a renderização de blocos.
remove_filter( "the_content", "do_blocks", 9 );
}, 11);Nota: O filtro
capital_P_dangité a forma do WordPress auto-corrigirWordpress(com p minúsculo) paraWordPress. É agressivo e por vezes indesejado.
[!WARNING] Remover
do_blocksdethe_contentsignifica que o markup dos blocos deixa de ser interpretado. Os blocos dinâmicos (query loop, últimos artigos, navegação) não mostram nada. Mantenha essa linha apenas num site cujos artigos foram todos escritos no editor clássico.
4. Remover estilos e scripts do Gutenberg
Se está a usar um tema personalizado e não depende dos estilos frontend do Gutenberg, remova-os. Num tema de blocos, não o faça: os estilos globais transportam todo o design do theme.json.
// Remover Estilos do Gutenberg.
// https://wordpress.org/support/topic/how-to-disable-inline-styling-style-idglobal-styles-inline-css/
remove_action( "wp_enqueue_scripts", "wp_enqueue_global_styles" );
// Nos temas clássicos o núcleo também o liga a wp_footer com prioridade 1.
remove_action( "wp_footer", "wp_enqueue_global_styles", 1 );
// Remover widgets de edição do Gutenberg.
// De https://wordpress.org/plugins/classic-widgets/
// Impede o editor de blocos de gerir os widgets no plugin Gutenberg.
add_filter( "gutenberg_use_widgets_block_editor", "__return_false" );
// Impede o editor de blocos de gerir os widgets.
add_filter( "use_widgets_block_editor", "__return_false" );
// Remover CSS da Block Library do Gutenberg do carregamento no frontend.
// https://smartwp.com/remove-gutenberg-css/
function remove_wp_block_library_css() {
wp_dequeue_style( "wp-block-library" );
wp_dequeue_style( "wp-block-library-theme" );
}
add_action( "wp_enqueue_scripts", "remove_wp_block_library_css", 100 );5. Remover meta tags do header
Limpe a sua secção <head> removendo meta tags desnecessárias:
// Remover shortlink.
// https://stackoverflow.com/questions/42444063/disable-wordpress-short-links
remove_action( "wp_head", "wp_shortlink_wp_head" );
// Remover RSD.
// https://wpengineer.com/1438/wordpress-header/
remove_action( "wp_head", "rsd_link" );
// Remover links de feed extra.
// https://developer.wordpress.org/reference/functions/feed_links/
add_filter( "feed_links_show_comments_feed", "__return_false" );
add_filter( "feed_links_show_posts_feed", "__return_false" );
// Remover link api.w.org.
// https://wordpress.stackexchange.com/questions/211467/remove-json-api-links-in-header-html
remove_action( "wp_head", "rest_output_link_wp_head" );
// https://wordpress.stackexchange.com/questions/211817/how-to-remove-rest-api-link-in-http-headers
// https://developer.wordpress.org/reference/functions/rest_output_link_header/
remove_action( "template_redirect", "rest_output_link_header", 11, 0 );6. Remover melhorias de imagem
O WordPress adiciona às imagens os atributos srcset, sizes, loading, decoding e fetchpriority. Se trata disto por conta própria, remova-os, mas leia primeiro a secção sobre imagens mais abaixo, porque estes atributos protegem o LCP e o CLS:
// Remover tamanho de imagem forçado do WordPress
// https://core.trac.wordpress.org/ticket/62413#comment:40
add_filter( "wp_img_tag_add_auto_sizes", "__return_false" );
// Remover melhorias de <img>
// https://developer.wordpress.org/reference/functions/wp_filter_content_tags/
remove_filter( "the_content", "wp_filter_content_tags", 12 );
// Parar reescrita de URLs http:// para o domínio principal.
// https://developer.wordpress.org/reference/hooks/wp_should_replace_insecure_home_url/
remove_filter( "the_content", "wp_replace_insecure_home_url", 10 );
// Remover coisas de attachment
// https://developer.wordpress.org/news/2024/01/building-dynamic-block-based-attachment-templates-in-themes/
remove_filter( "the_content", "prepend_attachment" );
// Remover filtro de blocos
remove_filter( "the_content", "apply_block_hooks_to_content_from_post_object", 8 );7. Remover verificação de browser e outras funcionalidades de admin
// Remover verificação de browser do painel de Admin.
// https://core.trac.wordpress.org/attachment/ticket/27626/disable-wp-check-browser-version.0.2.php
if ( !empty( $_SERVER["HTTP_USER_AGENT"] ) ) {
add_filter( "pre_site_transient_browser_" . md5( $_SERVER["HTTP_USER_AGENT"] ), "__return_null" );
}
// Remover hovercards nos links de comentários na área de admin.
// https://wordpress.org/support/topic/how-to-disable-mshots-service/#post-12946617
add_filter( "akismet_enable_mshots", "__return_false" );O que mais desativar no WordPress
Para além das técnicas acima, aqui estão as minhas próprias soluções para otimização adicional:
8. Desativar XML-RPC
Se não usa aplicações externas para publicar no WordPress, desligue os métodos XML-RPC que exigem login e, com eles, os métodos de pingback. O filtro xmlrpc_enabled, sozinho, não desliga o endpoint (detalhes mais abaixo):
// Desativar os métodos XML-RPC que exigem autenticação
add_filter( 'xmlrpc_enabled', '__return_false' );
// Remover os métodos de pingback, que de outra forma continuam abertos
add_filter( 'xmlrpc_methods', function( $methods ) {
unset( $methods['pingback.ping'], $methods['pingback.extensions.getPingbacks'] );
return $methods;
} );
// Remover link XML-RPC do head
remove_action( 'wp_head', 'rsd_link' );9. Remover jQuery Migrate
Temas e plugins modernos do WordPress raramente precisam do jQuery Migrate. Se o seu site funciona sem ele, remova-o:
function remove_jquery_migrate( $scripts ) {
if ( ! is_admin() && isset( $scripts->registered['jquery'] ) ) {
$script = $scripts->registered['jquery'];
if ( $script->deps ) {
$script->deps = array_diff( $script->deps, array( 'jquery-migrate' ) );
}
}
}
add_action( 'wp_default_scripts', 'remove_jquery_migrate' );10. Desativar oEmbed
Se nenhum outro site precisa de incorporar os seus artigos, desligue o lado de fornecedor do oEmbed. As incorporações de YouTube e de outros fornecedores registados nos seus próprios artigos continuam a funcionar, porque o WordPress só faz a descoberta para URLs que não estão na sua lista interna de fornecedores:
// Remover links de descoberta oEmbed
remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
remove_action( 'wp_head', 'wp_oembed_add_host_js' );
// Remover o endpoint oEmbed da REST API
remove_action( 'rest_api_init', 'wp_oembed_register_route' );
// Desativar auto-descoberta oEmbed
add_filter( 'embed_oembed_discover', '__return_false' );11. Adiar o carregamento de JavaScript
Adicione defer a scripts não críticos para melhor desempenho. O filtro abaixo é a abordagem antiga e ignora as regras de dependências que o núcleo aplica desde o WordPress 6.3; a secção sobre a estratégia de carregamento, mais abaixo, mostra a forma suportada:
function add_defer_attribute( $tag, $handle ) {
// Scripts que NÃO devem ser adiados
$scripts_to_not_defer = array( 'jquery-core' );
if ( in_array( $handle, $scripts_to_not_defer ) || str_contains( $tag, ' defer' ) ) {
return $tag;
}
return str_replace( ' src', ' defer src', $tag );
}
add_filter( 'script_loader_tag', 'add_defer_attribute', 10, 2 );Como medir o impacto do debloat no WordPress
Após implementar estas alterações, teste o seu site usando:
- Google PageSpeed Insights, Verifique os seus Core Web Vitals
- GTmetrix, Análise detalhada em cascata
- WebPageTest, Múltiplas localizações de teste e velocidades de ligação
Deverá ver:
- Tamanho de página reduzido (menos bytes de CSS/JS)
- Menos pedidos HTTP
- Melhor Largest Contentful Paint (LCP) quando um recurso removido bloqueava a renderização
O tempo de resposta do servidor (TTFB) quase não muda, porque nenhum destes snippets altera a forma como o PHP constrói a página. O que mexe no TTFB é uma camada de cache.
O que carrega uma instalação padrão do WordPress 7.1
Antes de remover o que quer que seja, convém saber quanto custa cada funcionalidade. Os tamanhos abaixo foram medidos nos ficheiros do wordpress-7.1.3.zip oficial: bytes em bruto no disco e o tamanho após gzip de nível 9, próximo do que um servidor envia pela rede.
| Recurso | Ficheiro | Bruto | Gzip | Quando carrega |
|---|---|---|---|---|
| Carregador de emoji (inline, rodapé) | wp-emoji-loader.min.js | 2,977 B | 1,290 B | Em todas as páginas do frontend |
| Script de substituição de emoji | wp-emoji-release.min.js | 22,752 B | 5,310 B | Só quando o navegador falha o teste de emoji |
| Estilos do classic theme | classic-themes.min.css | 291 B | 233 B | Temas sem theme.json |
| Biblioteca de blocos combinada | block-library/style.min.css | 140,829 B | 18,938 B | Só quando os estilos de blocos a pedido estão desligados |
| Estilos de tema da biblioteca de blocos | block-library/theme.min.css | 2,752 B | 751 B | Temas que declaram wp-block-styles, com carregamento a pedido desligado |
| jQuery | jquery.min.js | 87,553 B | 30,356 B | Quando o tema ou um plugin o coloca na fila |
| jQuery Migrate | jquery-migrate.min.js | 13,577 B | 4,891 B | Juntamente com o handle jquery |
| Dashicons | dashicons.min.css | 59,004 B | 35,693 B | Barra de administração para utilizadores com sessão iniciada, ou um plugin |
| Script anfitrião de incorporação de artigos | wp-embed.min.js | 1,251 B | 710 B | Só em páginas que incorporam um artigo WordPress |
| Heartbeat | heartbeat.min.js | 5,947 B | 2,058 B | Ecrãs de administração; no frontend só se um plugin o pedir |
| Resposta a comentários | comment-reply.min.js | 2,950 B | 1,371 B | Quando o tema ou o bloco Comentários o coloca na fila |
Destacam-se dois números. O jQuery com o Migrate é o que um tema clássico costuma enviar de mais pesado, por isso retirar o jQuery do código do seu próprio tema poupa mais do que todos os ajustes às tags do head juntos. E a folha de 140 KB da biblioteca de blocos já não é carregada por inteiro numa instalação padrão: os temas de blocos carregam apenas os estilos dos blocos presentes na página desde o WordPress 5.9, e desde a 6.9 o núcleo ativa o mesmo carregamento a pedido nos temas clássicos através de wp_load_classic_theme_block_styles_on_demand(), desde que o buffer de saída do template esteja ativo. Um tema pode recusar este comportamento devolvendo false nos filtros should_load_separate_core_block_assets e should_load_block_assets_on_demand.
Para ver o que uma página concreta carrega de facto, use o navegador. No Chrome DevTools abra o separador Network, recarregue com a cache desativada, filtre pelo seu domínio e ordene por tamanho. O Lighthouse, no mesmo painel do DevTools, lista o CSS e o JavaScript não utilizados por ficheiro. O WP-CLI não ajuda aqui: uma chamada wp eval nunca renderiza um template, por isso as filas de scripts e estilos que mostra vêm vazias. Um hook de rodapé com registo em log funciona:
// Registar cada handle na fila nas visualizações de páginas do frontend (só em staging).
add_action( 'wp_footer', function () {
if ( is_admin() ) {
return;
}
foreach ( wp_scripts()->queue as $handle ) {
error_log( 'script: ' . $handle . ' ' . wp_scripts()->registered[ $handle ]->src );
}
foreach ( wp_styles()->queue as $handle ) {
error_log( 'style: ' . $handle . ' ' . wp_styles()->registered[ $handle ]->src );
}
}, 999 );Que funcionalidades do WordPress desativar, uma a uma
O script acima é a versão rápida. Abaixo, cada funcionalidade recebe o contexto necessário para decidir se faz falta no seu site.
O que são os classic theme styles e quanto custam
O WordPress 6.1 acrescentou uma pequena folha de estilos que dá aos temas clássicos valores por omissão sensatos para o markup dos blocos, como o espaçamento dos blocos de botão e de ficheiro. Pesa 291 bytes e é colocada na fila por wp_enqueue_classic_theme_styles() só quando o tema ativo não tem theme.json. Remova-a num tema clássico com CSS próprio para blocos. Mantenha-a nos temas clássicos que contam com o markup de blocos do núcleo a aparecer bem sem trabalho extra, e não se preocupe com ela nos temas de blocos, onde nunca é carregada.
Porque é que o WordPress carrega um script de emoji
A funcionalidade de emoji faz dois trabalhos: testa se o navegador consegue desenhar emojis recentes e, se não conseguir, carrega wp-emoji-release.min.js para substituir os caracteres por imagens de s.w.org. No WordPress 7.1.3 o teste é um script inline type="module" impresso no rodapé, por isso já não bloqueia a renderização, e os resultados ficam em cache no sessionStorage. Vem acompanhado de uma pequena folha de estilos inline para img.emoji. Remover a ação wp_print_styles continua a funcionar: wp_enqueue_emoji_styles() verifica essa ação e salta o CSS inline quando ela já não existe.
O filtro emoji_svg_url agora só define o URL base de SVG nas definições de emoji. Guias mais antigos usavam-no para eliminar um DNS prefetch para s.w.org; no 7.1.3 o wp_resource_hints() já não acrescenta essa indicação, por isso a linha é inofensiva mas já não poupa nenhuma consulta. Mantenha o suporte a emoji se os visitantes escrevem em comentários ou fóruns a partir de dispositivos antigos cujas fontes não têm emojis recentes. A versão completa abrange também o e-mail e o editor clássico:
function disable_emojis_completely() {
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
remove_action( 'admin_print_styles', 'print_emoji_styles' );
remove_action( 'embed_head', 'print_emoji_detection_script' );
remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
add_filter( 'tiny_mce_plugins', function ( $plugins ) {
return array_diff( $plugins, array( 'wpemoji' ) );
} );
}
add_action( 'init', 'disable_emojis_completely' );O que o wptexturize altera no seu conteúdo
O wptexturize() transforma aspas retas em tipográficas, -- e --- em travessões curtos e longos, e três pontos num carácter de reticências. Em conteúdo técnico, estraga shortcodes e fragmentos de HTML e PHP que os leitores copiam. Toda a função pode ser desligada com um único filtro, em vez de a retirar de cada hook:
add_filter( 'run_wptexturize', '__return_false' );Mantenha-a apenas em sites editoriais que querem aspas tipográficas e nunca publicam código.
O que faz o filtro capital_P_dangit
O capital_P_dangit() substitui Wordpress por WordPress. Nos títulos substitui todas as ocorrências; no conteúdo e nos comentários, só depois de um espaço, de aspas, de > ou de (. Não mexe nos URLs, porque uma barra antes da palavra não corresponde ao padrão. O risco real está no código: um exemplo que contenha Wordpress depois de um espaço é alterado sem aviso.
Que estilos e scripts o editor de blocos acrescenta
No frontend, o editor de blocos contribui com wp-block-library (o CSS dos blocos), wp-block-library-theme (estilos de tema opinativos) e o global-styles inline gerado a partir do theme.json. O wp-components pertence aos ecrãs do editor, por isso retirá-lo da fila no frontend não faz nada. Snippets mais antigos também removem wp_global_styles_render_svg_filters de wp_body_open; essa função foi descontinuada na 6.3.0 e já não está ligada a nenhum hook. Remova o CSS dos blocos apenas em sites que não renderizam blocos no frontend. Num tema de blocos, remover os estilos globais retira o design do tema.
Que tags o WordPress adiciona ao head e quais remover
Um wp_head padrão no 7.1.3 imprime, entre outras:
<meta name="generator" content="WordPress 7.1.3" />
<link rel="shortlink" href="https://example.com/?p=123" />
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://example.com/xmlrpc.php?rsd" />
<link rel="https://api.w.org/" href="https://example.com/wp-json/" />
<link rel="alternate" type="application/json" href="https://example.com/wp-json/wp/v2/posts/123" />| Tag | Risco | Recomendação |
|---|---|---|
| generator | Baixo, a versão também aparece como ?ver= nos recursos do núcleo | Remova se quiser, esconde pouco |
| shortlink | Nenhum | Remover |
| RSD (EditURI) | Aponta os clientes para xmlrpc.php | Remover juntamente com o XML-RPC |
| Links da REST API | Baixo | Manter se algo descobre a sua API |
Duas remoções que ainda aparecem em muitos guias não fazem nada nas versões atuais: wlwmanifest_link foi descontinuado na 6.3.0 e já não é impresso, e adjacent_posts_rel_link_wp_head não é usado pelo núcleo desde a 5.6.0. Uma limpeza atual é mais curta:
add_action( 'init', function () {
remove_action( 'wp_head', 'wp_generator' );
remove_action( 'wp_head', 'wp_shortlink_wp_head' );
remove_action( 'template_redirect', 'wp_shortlink_header', 11 );
remove_action( 'wp_head', 'rsd_link' );
} );O que o WordPress acrescenta às imagens
O wp_filter_content_tags() acrescenta srcset e sizes, width e height quando faltam, loading="lazy" nas imagens abaixo da dobra, decoding="async" e fetchpriority="high" na imagem que provavelmente será o LCP. O filtro wp_img_tag_add_auto_sizes chegou na 6.7.0, não antes. Remover estas funcionalidades costuma piorar o CLS e o LCP, o contrário do objetivo, por isso faça-o apenas quando uma CDN ou o seu próprio markup define todos estes atributos. Para desligar só o carregamento diferido:
add_filter( 'wp_lazy_loading_enabled', '__return_false' );Como funciona a verificação de browser no painel
O wp_check_browser_version() pergunta ao api.wordpress.org se o navegador do administrador está desatualizado e guarda a resposta como site transient durante uma semana, com uma chave baseada num MD5 do user agent. É um pedido remoto por navegador por semana, não um por cada visualização de página de administração. A verificação da versão de PHP funciona da mesma forma, mas a chave do transient é php_check_ mais um MD5 de PHP_VERSION, não do user agent, por isso os snippets que filtram pre_site_transient_phpcompat_ não fazem nada:
add_filter( 'pre_site_transient_php_check_' . md5( PHP_VERSION ), '__return_null' );Mantenha essa verificação, a não ser que outra pessoa vigie a versão de PHP, porque é o aviso que diz aos donos do site que o seu PHP deixou de ter suporte.
O que o filtro xmlrpc_enabled desliga de facto
O XML-RPC é o protocolo de publicação remota por trás de clientes móveis mais antigos, editores de secretária e pingbacks. O nome do filtro sugere um interruptor geral, mas o código-fonte do WordPress 7.1.3 diz outra coisa no docblock de wp_xmlrpc_server::set_is_enabled():
“Ao contrário do que o nome indica, este filtro não controla se o XML-RPC está totalmente ativado; controla apenas se estão ativados os métodos XML-RPC que exigem autenticação, como os usados para publicar.”
Fonte: docblock de wp_xmlrpc_server::set_is_enabled(), código-fonte do WordPress 7.1.3 (tradução própria)
Assim, depois de add_filter( 'xmlrpc_enabled', '__return_false' ), o xmlrpc.php continua a responder e o pingback.ping continua a funcionar. Os pingbacks são a parte usada para tráfego refletido, e o system.multicall permite que um único pedido transporte muitas tentativas de login, algo que o filtro trava, porque esses métodos exigem autenticação. O snippet da secção 8 também retira os métodos de pingback através de xmlrpc_methods. O cabeçalho HTTP X-Pingback só é enviado em artigos individuais que aceitam pings, por isso fechar os pings (secções seguintes) também o elimina. Para desligar o endpoint por completo, bloqueie o xmlrpc.php no servidor web; depois verifique qualquer plugin ou aplicação que publique remotamente, porque vai deixar de funcionar.
Para que serve o jQuery Migrate
O jQuery Migrate repõe APIs do jQuery que foram removidas em versões posteriores e regista avisos quando código antigo as chama. O WordPress regista o handle jquery como um alias de jquery-core mais jquery-migrate, e é por isso que o snippet da secção 9 edita a lista de dependências em vez de retirar um ficheiro da fila. Antes de o remover em produção, abra o site em staging com define( 'SCRIPT_DEBUG', true );, o que faz o WordPress servir o jquery-migrate.js não minificado que o núcleo mantém para depuração, e procure na consola os avisos JQMIGRATE sobre chamadas obsoletas. Não chame wp_deregister_script( 'jquery-migrate' ) no frontend; qualquer plugin que declare jquery-migrate como dependência perderia o seu próprio script, porque o WordPress não imprime um script cuja dependência está em falta.
Como funciona o oEmbed no WordPress
O oEmbed tem dois lados. Como consumidor, o WordPress transforma um link colado do YouTube ou do Vimeo num leitor através da sua lista interna de fornecedores; isso continua a funcionar depois do snippet da secção 10. Como fornecedor, o seu site imprime links de descoberta e serve /wp-json/oembed/1.0/embed para que outros sites WordPress possam incorporar os seus artigos. O script wp-embed (710 bytes com gzip) só é colocado na fila em páginas que contêm uma incorporação desse tipo. Há duas linhas de código antigo para “desativar incorporações” que não devem ser copiadas: remover wp_filter_oembed_result de oembed_dataparse desliga a sanitização que o núcleo aplica ao HTML de fornecedores fora da lista de confiança, e o plugin TinyMCE wpembed já não existe, por isso filtrá-lo de tiny_mce_plugins não faz nada.
Como restringir a REST API sem partir o editor de blocos
A REST API responde em /wp-json/ e é o que o editor de blocos, o editor do site e muitos plugins usam. O manual oficial da REST API é explícito nas suas perguntas frequentes:
“Não deve desativar a REST API; isso vai partir funcionalidades da administração do WordPress que dependem de a API estar ativa.”
Fonte: REST API Handbook, perguntas frequentes (tradução própria)
Em alternativa, o manual propõe exigir autenticação através do filtro rest_authentication_errors. Os editores com sessão iniciada continuam a trabalhar e os pedidos anónimos recebem um 401:
add_filter( 'rest_authentication_errors', function( $result ) {
// Se já foi aplicada uma verificação de autenticação anterior,
// devolver esse resultado sem alterações.
if ( true === $result || is_wp_error( $result ) ) {
return $result;
}
// Ainda não foi feita nenhuma autenticação.
// Devolver um erro se o utilizador não tiver sessão iniciada.
if ( ! is_user_logged_in() ) {
return new WP_Error(
'rest_not_logged_in',
__( 'You are not currently logged in.' ),
array( 'status' => 401 )
);
}
// A nossa verificação personalizada não deve ter efeito
// nos pedidos com sessão iniciada
return $result;
});Isto parte, para visitantes anónimos, todas as funcionalidades do frontend que chamam /wp-json/: formulários enviados através da REST, widgets de pesquisa ou de filtros que vão buscar JSON, um frontend headless e outros sites que incorporam os seus artigos pelo endpoint oEmbed. Uma opção mais restrita é esconder rotas individuais com o filtro rest_endpoints, por exemplo o endpoint de utilizadores que lista os slugs dos autores. Depois da alteração, teste todos os formulários e blocos interativos sem sessão iniciada.
Como ajustar a Heartbeat API do WordPress
O Heartbeat é um ciclo de polling em heartbeat.js que envia um pedido a admin-ajax.php em intervalos fixos. Assegura o bloqueio de artigos (o aviso de que outra pessoa está a editar), os dados de gravação automática no editor clássico e a verificação de expiração do login que mostra a janela para voltar a entrar. No WordPress 7.1.3 o mainInterval padrão é de 60 segundos, o intervalo permitido vai de 1 a 3600 segundos, o ciclo pode acelerar temporariamente para 5 segundos e abranda para 120 segundos quando o separador está oculto. Definir o intervalo para 60 não muda, portanto, nada; um intervalo mais lento é o ajuste útil em equipas de administração numerosas ou em alojamento fraco:
add_filter( 'heartbeat_settings', function ( $settings ) {
$settings['interval'] = 120;
return $settings;
} );No frontend, o núcleo não carrega o Heartbeat para os visitantes; só aparece quando um plugin o coloca na fila. Remover o seu registo aí é seguro, desde que verifique depois a funcionalidade desse plugin. Nunca o remova na administração: os bloqueios de artigos e os avisos de expiração de sessão dependem dele.
Como limitar as revisões de artigos com WP_POST_REVISIONS
As revisões não tornam o frontend mais lento, porque nunca são consultadas nas páginas públicas. Fazem crescer a tabela wp_posts e tornam mais lentos os backups e as exportações. O controlo é uma constante no wp-config.php, lida por wp_revisions_to_keep():
define( 'WP_POST_REVISIONS', 10 ); // manter as 10 revisões mais recentes por artigo
// define( 'WP_POST_REVISIONS', false ); // sem revisõesO valor padrão é true, o que significa ilimitado. false ou 0 desativa as revisões; um número positivo mantém essa quantidade. O filtro wp_revisions_to_keep sobrepõe-se à constante e, desde o WordPress 5.8, o filtro wp_{$post_type}_revisions_to_keep define um limite por tipo de conteúdo. O limite aplica-se quando o artigo volta a ser guardado, por isso as revisões a mais que já existem ficam até lá. Desligar as revisões tira a rede de segurança aos editores, por isso um número pequeno costuma ser a melhor troca.
A gravação automática tem a sua própria constante. Não existe nenhum filtro autosave_interval no núcleo, por isso o código que o adiciona não faz nada; defina antes o intervalo, em segundos, no wp-config.php:
define( 'AUTOSAVE_INTERVAL', 120 ); // o padrão é 60Como desativar os comentários em todo o site
Um site sem comentários continua a mostrar formulários de comentários onde o tema os pede, mantém o link do feed de comentários no head e mantém o mecanismo de pingbacks. Fechar comentários e pings através de filtros abrange todos os tipos de conteúdo sem editar os artigos na base de dados:
add_filter( 'comments_open', '__return_false', 20, 2 );
add_filter( 'pings_open', '__return_false', 20, 2 );
add_filter( 'feed_links_show_comments_feed', '__return_false' );
add_action( 'admin_menu', function () {
remove_menu_page( 'edit-comments.php' );
} );
add_action( 'init', function () {
remove_post_type_support( 'post', 'comments' );
remove_post_type_support( 'page', 'comments' );
} );Fechar os pings também elimina o cabeçalho X-Pingback, já que o núcleo só o envia quando pings_open() é verdadeiro. Os comentários existentes ficam na base de dados e podem continuar a aparecer se o tema os imprimir independentemente de comments_open(). O script comment-reply não justifica trabalho à parte: o núcleo regista-o com a estratégia async e prioridade de obtenção baixa, e tem 1371 bytes com gzip.
Como adiar scripts com a API de estratégia de carregamento
Desde o WordPress 6.3, wp_register_script() e wp_enqueue_script() aceitam um argumento strategy com os valores defer ou async. O núcleo verifica então a árvore de dependências antes de imprimir o atributo: um script com um script inline anexado na posição after nunca é atrasado, e um script defer volta a ser bloqueante quando um script dependente precisa que ele corra primeiro. Essa lógica está em WP_Scripts::get_eligible_loading_strategy(). O filtro script_loader_tag da secção 11 salta tudo isto, e é assim que os scripts adiados acabam por correr depois do código inline que os chama.
// O seu próprio script.
wp_enqueue_script( 'site-main', get_theme_file_uri( 'js/main.js' ), array(), '1.4.0', array(
'in_footer' => true,
'strategy' => 'defer',
) );
// Um script registado por um plugin.
add_action( 'wp_enqueue_scripts', function () {
wp_script_add_data( 'some-plugin-handle', 'strategy', 'defer' );
}, 20 );Veja depois o código-fonte da página: se o núcleo decidiu que um handle não pode ser adiado, o atributo simplesmente não aparece.
Como testar o desempenho do WordPress antes e depois do debloat
Uma única execução do PageSpeed Insights não é uma medição, porque as pontuações de laboratório variam entre execuções. Um procedimento que dá números comparáveis:
- Preparar: limpe a cache de páginas, use o mesmo alojamento e o mesmo conjunto de URLs nas duas rondas, e anote as versões do WordPress, do tema e dos plugins.
- Linha de base: corra o PageSpeed Insights ou o Lighthouse três vezes por URL e fique com a mediana; depois registe os bytes transferidos e o número de pedidos no separador Network do DevTools, com a cache desativada.
- Instale o código de debloat em staging e limpe de novo a cache.
- Repita as mesmas execuções nos mesmos URLs.
- Compare bytes transferidos, número de pedidos, LCP e CLS. Os dados de campo na secção Chrome UX Report do PageSpeed Insights atualizam-se ao longo de 28 dias, por isso volte a verificá-los um mês depois.
A tabela de tamanhos acima indica o limite máximo. Num tema clássico que já carrega os estilos de blocos a pedido, remover os emojis, os classic theme styles e as tags do head poupa alguns kilobytes e algumas linhas de HTML; os números grandes estão no jQuery e nos recursos dos plugins.
Como verificar a compatibilidade depois do debloat
Depois de cada alteração, verifique três áreas:
- Frontend: o layout, os menus, os sliders e os formulários, e a consola do navegador à procura de erros de JavaScript.
- Administração: o editor de artigos, a biblioteca multimédia, o ecrã de widgets e cada página de definições de plugins que usa.
- Sem sessão iniciada: formulários de contacto, comentários se os mantiver, pesquisa e tudo o que carregue dados sem recarregar a página.
Ative o registo em log enquanto testa e mantenha a apresentação desligada para que os visitantes não vejam avisos:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );| Problema | Causa provável | Correção |
|---|---|---|
| Erros de jQuery na consola | jQuery Migrate removido | Repor o Migrate ou atualizar o plugin que chama APIs obsoletas |
| Blocos sem estilo | Biblioteca de blocos ou estilos globais removidos | Repor os estilos nas páginas com conteúdo em blocos |
| Query loop ou navegação não mostram nada | do_blocks removido de the_content | Retirar essa linha |
| Envio de formulários falha sem sessão iniciada | REST API limitada a utilizadores com sessão iniciada | Permitir a rota do plugin ou retirar a restrição |
| Aplicação móvel ou publicação remota falham | XML-RPC bloqueado | Reativá-lo ou passar o cliente para palavras-passe de aplicação e REST |
| Incorporações dos seus artigos noutros sites deixam de funcionar | Lado de fornecedor do oEmbed removido | Esperado; repor se os parceiros precisarem |
Como empacotar o código de debloat num mu-plugin
O código no functions.php desaparece quando o tema muda. Um plugin de uso obrigatório (must-use) em wp-content/mu-plugins/ é carregado em cada pedido, não pode ser desativado na administração e mantém as definições de debloat independentes do tema. O WordPress carrega os ficheiros PHP colocados diretamente nessa pasta, não os que estão em subpastas, por isso mantenha um único ficheiro ou acrescente um pequeno carregador:
wp-content/
mu-plugins/
debloat-loader.php
debloat/
emoji.php
head-cleanup.php
xmlrpc.php
heartbeat.php<?php
/**
* Plugin Name: Debloat
* Description: Removes front-end features this site does not use.
*/
defined( 'ABSPATH' ) || exit;
foreach ( array( 'emoji', 'head-cleanup', 'xmlrpc', 'heartbeat' ) as $module ) {
$file = __DIR__ . '/debloat/' . $module . '.php';
if ( is_readable( $file ) ) {
require_once $file;
}
}Cada módulo guarda os snippets das secções acima. Deixe duas coisas fora de um plugin de debloat. Desligar as atualizações automáticas de plugins e temas com auto_update_plugin e auto_update_theme é uma política de manutenção, não uma definição de desempenho, e desliga as versões de segurança juntamente com as de funcionalidades. E os limites de revisões e de gravação automática são constantes, por isso pertencem ao wp-config.php, não a um plugin que é carregado depois de essas constantes serem lidas.
Resumo
A abordagem “baterias incluídas” do WordPress é ótima para iniciantes, mas os programadores que procuram desempenho máximo precisam de cortar a gordura. As técnicas neste guia, inspiradas pelo excelente script de debloat de Terence Eden, vão ajudá-lo a alcançar uma instalação WordPress mais leve e rápida.
Vários snippets clássicos já não fazem nada no WordPress 7.1 (manifesto WLW, links de artigos adjacentes, filtros SVG, o filtro autosave_interval), e alguns fazem mal (remover do_blocks, remover a sanitização do oEmbed, bloquear a REST API por inteiro). Cada linha de código que remove é um potencial ponto de falha a menos, por isso confirme cada snippet com a versão que usa antes de o levar para produção.







