wp_kses() ligger bak wp_kses_post(), rensing av kommentarer, widget-tekst og hvert eneste wp_kses( $html, $allowed )-kall i pluginen din. I trunk kjører den nå på WordPress HTML API i stedet for regulære uttrykk. Ifølge Dennis Snells fremdriftsrapport skal endringen inn i WordPress 7.2 eller 7.3, avhengig av hva testingen viser. Her går vi gjennom hva som endres i output, hvordan du finner koden din som berøres, og hva det midlertidige opt-out-filteret er til for.
Hva er det egentlig som endres i wp_kses()
Den gamle implementasjonen skilte markup fra hverandre med regulære uttrykk. Den nye leser det med tokenizeren i HTML API, avgjør per tagg og attributt hva som er tillatt, og skriver resultatet ut på nytt. Pull requesten heter “KSES: Reimplement with Tag Processor” (PR 13271) og hører til Trac-saken 66208. Ifølge PR-en ligger den nye koden i en funksjon som heter wp_sanitize_html_kses().
Hensikten i rapporten er tydelig: wp_kses() skal ikke bli dårligere enn før. Rapporten sier også at plugins og temaer ikke bør trenge endringer. Begge utsagnene kan stemme mens testene dine likevel blir røde, fordi “like trygt” ikke betyr “like bytes”. Ny serialisering er hele poenget, og den endrer strenger.
Kilde: Progress Report: wp_kses(), 7. oktober 2026.
Status 15. oktober 2026: endringen er i trunk. Den kom inn 7. oktober 2026 som changeset 64233 (commit på GitHub), og commit-meldingen sier at kode som kaller funksjonen ikke skal trenge endringer. Docblocken til wp_kses() i trunk har allerede @since 7.2.0, men rapporten sier fortsatt 7.2 eller 7.3, og det er testperioden som avgjør hva som kommer med i den endelige versjonen, ikke annoteringen. 9. oktober kom to oppfølgingscommits i kses.php: én normaliserer alle blokkavgrensere, den andre serialiserer JSON-attributter for blokker bare når de ikke er tomme (filhistorikk).
Hvilke inndata gir annerledes output
Rapporten viser par av før og etter. Blokken under er modellert etter dem (min egen tabell over tillatte tagger, inndata fra rapporten). Kjør tilfellene på din egen trunk-bygg før du stoler på min gjengivelse.
<?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="boat" src=\'vehicle.png\' /> & the wheels…', $allowed );
// legacy: The <IMG class="bike" src="vehicle.png" /> & the wheels…
// new: The <img class="bike" src="vehicle.png"> & the wheels…
wp_kses( 'Add <code>/?preview=true§ion=grilling</code>.', $allowed );
// legacy: Add <code>/?preview=true&section=grilling</code>.
// new: Add <code>/?preview=true§ion=grilling</code>.
wp_kses( 'Click on the <butto', $allowed );
// legacy: Click on the <butto
// new: Click on the (trailing space, nothing else)Rapporten grupperer forskjellene slik:
- Normalisering. Taggnavn blir små bokstaver, attributter får doble anførselstegn, ved duplikate attributter vinner det første, og tegnreferanser skrives på nytt.
- Løse vinkelparenteser. Tekst som
<$500eller>5yoble tidligere svelget. Nå blir den til<og>, og teksten består. - Tvetydig ampersand. En navngitt referanse uten semikolon, for eksempel
§ioni en URL i en tekstnode, dekodes slik nettleseren gjør det. Derfor blir det tredje tilfellet til paragraftegnet. - Script og style. Når disse elementene ikke er tillatt, forsvinner innholdet sammen med taggene. Den gamle koden lot innholdet stå igjen som synlig tekst.
- Avkortet inndata. En ufullstendig siste tagg forkastes, den escapes ikke.
- Spesielle elementer. Taggliknende tekst inni en tillatt
<title>escapes, mens samme tekst inni en<div>forsvinner sammen med den ukjente taggen. - CDATA, PLAINTEXT og ufullstendige spesialelementer. CDATA-seksjoner og innholdet i
PLAINTEXTblir vanlig escapet tekst. En<title>eller et annet spesialelement som kommer ufullstendig, fjernes helt. - SVG og MathML. Innhold som krever kompleks parsing gjør at funksjonen stopper og bare returnerer det som kom før. Rapporten viser en
<li>med MathML og en nøstet<span>som kuttes der. - Harde grenser. Enkelte ødelagte kommentarer,
NOSCRIPTog forvekslbare elementer avvises nå. - Ubalanserte tagger. Beholdes med vilje, fordi eksisterende kode er avhengig av det.
På en typisk norsk nettbutikk er de første stedene å lete produktbeskrivelser med mål som “<5 cm” limt inn fra leverandørens regneark, importert leverandør-HTML med store bokstaver i taggene, og sidebyggere som skriver ut inline SVG. Det er en antakelse om hvor du bør lete, ikke en måling.
Jeg fant ikke bekreftet i kildene jeg leste hvordan <script> oppfører seg når du uttrykkelig tillater det i arrayen. Test det tilfellet selv i stedet for å anta et resultat.
Hvorfor wp_kses() bruker Tag Processor og ikke HTML Processor
HTML API består av to deler. WP_HTML_Tag_Processor har fantes siden WordPress 6.2 og går gjennom dokumentet token for token: tagger, kommentarer og tekstnoder (klassereferanse). WP_HTML_Processor kom i 6.4, bygger dokumenttreet og avbryter tidlig når den møter markup den ikke støtter ennå, for ikke å ødelegge dokumentet (klassereferanse).
En fotnote i rapporten sier at nye wp_kses() bygger på Tag Processor. Den parser hver tagg, kommentar og tekstnode, men kjenner ikke trestrukturen i dokumentet. HTML Processor bygger det treet, mot betydelig mer tid og arbeid. PR-beskrivelsen forklarer hvorfor åpne elementer ikke lukkes: mye kjernekode kaller wp_kses() med bevisst ufullstendig inndata, for eksempel en åpnende wrapper-tagg med en del av innholdet, adskilt fra den lukkende taggen. Å isolere innhold ved å lukke slike elementer ville ødelagt nettsteder. Derfor forblir ubalanserte tagger i listen over ubalanserte.
Fungerer min egen allowed-html-array fortsatt
For det meste, siden tillatelseslogikken er den samme: en tagg eller et attributt står i arrayen eller ikke. Det som endres er hva som kommer ut rundt. Tre mønstre fortjener et blikk.
- Arrayer som tillater inline
scriptellerstyle. En shortcode som skriver ut et inline-skript og sender det gjennomwp_kses()medscripttillatt, ligger midt i området rapporten berører. Sammenlign gammel og ny output. Vurder også om skriptet heller bør gå viawp_add_inline_script()enn via sanitizeren. - Arrayer som tillater
svgellermath. Inline ikonsett er det vanlige tilfellet. Hvis regelen fra rapporten gjelder, kan output kuttes ved den første konstruksjonen parseren ikke håndterer. Sammenlign hvert ikon du leverer. - Arrayer for
<title>og lignende.<title>er et spesielt element, og innholdet behandles som tekst. Derfor eksempelet med escapet<sneaky>.
Tillater arrayen bare a, strong, em, img og noen få attributter, blir effekten trolig kosmetisk: <IMG ... /> blir <img ...>.
Hvor WordPress kjører wp_kses() uten at du kaller den
Kjernen kobler renseren til lagring. kses_init() er koblet til hookene init og set_current_user i default-filters.php og legger bare til filtrene når gjeldende bruker mangler rettigheten unfiltered_html (referanse for kses_init). Da legger kses_init_filters() wp_filter_kses på title_save_pre, wp_filter_post_kses på content_save_pre, excerpt_save_pre og content_filtered_save_pre, og filtrerer pre_comment_content med den enkle varianten (referanse for kses_init_filters).
Referansesiden for wp_kses() lister i tillegg dusinvis av direkte kall i kjernen, blant dem Walker_Comment::filter_comment_text(), wp_filter_oembed_result(), img_caption_shortcode(), filter_block_kses_value() og installasjonsskjermene for utvidelser og temaer (referanse for wp_kses). Omskrivingen berører altså kommentarer, oEmbed-resultater og bildetekster selv om koden din aldri kaller wp_kses().
For testing får dette en praktisk følge. På en enkeltside har administratorer og redaktører unfiltered_html, på multisite bare brukere med rollen Superadmin (roller og rettigheter). Innholdet deres går ikke gjennom kses ved lagring. Test lagring med en konto med rollen Forfatter eller Bidragsyter, der filtrene faktisk kjører, og ikke bare med din egen admin-innlogging.
Hva går i stykker i tester som sammenligner renset HTML
Alt som sjekker en eksakt streng. En test som den første assertionen under består i dag og kan feile etter omskrivingen, selv om markupen betyr det samme. Den andre assertionen tåler normaliseringen.
<?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' ) );Fest deg til oppførsel, ikke bytes. Fixtures som må forbli strenglike, genererer du én gang på trunk, leser diffen som et menneske og committer den nye forventede verdien med en kommentar om hvilken versjon den endret seg i. Et generelt “oppdater snapshots” er måten en ekte regresjon blir godkjent på.
Visuelle tester og golden-filer trenger samme behandling. E-postmaler du renser før utsending er et typisk sted der en lagret streng sammenlignes med en fersk.
Slik bruker du assertEqualHTML() i tester for wp_kses()
I kommentarene til rapporten anbefaler Jon Surrell assertEqualHTML() til alle som får testfeil på grunn av kses-forskjeller. Metoden kom i WordPress 6.9 som en del av WP_UnitTestCase (sak 63527). Ifølge innlegget til JuanMa Garrido på Developer Blog, datert 26. februar 2026, parser den begge strengene med WP_HTML_Processor og sammenligner trærne, ikke bytene.
Den ignorerer akkurat den typen forskjell omskrivingen gir: store og små bokstaver i taggnavn, anførselstegn, rekkefølgen på attributter og klasser, de ulike formene av en tegnreferanse og dupliserte attributter, der det første vinner. Den feiler fortsatt når innhold, en attributtverdi eller en klasse endres, eller når et attributt mangler eller er i tillegg.
<?php
$this->assertEqualHTML(
'<a href="/x">Read</a>',
wp_kses_post( "<A HREF='/x'>Read</A>" )
);Det samme innlegget trekker grensen: når eksakt serialisering betyr noe, som innholdet i en <script> eller en bestemt data-wp-context-verdi, bruker du fortsatt assertSame(). For kses betyr det assertSame() for hvert script- eller style-tilfelle du tillater, og assertEqualHTML() for resten. Kjører testsuiten din mot WordPress 6.9 eller nyere, er metoden allerede tilgjengelig.
Hvordan tester jeg på trunk uten å røre produksjon
Tre veier, alle på staging eller lokalt. Dette er mine forslag, ikke en del av den offisielle rapporten.
Pluginen WordPress Beta Tester. Den kan flytte en staging-side til nattlige bygg og senere til 7.2-betaene. Ifølge tidsplanen kommer Beta 1 20. oktober 2026. Endringen kom inn i trunk 7. oktober, men sjekk likevel at filteret wp_kses_force_legacy_parser finnes i koden du faktisk installerte.
WP-CLI nightly. På en kopi du kan kaste:
# 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.txtwp-env. Pek kjernen mot trunk-speilet og monter pluginen:
{
"core": "WordPress/WordPress#master",
"plugins": [ "." ]
}Uansett vei: avslutt med å bekrefte at filteret finnes, for eksempel med grep -rn wp_kses_force_legacy_parser wp-includes/. Finnes det ikke, tester du ikke omskrivingen.
Hvordan sammenligner jeg renset output på ekte innhold
Syntetiske tilfeller finner bare feil du allerede har tenkt deg. Den nyttige testen er din egen database. Skriptet under renser hvert publiserte innlegg to ganger, én gang med tvunget gammel parser og én uten, og skriver bare ut innleggene som er forskjellige.
<?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 ) );Kjør det på en kopi av produksjonsdatabasen, siden redaktører limer inn rare ting. Les de første tjue diffene for hånd. Regn med en håndfull gjentakende årsaker (selvlukkende tagger, en løs < i en måleangivelse, inline SVG). Retter du én årsak, retter du mange innlegg samtidig.
Utvid nettet med samme mønster: bytt wp_kses_post() med kallet pluginen din gjør med sin egen array, og mat det med opsjonsverdier, widget-tekst og kommentarer, ikke bare innlegg.
Vær klar over hva skriptet måler. Det kjører wp_kses_post() på alt innhold, også innlegg skrevet av brukere med unfiltered_html, som aldri gikk gjennom kses ved lagring. For de innleggene beskriver diffen ingen synlig endring i dag. Den viser hva som ville skjedd om noen uten den rettigheten lagret dem på nytt.
Når bør jeg bruke opt-out for den gamle parseren
Filteret heter wp_kses_force_legacy_parser. Returnerer det true, gjeninnføres den gamle parseren. Rapporten beskriver det som en måte for nettstedeiere å slippe å kjøre erstatningskoden, og ordet som teller er midlertidig.
<?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' );To situasjoner rettferdiggjør det. For det første: du fant en regresjon på en kundeside i testvinduet og må holde siden stabil mens du retter koden eller melder feilen. For det andre: en plugin du ikke styrer slutter å virke, og leverandøren har ikke gitt ut en fiks. Legg filteret i en mu-plugin så det er synlig ett sted, og knytt en sak med slettedato til det.
Ikke lever det som permanent standard. Den gamle implementasjonen har kjente problemer som omskrivingen skal fikse, blant annet PCRE-krasj ved store attributtverdier og skriptinnhold som vises som synlig tekst, ifølge PR-beskrivelsen. Et stille opt-out beholder problemene og skjuler migreringen for neste utvikler.
Rapporten lover ingen lang overgangstid. Den sier at den opprinnelige implementasjonen beholdes inntil videre av kompatibilitetshensyn og forsvinner i fremtidige versjoner, kanskje allerede i WordPress 7.2.0. Planlegg som om den gamle parseren kan være borte i neste hovedversjon.
Slik virker det i trunk: wp_kses() kjører filteret med true som standardverdi, og default-filters.php registrerer __return_false på det, som er det som slår på den nye koden. wp-settings.php laster mu-plugins etter default-filters.php, så din __return_true med standardprioritet kjører senere og vinner (kses.php i trunk). Ikke kall wp_sanitize_html_kses() direkte: docblocken merker den som privat og midlertidig.
Ytelse i nye wp_kses() sammenlignet med den gamle parseren
Det finnes ingen publiserte tall. Da Dennis Snell ble spurt om benchmarks i kommentarene til rapporten, svarte han at denne endringen ikke inneholder noen, og at forventningen er at den nye koden er raskere og bruker mindre minne. Han gir tre grunner:
- Den gamle koden deler dokumentet opp i et stort token-array og holder det i minnet. Den nye koden går fremover token for token uten å holde på det arrayet.
- Den gamle koden gjør flere tekstbehandlingsrunder over hele dokumentet. Den nye fjerner de fleste og klarer seg stort sett med én runde fremover.
- Den gamle koden kaller alltid
serialize_blocks( parse_blocks() )på hele dokumentet. Den nye parser en blokk først når det faktisk finnes en, og lener seg påWP_Block_Parserfor enda senere evaluering.
Snell innrømmer også at deler av HTML-behandlingen er mer krevende i den nye implementasjonen. Renser nettstedet ditt mye innhold per forespørsel, mål på staging med filteret av og på, og legg tallene i kommentarene til rapporten. Det er akkurat det forfatteren ber om.
Hva er tidsplanen for WordPress 7.2
Fra innlegget om 7.2-tidsplanen, alt klokken 15:00 UTC:
| Milepæl | Dato |
|---|---|
| Beta 1 | 20. oktober 2026 |
| Beta 2 | 27. oktober 2026 |
| Beta 3 | 3. november 2026 |
| Beta 4 | 10. november 2026 |
| RC1 | 17. november 2026 |
| RC2 | 24. november 2026 |
| RC3 | 1. desember 2026 |
| Endelig utgivelse | 8. desember 2026 |
Rapporten sier 7.2 eller 7.3. Du kan altså ikke regne med noen av dem, men heller ikke utelukke 7.2. En fornuftig plan: kjør diff-skriptet på staging før Beta 1, igjen etter RC1, og meld alt uventet på Trac-saken mens vinduet er åpent. Akkurat slik tilbakemelding ber forfatteren om.
Hva bør et byrå gjøre denne uken
- Søk i koden etter
wp_kses(,wp_kses_post(,wp_kses_data(og egne$allowed-arrayer. List opp hvilke som får HTML fra brukere eller redaktører. - Sett opp en trunk-staging via en av veiene over og bekreft at filteret finnes.
- Kjør diff-skriptet mot en kopi av produksjonsinnholdet. Sorter etter årsak, ikke etter innlegg.
- Skriv om skjøre tester slik at de sjekker struktur, og generer strengfixtures én gang med menneskelig gjennomgang.
- Sjekk shortcodes og blokker som sender ut inline script, style, SVG eller MathML.
- Avgjør per kunde om opt-out trengs, dokumenter det og sett en slettedato.
Ligger det flere år med egen rensekode rundt et plugin-økosystem i prosjektet, passer en slik gjennomgang inn i tjenesten vår for skreddersydd WordPress-utvikling.
Kilder
- Progress Report: wp_kses(), Make Core, 7. oktober 2026. Eksempler, filternavn, utsagnet om 7.2 eller 7.3.
- Tidsplan for 7.2 release party, Make Core, 6. oktober 2026.
- Pull request 13271, KSES: Reimplement with Tag Processor. Funksjonsnavn, filter, liste over endringer i oppførsel. Trac-sakene 66208 og 65984 er nevnt der.
- Trac-sak 66208. Trac viste meg en nettlesersjekk, så opplysningene om saken kommer fra PR-en og commit-meldingen.
- Changeset 64233 og GitHub-commit 7119e1b, 7. oktober 2026. Dato i trunk, commit-melding, lukkede saker 37698, 58921, 59310 og 63208.
- kses.php i trunk og default-filters.php. Standardverdien til filteret, annoteringen
@since 7.2.0, hookene tilkses_init(). - Referanser for wp_kses(), kses_init(), kses_init_filters(), WP_HTML_Tag_Processor og WP_HTML_Processor på developer.wordpress.org.
- A better way to test HTML in WordPress with assertEqualHTML(), WordPress Developer Blog, 26. februar 2026.
- Roles and Capabilities, WordPress-dokumentasjon. Hvilke roller som har
unfiltered_html.
Sist kontrollert 15. oktober 2026 mot trunk. Oppførselen i trunk kan endre seg før utgivelsen.






