wp_kses() na HTML API: o que testar antes do WordPress 7.2

wp_kses() na HTML API: o que testar antes do WordPress 7.2

Última verificação: 10 de outubro de 2026
11 min de leitura
Tutorial
500+ projetos WP
Desenvolvedor full-stack

O wp_kses() está por trás do wp_kses_post(), da limpeza de comentários, do texto de widgets e de cada chamada wp_kses( $html, $allowed ) no seu plugin. No trunk, passa agora a correr sobre a HTML API do WordPress em vez de expressões regulares. Segundo o relatório de progresso de Dennis Snell, a alteração deve chegar ao WordPress 7.2 ou 7.3, consoante o que os testes revelarem. Este artigo explica o que muda no resultado, como encontrar o código seu que é afetado e para que serve o opt-out temporário.

#O que muda, exatamente, no wp_kses()?

A implementação antiga desmontava o markup com expressões regulares. A nova lê-o com o tokenizador da HTML API, decide por etiqueta e atributo o que é permitido e volta a escrever o resultado. O pull request chama-se “KSES: Reimplement with Tag Processor” (PR 13271) e está ligado ao ticket Trac 66208. Segundo o PR, o código novo vive numa função chamada wp_sanitize_html_kses().

A intenção do relatório é clara: o wp_kses() não deve ficar pior do que era. O relatório diz também que plugins e temas não deverão precisar de alterações. As duas frases podem ser verdadeiras e os seus testes ficarem vermelhos na mesma, porque “igualmente seguro” não quer dizer “os mesmos bytes”. A nova serialização é o centro da mudança, e altera strings.

Fonte: Progress Report: wp_kses(), 7 de outubro de 2026.

#Que entradas produzem resultado diferente?

O relatório apresenta pares de antes e depois. O bloco abaixo inspira-se neles (o meu array de etiquetas permitidas, as entradas do relatório). Corra os casos no seu próprio build trunk antes de confiar na minha transcrição.

<?php
// Modelled on the examples in the Make Core progress report.
$allowed = array(
	'a'    => array( 'href' => true ),
	'code' => true,
	'img'  => array( 'src' => true, 'class' => true ),
);

wp_kses( 'Click on my <script>alert(1)</script>!', $allowed );
// legacy: Click on my alert(1)!
// new:    Click on my !

wp_kses( 'The <IMG class=bike class="bo&#x0061;t" src=\'vehicle.png\' /> & the wheels&hellip;', $allowed );
// legacy: The <IMG class="bike" src="vehicle.png" /> &amp; the wheels&hellip;
// new:    The <img class="bike" src="vehicle.png"> &amp; the wheels…

wp_kses( 'Add <code>/?preview=true&section=grilling</code>.', $allowed );
// legacy: Add <code>/?preview=true&amp;section=grilling</code>.
// new:    Add <code>/?preview=true§ion=grilling</code>.

wp_kses( 'Click on the <butto', $allowed );
// legacy: Click on the &lt;butto
// new:    Click on the (trailing space, nothing else)

O relatório agrupa as diferenças assim:

  • Normalização. Os nomes das etiquetas passam a minúsculas, os atributos ficam com aspas duplas, num atributo repetido vence o primeiro e as referências de caracteres são reescritas.
  • Chavetas angulares soltas. Texto como <$500 ou >5yo era engolido. Agora passa a &lt; e &gt;, e o texto sobrevive.
  • E comercial ambíguo. Uma referência nomeada sem ponto e vírgula, como &section num URL dentro de um nó de texto, é descodificada como o browser a descodifica. Por isso o terceiro caso dá o sinal de parágrafo.
  • Script e style. Quando estes elementos não são permitidos, o conteúdo desaparece juntamente com as etiquetas. O código antigo deixava o conteúdo como texto visível.
  • Entrada truncada. Uma última etiqueta incompleta é descartada, não escapada.
  • Elementos especiais. Texto com aspeto de etiqueta dentro de um <title> permitido é escapado, enquanto o mesmo texto dentro de um <div> desaparece com a etiqueta desconhecida.
  • SVG e MathML. Conteúdo que exige parsing complexo faz a função parar e devolver apenas o que vinha antes. O relatório mostra um <li> com MathML e um <span> aninhado cortado nesse ponto.
  • Limites rígidos. Alguns comentários malformados, o NOSCRIPT e elementos confundíveis passam a ser rejeitados.
  • Etiquetas desequilibradas. Mantêm-se de propósito, porque o código existente depende disso.

Numa loja WooCommerce típica, os primeiros sítios onde olhar são descrições de produto com medidas como “<5 cm” coladas da folha de cálculo do fornecedor, HTML importado de fornecedores com etiquetas em maiúsculas e construtores de páginas que imprimem SVG inline. É uma suposição sobre onde procurar, não uma medição.

