The WordPress HTML API in 6.9 replaces your regex hacks

A client’s high-traffic store kept throwing layout errors. The cause was a “clever” snippet that injected custom attributes into product images with preg_replace. It worked fine until someone uploaded an image whose attribute order the regex did not expect, and the layout imploded over a single misplaced double quote.

Years ago my first instinct would have been to “fix” the regex, maybe add a couple more lookarounds. That is just digging a deeper hole. If you parse HTML with regular expressions in 2025, your markup handling breaks the first time someone writes perfectly valid HTML you did not anticipate. The WordPress HTML API improvements in 6.9 remove the last excuse for brittle string manipulation.

serialize_token is now public

The change most of us will actually use is that WP_HTML_Processor::serialize_token() is now public. The processor was always good at finding things, but rebuilding the HTML safely afterwards was awkward. Now you can walk a document and emit normalized HTML for every token you hit, which matters for both security and reliability.

Here is how I fixed that client’s image attribute problem with the updated API. Instead of guessing with regex, WordPress does the normalization.

function bbioon_safe_image_processor( $html ) {
    $processor = WP_HTML_Processor::create_fragment( $html );
    $output    = '';

    while ( $processor->next_token() ) {
        // If it's an image, let's add our tracking attribute.
        if ( 'IMG' === $processor->get_tag() ) {
            $processor->set_attribute( 'data-bbioon-track', 'product-view' );
        }
        
        // This is the magic. It returns the well-formed representation of the token.
        $output .= $processor->serialize_token();
    }
    
    return $output;
}

The approach follows the official dev notes. Even when the input HTML is “junk,” the output comes back well-formed, so you stop shipping broken tags.

Mapping HTML attributes to the JavaScript dataset

Anyone who has worked with the Interactivity API or custom blocks knows that the mapping between an HTML attribute like data-wp-bind--class and the JavaScript .dataset.wpBind-class is a headache, and nothing about it is intuitive. 6.9 adds wp_js_dataset_name() and wp_html_custom_data_attribute_name() to do that conversion for you.

That kills the “how many dashes do I need?” guessing game. It is a quiet change, and it is the kind that saves you an hour of debugging on a Friday afternoon.

Semantic testing with assertEqualHTML

Testing gets a fix too. If you write unit tests for your plugins (and you should), you have probably watched assertSame() fail because one string used single quotes and the other used double. That false positive wastes time. The new assertEqualHTML() method in WP_UnitTestClass compares the meaning of the HTML rather than the characters. It knows that <img src="a.jpg" loading="lazy"> is the same as <img loading='lazy' src='a.jpg' />.

This stuff gets complicated fast. If you are tired of debugging someone else’s mess and just want your site to work, drop my team a line. We have probably seen it before. The HTML API can do a lot now, but you still need to use it without overcomplicating your codebase.

Stop fighting HTML with strings. Use the tools Core hands you, and you will spend less of your client’s budget on layout bugs you wrote yourself.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.