Nas fontes que li não encontrei confirmado como o <script> se comporta quando o permite expressamente no array. Teste esse caso por si mesmo, em vez de assumir um resultado.

#O meu array de allowed html continua a funcionar?

Na maioria dos casos sim, porque a lógica de permissões é a mesma: uma etiqueta ou um atributo está no array ou não está. O que muda é o que sai à volta. Três padrões merecem atenção.

  1. Arrays que permitem script ou style inline. Um shortcode que imprime um script inline e o passa por wp_kses() com script permitido está exatamente na zona que o relatório toca. Compare o resultado antigo com o novo. Pergunte também se o script não deveria antes passar por wp_add_inline_script(), em vez de passar pelo sanitizador.
  2. Arrays que permitem svg ou math. O caso comum são conjuntos de ícones inline. Se a regra do relatório se aplicar, o resultado pode ser cortado na primeira construção que o parser não consiga tratar. Compare cada ícone que entrega.
  3. Arrays para <title> e semelhantes. O <title> é um elemento especial e o conteúdo é tratado como texto. Daí o exemplo do &lt;sneaky&gt; escapado.

Se o array permitir apenas a, strong, em, img e poucos atributos, o efeito provável é cosmético: <IMG ... /> passa a <img ...>.

#O que quebra nos testes que comparam HTML limpo?

Tudo o que verifica uma string exata. Um teste como a primeira asserção abaixo passa hoje e pode falhar depois da reescrita, embora o markup signifique o mesmo. A segunda asserção sobrevive à normalização.

<?php
// Brittle: pins the exact string the sanitizer happens to emit.
$this->assertSame( '<a href="/x">Read</a>', wp_kses_post( "<A HREF='/x'>Read</A>" ) );

// Sturdier: asserts on what the markup means.
$p = new WP_HTML_Tag_Processor( wp_kses_post( "<A HREF='/x'>Read</A>" ) );
$this->assertTrue( $p->next_tag( 'a' ) );
$this->assertSame( '/x', $p->get_attribute( 'href' ) );

Fixe o comportamento, não os bytes. Nos fixtures que têm de ficar iguais à string, volte a gerá-los uma vez no trunk, leia o diff como pessoa e faça commit do novo valor esperado com um comentário a indicar a versão em que mudou. Um “atualizar snapshots” em bloco é a forma como uma regressão real fica aprovada.

Os testes visuais e os ficheiros de referência pedem o mesmo cuidado. Os modelos de email que limpa antes do envio são um sítio típico onde uma string guardada é comparada com uma recém-gerada.

#Como testo no trunk sem tocar na produção?

Três caminhos, todos em staging ou localmente. São sugestões minhas, não fazem parte do relatório oficial.

Plugin WordPress Beta Tester. Pode mover um site de staging para as versões noturnas e depois para as betas da 7.2. Segundo o calendário, a Beta 1 sai a 20 de outubro de 2026. Não consegui confirmar se a reescrita já vem na Beta 1, por isso verifique se o filtro wp_kses_force_legacy_parser existe no código que instalou.

WP-CLI nightly. Numa cópia descartável:

# Staging only, never production.
wp core update --version=nightly --force
wp core version
wp eval-file bin/kses-diff.php > kses-diff.txt
tail -n 1 kses-diff.txt

wp-env. Aponte o core para o espelho do trunk e monte o plugin:

{
  "core": "WordPress/WordPress#master",
  "plugins": [ "." ]
}

Qualquer que seja o caminho, termine por confirmar que o filtro existe, por exemplo com grep -rn wp_kses_force_legacy_parser wp-includes/. Se não existir, não está a testar a reescrita.

#Como comparo o resultado limpo de conteúdo real?

Casos sintéticos só encontram os erros que já imaginou. O teste útil é a sua própria base de dados. O script abaixo limpa cada artigo publicado duas vezes, uma com o parser antigo forçado e outra sem, e imprime só os artigos que diferem.

<?php
// bin/kses-diff.php
// Run on a trunk build: wp eval-file bin/kses-diff.php > kses-diff.txt
$ids  = get_posts( array(
	'post_type'   => 'any',
	'post_status' => 'publish',
	'numberposts' => -1,
	'fields'      => 'ids',
) );
$diff = 0;

foreach ( $ids as $id ) {
	$raw = get_post_field( 'post_content', $id );

	add_filter( 'wp_kses_force_legacy_parser', '__return_true' );
	$old = wp_kses_post( $raw );
	remove_filter( 'wp_kses_force_legacy_parser', '__return_true' );

	$new = wp_kses_post( $raw );

	if ( $old !== $new ) {
		++$diff;
		printf( "== %d %s\n--- old\n%s\n+++ new\n%s\n", $id, get_permalink( $id ), $old, $new );
	}
}

printf( "%d of %d posts differ\n", $diff, count( $ids ) );

Corra-o numa cópia da base de dados de produção, porque os editores colam coisas estranhas. Leia os primeiros vinte diffs à mão. Conte com um punhado de causas repetidas (etiquetas auto-fechadas, um < solto numa medida, SVG inline). Corrigir uma causa corrige muitos artigos de uma vez.

Alargue a rede com o mesmo padrão: troque wp_kses_post() pela chamada que o seu plugin faz com o seu próprio array e alimente-a com valores de opções, texto de widgets e comentários, não só com artigos.

#Quando devo usar o opt-out do parser antigo?

O filtro chama-se wp_kses_force_legacy_parser. Devolver true repõe o parser antigo. O relatório descreve-o como forma de os donos de sites não executarem o código de substituição, e a palavra que conta é temporário.

<?php
// wp-content/mu-plugins/kses-legacy-parser.php
// Stopgap only. Delete it once your output diff is clean.
add_filter( 'wp_kses_force_legacy_parser', '__return_true' );

Há duas situações. A primeira: encontrou uma regressão num site de cliente durante a janela de testes e precisa de manter o site estável enquanto corrige o código ou reporta o erro. A segunda: um plugin que não controla deixa de funcionar e o autor ainda não lançou correção. Ponha o filtro num mu-plugin, para ficar visível num só sítio, e associe-lhe uma tarefa com data de remoção.

Não o entregue como predefinição permanente. A implementação antiga tem problemas conhecidos que a reescrita quer resolver, entre eles falhas de PCRE com valores de atributo grandes e conteúdo de scripts apresentado como texto visível, segundo a descrição do PR. Um opt-out silencioso conserva esses problemas e esconde a migração do próximo programador.

Não encontrei uma data confirmada para remover o parser antigo. Trate o opt-out como algo que vai desaparecer e planeie em conformidade.

#Qual é o calendário do WordPress 7.2?

Do artigo do calendário da 7.2, sempre às 15:00 UTC:

MarcoData
Beta 120 de outubro de 2026
Beta 227 de outubro de 2026
Beta 33 de novembro de 2026
Beta 410 de novembro de 2026
RC117 de novembro de 2026
RC224 de novembro de 2026
RC31 de dezembro de 2026
Lançamento final8 de dezembro de 2026

O relatório diz 7.2 ou 7.3. Não pode contar com nenhuma das duas, mas também não pode excluir a 7.2. Um plano sensato: correr o script de diff em staging antes da Beta 1, de novo depois da RC1, e reportar no ticket Trac tudo o que surpreender enquanto a janela está aberta. É exatamente esse retorno que o autor pede.

#O que deve uma agência fazer esta semana?

  1. Pesquisar o código por wp_kses(, wp_kses_post(, wp_kses_data( e arrays $allowed próprios. Listar quais recebem HTML de utilizadores ou editores.
  2. Montar um staging em trunk por um dos caminhos acima e confirmar que o filtro existe.
  3. Correr o script de diff contra uma cópia do conteúdo de produção. Triar por causa, não por artigo.
  4. Reescrever os testes frágeis para verificarem estrutura e gerar uma vez os fixtures de texto, com revisão humana.
  5. Verificar shortcodes e blocos que emitem script, style, SVG ou MathML inline.
  6. Decidir por cliente se o opt-out é necessário, documentá-lo e fixar uma data de remoção.

Se o projeto tem anos de limpeza própria à volta de um ecossistema de plugins, esta auditoria encaixa no nosso serviço de desenvolvimento WordPress à medida.

#Fontes

Verificado a 10 de outubro de 2026. O comportamento do trunk pode mudar antes do lançamento.

Próximo passo

Transforme o artigo numa implementação real

Este bloco reforça a ligação interna e conduz o leitor para o passo seguinte mais útil dentro da arquitetura do site.

Cluster relacionado

Explorar outros serviços WordPress e base de conhecimento

Reforce o seu negócio com suporte técnico profissional em áreas-chave do ecossistema WordPress.

FAQ do artigo

Perguntas frequentes

Respostas práticas para aplicar o tema na execução real.

SEO-readyGEO-readyAEO-ready4 Q&A
O novo wp_kses() entra no WordPress 7.2?#
Ainda não está decidido. O relatório no Make Core indica 7.2 ou 7.3, consoante o que o período de testes revelar.
Como volto ao parser antigo?#
Devolva true no filtro wp_kses_force_legacy_parser. É uma saída temporária, enquanto corrige o código que depende do resultado antigo.
Os meus arrays de allowed html vão deixar de funcionar?#
O relatório prevê que plugins e temas não precisem de alterações, mas o resultado de alguns inputs muda. Compare conteúdo real num build trunk.
O que acontece ao conteúdo de script e style?#
Quando script ou style não são permitidos, o código novo remove também o conteúdo, não só as etiquetas. O código antigo deixava-o como texto visível.

Precisa de FAQ adaptado ao setor e mercado? Criamos uma versão alinhada com os seus objetivos de negócio.

Fale connosco

Artigos Relacionados