Updates to the HTML API in 6.9

WordPress 6.9 brings an abundance of quiet improvements to the HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways.. Updates in this release mostly represent applications of the HTML API to existing code in CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress.; these updates increase WordPressโ€™ reliability, improve its security hardening, and reduce maintenance burden on the project.

Major Updates

WP_HTML_Processorโ€‹::โ€‹serialize_token() is now public.

The HTML Processorโ€™s serialize_token() method returns a fully-normalized and well-formed representation of the currently-matched token. It was introduced in #62036 for WordPress 6.7 as a private method which performs the heavy-lifting for how the HTML API turns โ€œjunkโ€ inputs into equivalent well-formed outputs. For example:

$html = '5 < 8 & <tag a=v a="dup"id=di></3>bl&#97rg';
echo WP_HTML_Processor::normalize( $html );
// 5 &lt; 8 &amp; <tag a="v" id="di"><!--3-->blarg</tag>

Its value outside of WP_HTML_Processor::normalize() became evident, however, particularly in the creation of โ€œserialization builders1โ€ which make it possible to modify more of the HTML structure than the HTML Processor itself does. In typical HTML API loops, this method can be used to partially extract portions of the document safely:

// Extract the outerHTML of every paragraph element.
$processor = WP_HTML_Processor::create_fragment( $html );
$content   = '';
while ( $processor->next_tag( 'P' ) ) {
    $content .= $processor->serialize_token();
    $depth    = $processor->get_current_depth();
    while (
        $processor->next_token() &&
        $processor->get_current_depth() > $depth
    ) {
        $content .= $processor->serialize_token();
    }
    $content .= $processor->serialize_token();
    $content .= "\n\n";
}

WordPress understands JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a userโ€™s browser. https://www.javascript.com/. .dataset properties.

HTML provides a convenient mechanism tying HTML and JavaScript together through the custom data attributes on a tagtag A directory in Subversion. WordPress uses tags to store a single snapshot of a version (3.6, 3.6.1, etc.), the common convention of tags in version control systems. (Not to be confused with post tags.). These are the attributes starting with data- like dataโ€‘wpโ€‘interactive or dataโ€‘postโ€‘id and their values are available on the corresponding Element object in JavaScript through the .dataset property:

<span data-order="Carrots please!">
    What should we order?
</span>
<script>
document.body.addEventListener(
    'click',
    event => alert( event.target.dataset.order )
);
</script>

There are endless ways this integration can be used to add a level of dynamism to a site. Unfortunately, how the name of these attributes is transformed looks simpler than it is. For example, the dataโ€‘wpโ€‘bindโ€‘โ€‘class HTML attribute corresponds to the wpBindโ€‘Class dataset property.

To prevent confusion, WordPress 6.9 includes two new functions to map between the HTML and JavaScript names: wp_js_dataset_name() indicates what would appear on the .dataset property in a browser while wp_html_custom_data_attribute_name() indicates what name should be used in HTML to produce the .dataset property of a given name. For example:

// What would this HTML attribute name correspond to in JavaScript?
echo wp_js_dataset_name( 'data-one-two--three---four' );
// oneTwo-Three--Four

// What HTML attribute name is necessary to produce the given JavaScript name?
echo wp_html_custom_data_attribute_name( 'postId.guid' );
// data-post-id.guid

No more hard-coding HTML string assertions in unit tests.

WordPress is full of unit tests asserting specific HTML transformations. The expected outputs for these tests are usually hard-coded and sent to $this->assertSame() to compare against the actual outputs from the code under test. Unfortunately this tends to produce a high rate of false positives because of trivialities like adding an attribute in a different order than was expected, using single-quotes around an attribute value rather than double-quotes, leaving extra whitespace or not enough, or using the mistaken self-closer on an <img> or <br> tag.

When two HTML strings produce the same result in a browser they should pass regardless of their insignificant differences. To ease the development of these kinds of tests and to reduce their false-positive rates, WordPress 6.9 introduces a new method on the WP_UnitTestClass base class: $this->assertEqualHTML().

This new test assertion verifies that two strings are equivalent representations of the same normative HTML. They compare HTML strings semantically, provide more useful output than string comparison when they fail to assert, and theyโ€™re even aware of blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. semantics.

$this->assertEqualHTML(
  "<img src='puppy&period;jpg'   loading=lazy>",
  '<img loading="l&#97zy"src="puppy.jpg"/>'
);
 โœ”๏ธŽ Is equivalent html

Time: 00:00.038, Memory: 40.00 MB

OK (1 test, 1 assertion)

This test case would pass since the arguments are two equivalent constructions of the same IMG element. However, a few small changes and it succinctly highlights their differences. The addition of the block comment delimiter is for illustrative purposes only.

$this->assertEqualHTML(
    "<!-- wp:image {\"id\":5} --><img src='puppy.jpg' loading=lazy>",
    '<!-- wp:img {"id":6} --><img loading="lazy" data-priority=5 src=puppy.jpg/>'
);
 โœ˜ Is equivalent html
   โ”
   โ”œ HTML markup was not equivalent.
   โ”œ Failed asserting that two strings are identical.
   โ”Š ---ยทExpected
   โ”Š +++ยทActual
   โ”Š @@ @@
   โ”Š -'BLOCK["core/image"]
   โ”Š +'BLOCK["core/img"]
   โ”Š    {
   โ”Š -ยทยทยทยท"id": 5
   โ”Š +ยทยทยทยท"id": 6
   โ”Š    }
   โ”Š    <img>
   โ”Š +ยทยทยทยทdata-priority="5"
   โ”Š      loading="lazy"
   โ”Š -ยทยทยทยทsrc="puppy.jpg"
   โ”Š +ยทยทยทยทsrc="puppy.jpg/"
   โ”Š  '
   โ”‚
   โ•ต /WordPress-develop/tests/phpunit/includes/abstract-testcase.php:1235
   โ•ต /WordPress-develop/tests/phpunit/tests/html/equivalentHtmlTest.php:10
   โ”ด

Time: 00:00.038, Memory: 40.00 MB

The HTML API received minor updates.

  • The Tag Processorโ€™s constructor will now cast null to an empty string. Similarly, the static creator methods on the HTML Processor will return null instead of an instance of the WP_HTML_Processor class. In each case a _doing_it_wrong() notice will alert developers that these classes expect a string input. This change prevents burying the type errors, which leads to unexpected crashes later on, such as when calling get_updated_html().
  • When calling set_modifiable_text() on a SCRIPT element, updates are rejected if they contain <script or </script in them. This is a conservative measure to avoid entering the script data double escaped state (personal blogblog (versus network, site)) which is prone to misinterpretation.

Full Changelog

Enhancements

  • wp_js_dataset_name() and wp_html_custom_data_attribute_name() map between HTML attributes and the .dataset property in JavaScript. [#61501, PR#9953]
  • The WP_UnitTestClass now contains an assertEqualHTML() method which determines if two strings represent the same normative HTML. [#63527, PR#8882]
  • Multiple length checks are safely skipped when processing SCRIPT content due to an early minimum-length check. [#63738, PR#9230]
  • Encoding detection in METAMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. tags is simplified, leading to a minor performance lift. [#63738, PR#9231]
  • WP_HTML_Processor::serialize_token() is now public, making it easier to mix the full safety of the HTML API with outside code modifying and combining HTML. [#63823, PR#9456]
  • The Tag Processor and HTML Processor handle invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid. null inputs safely. [#63854, PR#9545]
  • set_modifiable_text() rejects additional contents inside a SCRIPT element when the contents could disturb its normal closing. [#63738, PR#9560]

Bug Fixes

  • Attempting to avoid the HTTP Referer problem, quirks mode is referred to as indicated_compatibility_mode. [#63391, PR#9401]
  • wp_kses() no longer unescapes escaped numeric character references for users without unfiltered_html, preserving more of the actual entered content in a post or comment. [#63630, PR#9099]
  • SCRIPT tags are properly closed in the presence of abruptly-closed HTML comments within the contents, and when the closing SCRIPT tagโ€™s tag name is delimited by a form-feed. [#63738, PR#9397]
  • wp_kses() now allows some previously-missing HTML5 semantic tags and their attributes. [#63786, PR#9379]
  • set_attribute() directly escapes syntax characters into HTML character references to avoid problems with double-escaping logic. This ensures that all values are represented accurately in the resulting HTML. [#64054, PR#10143]

Core refactors

A number of places in Core were updated to benefit from the HTML API.

  • Several of the unit tests now rely on assertEqualHTML(), including for block supports, wp_rel_nofollow(), wp_rel_ugc(), wp_kses, post-filtering, media, oEmbed filtering. [#59622, #63694, PR#5486, PR#9251, PR#9255, PR#9257, PR#9258, PR#9259, PR#9264]
  • get_url_in_content() relies on the Tag Processor to more reliably detect links. Besides improving general HTML parsing, this new version always returns the decoded href attribute, preventing confusion in downstream code. [#63694, PR#9272]
  • Processing for image blocks in classic themes is now performed via the HTML API rather than with PCREs. [#63694, PR#10218]

Acknowledgements

Props to @jonsurrell and @westonruter for reviewing this post.

  1. Methods to replace innerHTML and outerHTML, wrap an element, unwrap an element, insert elements, and more are possible by scanning through a document and conditionally copying the normalized tokens into an output string. Login to Reply<\/a><\/li><\/ul><\/div>","commentTrashedActions":"

Summary, Dev Chat, November 19, 2025

Startย of the meeting inย SlackSlack Slack is a Collaborative Group Chat Platform https://slack.com/. The WordPress community has its own Slack Channel at https://make.wordpress.org/chat/., facilitated by @amykamala ๐Ÿ”— Agenda post.

Announcements ๐Ÿ“ข

GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses โ€˜blocksโ€™ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/ย 22.1 has been released!

Gutenberg 22.1ย has been released and isย available for download! Thanks to @psykroย for writing this wonderful overview.

WordPress 6.9ย Release Candidaterelease candidate One of the final stages in the version release cycle, this version signals the potential to be a final release to the public. Also see alpha (beta).ย 2 is now available!

WordPress 6.9 Release Candidate 2 is now available for download and testing.
Further information you can find here.

WordPress 6.9ย Dev Notesdev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase.

For more detailed information, see the following WordPress 6.9 Dev Notes:

Forthcoming releases ๐Ÿš€

WordPress 6.9 Timeline

WordPress 6.9ย is planned forย December 2, 2025. Release Candidate 3 is planned forย November 25.

Call for Testing

The Test Team invitesย testing and feedbackย on the following upcomingย blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience.ย editor features:

Discussions ๐Ÿ’ฌ

CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. Block Decisions

The discussion focused on how decisions are made about which new blocks should be added to Core. @elrae raised concerns that there is no clear standard, and that blocks like the Math block benefit only a very small group of users. Others argued that Core blocks improve consistency, accessibilityAccessibility Accessibility (commonly shortened to a11y) refers to the design of products, devices, services, or environments for people with disabilities. The concept of accessible design ensures both โ€œdirect accessโ€ (i.e. unassisted) and โ€œindirect accessโ€ meaning compatibility with a personโ€™s assistive technology (for example, computer screen readers). (https://en.wikipedia.org/wiki/Accessibility), and reliability across websites. Everyone agreed that clearer and more transparent guidelines are needed to determine which blocks are truly useful and worth maintaining in the long run.

#6-9, #core, #dev-chat

Accessibility Improvements in WordPress 6.9

WordPress 6.9 brings extensive accessibilityAccessibility Accessibility (commonly shortened to a11y) refers to the design of products, devices, services, or environments for people with disabilities. The concept of accessible design ensures both โ€œdirect accessโ€ (i.e. unassisted) and โ€œindirect accessโ€ meaning compatibility with a personโ€™s assistive technology (for example, computer screen readers). (https://en.wikipedia.org/wiki/Accessibility) improvements across WordPress CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. and GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses โ€˜blocksโ€™ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/, continuing the goals to meet web content accessibility standards throughout WordPress and make it easier to author accessible content. These updates include changes to administration, customization, login and registration, bundled themes, and the blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. editor.

Core

Improvements to WordPress Core include 33 accessibility enhancements and bugbug A bug is an error or unexpected result. Performance improvements, code optimization, and are considered enhancements, not defects. After feature freeze, only bugs are dealt with, with regressions (adverse changes from the previous version) being the highest priority. fixes. Major changes include numerous new or improved screen reader notifications, a complete update of CSSCSS Cascading Style Sheets. generated content to ensure no excess content is spoken, and code changes to ensure proper semantics and improved focus management.

Administration

  • #47101 โ€“ Improve accessibility when deleting terms via AJAX: color contrast & spoken message.
  • #48655 โ€“ Improve the โ€œAdd-itemโ€ function in menus (esp. for pages)
  • #63118 โ€“ Hide โ€œSkip to Toolbarโ€ shortcut on small screens within adminadmin (and super admin)
  • #63126 โ€“ Theme preview model and Media library model having issues with Shift/Ctrl + Shift next and previous arrows.
  • #63449 โ€“ Low color contrast for <code> elements in description text on Settings > General page
  • #63546 โ€“ Fix unclosed li element in pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party-editor.php
  • #63603 โ€“ Replace deprecated / non-standard CSS for `speak` and `aural`
  • #63723 โ€“ On the Add New plugin page, put the Add Plugins screen description above the filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. menu

CustomizerCustomizer Tool built into WordPress core that hooks into most modern themes. You can use it to preview and modify many of your siteโ€™s appearance settings.

  • #42078 โ€“ Customize: fix the color hue picker HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. and accessibility
  • #47579 โ€“ Customizer โ€œSelect logoโ€ and โ€œSelect site iconโ€ look like drop areas, but are buttons.
  • #50696 โ€“ UIUI User interface & Accessibility issues in customizer menus section
  • #63011 โ€“ Customizer: The back button is not keyboard focusable
  • #63832 โ€“ Loss of focus when setting or changing the Site Logo or Site Icon in Customizer

Editing

  • #63460 โ€“ Increase color contrast for embed template
  • #61959 โ€“ Enhance Support for `popovertarget` and `popover` Attributes in Native Browser Popover APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways.

Login and Registration

  • #63281 โ€“ Password field has wrong focus on installations
  • #63286 โ€“ User profile first name, last name, nickname and email fields should have autocomplete attributes for accessibility
  • #48345 โ€“ Add Caps lock message to login screen

Media

  • #63114 โ€“ No screen reader announcements for upload image errors
  • #63238 โ€“ Remove `target=โ€_blankโ€` from Browser Uploader Link
  • #63239 โ€“ Button focus visibility issue in media upload page
  • #63571 โ€“ Excessive Spacing Between Right SidebarSidebar A sidebar in WordPress is referred to a widget-ready area used by WordPress themes to display information that is not a part of the main content. It is not always a vertical column on the side. It can be a horizontal rectangle below or above the content area, footer, header, or any where in the theme. Items in Edit Media Screen on Mobile View
  • #63973 โ€“ Add Media Button missing aria-haspopup and aria-controls

Miscellaneous

  • #40428 โ€“ Introduce best practices to hide CSS generated content from assistive technologies
  • #44267 โ€“ Privacy Request List Table: A way to show the time of request when itโ€™s older than 24 hours.
  • #63030 โ€“ Update CSS for `::-moz-placeholder` color
  • #63620 โ€“ Remove translator comments when hidden text matches visible text
  • #63950 โ€“ Tabbing through database upgrade screen shows โ€œWordPressโ€ text over logo

Bundled Themes

  • #10219 โ€“ โ€œOlder Entriesโ€ and โ€œNewer Entriesโ€ links are wrong when entries displayed in ascending order
  • #44656 โ€“ Multiple themes: Empty site title leaves empty anchor tagtag A directory in Subversion. WordPress uses tags to store a single snapshot of a version (3.6, 3.6.1, etc.), the common convention of tags in version control systems. (Not to be confused with post tags.) in headerHeader The header of your site is typically the first thing people will experience. The masthead or header art located across the top of your page is part of the look and feel of your website. It can influence a visitorโ€™s opinion about your content and you/ your organizationโ€™s brand. It may also look different on different screen sizes.
  • #52116 โ€“ Twenty Twenty: Menu + Search can cause a scroll jump on close
  • #63875 โ€“ Twenty Twenty-Two and Twenty Twenty-Five: <pre> tag overflows container, causing horizontal scroll

Widgets

  • #63531 โ€“ CategoryCategory The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging. dropdown does not meet WCAGWCAG WCAG is an acronym for Web Content Accessibility Guidelines. These guidelines are helping make sure the internet is accessible to all people no matter how they would need to access the internet (screen-reader, keyboard only, etc) https://www.w3.org/TR/WCAG21/. 2.2 A on windows and some linux systems

Gutenberg

Changes within Gutenberg include 44 accessibility fixes and enhancements, including the addition of new blocks and the block Notes feature that have undergone accessibility reviews. Numerous fundamental components have had accessibility improvements to ensure that interfaces across the editor are more consistent and understandable.ย 

Blocks

  • #68662 โ€“ Cover: Fix placeholder color options keyboard accessibility
  • #68909 โ€“ Site Title: Fix logic for โ€˜aria-currentโ€™ attribute
  • #69628 โ€“ Site Title: Prevent saving and rendering a value made of only spaces
  • #69689 โ€“ Navigation Link, Navigation Submenu: Remove the title attribute controls
  • #69821 โ€“ Social Icons: Remove custom placeholder state
  • #69837 โ€“ Navigation block: fix submenu Escape key behavior
  • #70139 โ€“ Button Block: Add HTML Element selection in Advanced settings
  • #70192 โ€“ Button: Avoid focus loss when unlinking using keyboard
  • #70210ย  โ€“ Columns block: Donโ€™t use ToolsPanelItem for Columns setting
  • #70730 โ€“ a11yAccessibility Accessibility (commonly shortened to a11y) refers to the design of products, devices, services, or environments for people with disabilities. The concept of accessible design ensures both โ€œdirect accessโ€ (i.e. unassisted) and โ€œindirect accessโ€ meaning compatibility with a personโ€™s assistive technology (for example, computer screen readers). (https://en.wikipedia.org/wiki/Accessibility): Comments Pagination Nav Wrapper
  • #64119 โ€“ Add Accordions Block
  • #73177 โ€“ Fix a11y of descriptions and alerts for โ€œInvalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid.โ€ Nav Items

Components

  • #67792 โ€“ Improve the EntitiesSavedStates modal dialog design and labeling
  • #69011 โ€“ Remove non translatable additional info from font size picker visual label and improve labeling
  • #69441 โ€“ ARIA: Fix invalid `DropdownMenu` children structure
  • #68633 โ€“ Global Styles: Prevent Unwanted ItemGroup List Rendering in Border Panel
  • #68542 โ€“ Button: Update hover styles to account for pressed state for `tertiary button`
  • #69609 โ€“ ActionModal: Add support for customisable `focusOnMount`
  • #69904 โ€“ Add new HTMLElementControl component
  • #70591 โ€“ `FormTokenField`: Fix focus lost on tab when `__experimentalExpandOnFocus` is set
  • #70096 โ€“ Components: Fix label and placeholder handling in `LinkControlSearchInput`
  • #70660 โ€“ Autocomplete: Prevent text cursor position loss when clicking to insert an item
  • #70146 โ€“ Color Picker: Improve color picker slider focus styles

Data Views

  • #67874 โ€“ Display Checkbox by default in dataviews
  • #69876 โ€“ DataViews: Always show primary action for list layout if hover isnโ€™t supported
  • #71561 โ€“ DataViews: Custom `empty` elements are no longer wrapped in `<p>` tags to improve accessibility
  • #72417 โ€“ DataViews: Use Text-Based Links for Primary Actions
  • #72501 โ€“ Dataviews: Make bulk actions text based.

Editor

  • #68481 โ€“ Fix CSS classes for the post editor iframeiframe iFrame is an acronym for an inline frame. An iFrame is used inside a webpage to load another HTML document and render it. This HTML document may also contain JavaScript and/or CSS which is loaded at the time when iframe tag is parsed by the userโ€™s browser. body.
  • #68975 โ€“ Close patterns modal on insertion and focus on inserted pattern
  • #69305 โ€“ Swap fullscreen mode snackbar notice message.
  • #69334 โ€“ InputControl: Ensure consistent placeholder color
  • #69378 โ€“ Button: Remove fixed width from small and compact buttons with icons
  • #69451 โ€“ Editor: Refactor the โ€˜PostVisibilityโ€™ component
  • #69520 โ€“ Fix shift+tab from post title
  • #69724 โ€“ Post Template Panel: Preserve parent modal when closing template creation dialog
  • #68631 โ€“ Global Styles: Fix incorrect usage of ItemGroup in the Background image panel
  • #69813 โ€“ Background Image Panel: fix focus loss
  • #70128 โ€“ Global Styles: Move `Randomize colors` button to Edit Palette panel
  • #70133 โ€“ Editor: Add label in`TextareaControl` in CollabSidebar
  • #69278 โ€“ Toolbar: Adjust colors for dark mode support
  • #70451ย  โ€“ feat: clarify label & add help text with link for Link Rel

Miscellaneous

  • #69440 โ€“ Make password protected input fields consistent.
  • #70091 โ€“ Templates: Add back button & fix focus loss when navigating through template creation flow

Acknowledgements

Props to @jorbin and @jeffpaul for reviewing this post.

#6-9, #accessibility, #dev-notes, #dev-notes-6-9

Admin menu search query changed

When creating and editing menus in the Menus interface, searching for posts and pages has historically used a full text search as a query. This can make some pages difficult to find, if they use a title that primarily uses common words in the site content.

In WordPress 6.9, the search query arguments have been changed to limit searches to only the post title. This is intended to make it easier to find the post youโ€™re looking for in search results.

The query change adds the argument search_columns with the value array( โ€˜post_titleโ€™ ) to the search. The columns correspond to the database columns in the wp_posts table.

To facilitate sites that may need the previous search logic, a filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. has been added to easily modify the search query.

/**
 * Filter the menu quick search arguments.
 *
 * @since 6.9.0
 *
 * @param array $args {
 * ย  ย  Menu quick search arguments.
 *
 * ย  ย  @type booleanย  ย  ย  $no_found_rowsย  ย  ย  ย  ย  Whether to return found rows data. Default true.
 * ย  ย  @type booleanย  ย  ย  $update_post_meta_cache Whether to update post meta cache. Default false.
 * ย  ย  @type booleanย  ย  ย  $update_post_term_cache Whether to update post term cache. Default false.
 * ย  ย  @type intย  ย  ย  ย  ย  $posts_per_page ย  ย  ย  ย  Number of posts to return. Default 10.
 * ย  ย  @type string ย  ย  ย  $post_typeย  ย  ย  ย  ย  ย  ย  Type of post to return.
 * ย  ย  @type string ย  ย  ย  $sย  ย  ย  ย  ย  ย  ย  ย  ย  ย  ย  Search query.
 * ย  ย  @type arrayย  ย  ย  ย  $search_columns ย  ย  ย  ย  Which post table columns to query.
 * }
 */
 $query_args = apply_filters( 'wp_ajax_menu_quick_search_args', $query_args );

To restore the previous behavior, you can unset the additional argument:

/**
 * Restore pre-6.9 menu search arguments.
 *
 * @param array $args Array of arguments as documented.
 *
 * @return array
 */
function restore_menu_quick_search_args( $args ) {
ย  ย  unset( $args['search_columns'] );
ย ย ย ย return $args;
}
add_filter( 'wp_ajax_menu_quick_search_args', 'restore_menu_quick_search_args' );

Related ticketticket Created for both bug reports and feature development on the bug tracker.: Improve the โ€œAdd itemโ€ function in menus.

Acknowledgements

Props to @jorbin for reviewing this post.

#6-9, #dev-notes, #dev-notes-6-9

Legacy Internet Explorer Code Removed

With WordPress 6.9, numerous legacy features that were used to support Internet Explorer have been removed. All versions of Internet Explorer have been unsupported in WordPress since version 5.8, released in July 2021. These changes continue the process of removing code that existed only to provide support for these browsers.

Removed Support for IE Conditional Scripts and Styles

Conditional comment support was added for scripts in WordPress 4.2, and for styles sometime around version 2.6.0, but was made more easily available in WordPress 3.6.

Conditional comments were a mechanism to pass scripts and styles for specific versions of IE. The last browser to support conditional comments in any way was IE9, which has been out of support by WordPress since version 4.8. No supported browser uses scripts or styles provided within conditional comments, treating them the same as any other commented code.

The feature has been removed, and using the โ€˜conditionalโ€™ argument will throw a deprecation notice (โ€œIE conditional comments are ignored by all supported browsers.โ€) if WP_DEBUG is set to true.ย 

Any style or script currently loaded using conditional arguments will be ignored, as will any dependencies of those styles or scripts if they are not already required by another script or style.

IE Conditional scripts and styles were removed in core ticket #63821.

Updates to bundled themes

All bundled themes that used conditional comments have been updated to remove usages of conditional comments and CSSCSS Cascading Style Sheets. syntax only used to support Internet Explorer.

CSS and JSJS JavaScript, a web scripting language typically executed in the browser. Often used for advanced user interfaces and behaviors. files that were only required conditionally remain in place as blank files, containing only comments to indicate when the related support was removed.ย 

Conditional comments were removed from bundled themes in #58836.ย 

IE Compatibility Removals

Compatibility scripts were removed from the Media Elements instantiation process in #63471.

#62128 removed IE-specific hacks and EOT file rules from the Genericons stylesheet for four bundled themes, from Twenty Thirteen to Twenty Sixteen.

Acknowledgements

Props to @jorbin, @westonruter, @jonsurrell and @sabernhardt for reviewing this post.

Login to Reply<\/a><\/li><\/ul><\/div>","commentTrashedActions":"

Introducing the streaming block parser in WordPress 6.9

WordPress 6.9 introduces the WP_Block_Processor class โ€” a new tool inspired by the HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. and designed for efficiently scanning, understanding, and modifying blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. structure in HTML documents.

Continue on to learn about this new class, its use-cases, and how you can take advantage of it for more efficient server-side processing.

Login to Reply<\/a><\/li><\/ul><\/div>","commentTrashedActions":"

URL-escaping functions can support HTTPS as the default protocol in WordPress 6.9

When a string passed to the esc_url() and esc_url_raw() functions does not include a protocol (https://, http://, etc.), WordPress will prepend http:// to the URLURL A specific web address of a website or web page on the Internet, such as a websiteโ€™s URL www.wordpress.org string before further processing and returning it. This is a reasonable fallback behavior, but there is currently no way to override the default protocol with another (such as https:// for social media profiles).

Starting in WordPress 6.9, the esc_url() and esc_url_raw() functions will now prepend https:// to the URL if it does not already contain a scheme and the first item in the $protocols array is 'https'. The current behavior (prepending http://) will continue when any other value is listed first within the $protocols array.

<?php
/*
 * Recommended approach for defaulting to 'https' while maintaining
 * backward compatibility.
 * 
 * Example: no protocol with $protocols and 'https' first.
 *
 * Output:
 * - WordPress >= 6.9: 'https://profiles.wordpress.org'
 * - WordPress  < 6.9: 'http://profiles.wordpress.org'
 */
echo esc_url( 'profiles.wordpress.org', array( 'https', 'http' ) );

By including 'https' first and then 'http' in the array:

  • WordPress 6.9 would prepend https:// to an incomplete URL.
  • Older WordPress versions would continue to prepend http://, which remains the default scheme when the $protocols argument is not defined. If the array only contains 'https', esc_url() would return an empty string because http is not included in the list of valid protocols.

Additional examples of output include:

<?php
/*
 * Example 1: no protocol included in $url.
 * 
 * Output:
 * - WordPress >= 6.9: 'http://profiles.wordpress.org'
 * - WordPress  < 6.9: 'http://profiles.wordpress.org'
 */
echo esc_url( 'profiles.wordpress.org' );

/*
 * Example 2: 'http' protocol included in $url.
 *
 * Output:
 * - WordPress >= 6.9: 'http://profiles.wordpress.org'
 * - WordPress  < 6.9: 'http://profiles.wordpress.org'
 */
echo esc_url( 'http://profiles.wordpress.org' );

/*
 * Example 3: 'https' protocol included in $url.
 *
 * Output:
 * - WordPress >= 6.9: 'https://profiles.wordpress.org'
 * - WordPress  < 6.9: 'https://profiles.wordpress.org'
 */
echo esc_url( 'https://profiles.wordpress.org' );

/*
 * Example 4: no protocol with $protocols and 'http' first.
 *
 * Output:
 * - WordPress >= 6.9: 'http://profiles.wordpress.org'
 * - WordPress  < 6.9: 'http://profiles.wordpress.org'
 */
echo esc_url( 'profiles.wordpress.org', array( 'http', 'https' ) );
       
/*
 * Example 5: no protocol in $url with $protocols and no 'http'.
 *
 * Output:
 * - WordPress >= 6.9: 'https://profiles.wordpress.org'
 * - WordPress  < 6.9: ''
 *
 * Note: if 'http' is not included in the $protocols array,
 * the fully escaped URL will not pass the final check that
 * a valid, allowed protocol is included.
 */
echo esc_url( 'profiles.wordpress.org', array( 'https' ) );
             
/*
 * Example 6: protocol within $url missing within $protocols.
 *
 * Output for all:
 * - WordPress >= 6.9: ''
 * - WordPress  < 6.9: ''
 *
 * Note: if 'http' is not included in the $protocols array,
 * the fully escaped URL will not pass the final check that
 * a valid, allowed protocol is included.
 */
echo esc_url( 'https://profiles.wordpress.org', array( 'http' ) );
echo esc_url( 'http://profiles.wordpress.org', array( 'https' ) );
echo esc_url( 'mailto:indana@jon.es', array( 'https', 'http' ) );

For more information, refer to #52886.


Props to @desrosj for co-authoring the note, writing the code examples and expanding on details. Props to @jorbin for review.

#6-9, #dev-notes, #dev-notes-6-9

Dev Chat Agenda โ€“ November 19, 2025

The next WordPress Developers Chat will take place on Wednesday, November 19, 2025, at 15:00 UTC in theย coreย channel onย Make WordPress Slack.

The live meeting will focus on the discussion for upcoming releases, and have an open floor section.

The various curated agenda sections below refer to additional items. If you haveย ticketticket Created for both bug reports and feature development on the bug tracker.ย requests for help, please continue to post details in the comments section at the end of this agenda or bring them up during the dev chat.

Announcements ๐Ÿ“ข

WordPress 6.9ย Release Candidaterelease candidate One of the final stages in the version release cycle, this version signals the potential to be a final release to the public. Also see alpha (beta). 2 is now available!

WordPress 6.9 Release Candidate 2 is now available for download and testing.
Further information you can find here.

WordPress 6.9 Dev Notesdev note Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase.

For more detailed information, see the following WordPress 6.9 Dev Notes:

Forthcoming releases ๐Ÿš€

WordPress 6.9 Timeline

WordPress 6.9ย is planned forย December 2, 2025. Release Candidate 3 is planned forย November 25.

Call for Testingย 

The Test Team invitesย testing and feedbackย on the following upcomingย blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience.ย editor features:

Discussions ๐Ÿ’ฌ

The discussion section of the agenda is for discussing important topics affecting the upcoming release or larger initiatives that impact the CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. Team. To nominate a topic for discussion, please leave a comment on this agenda with a summary of the topic, any relevant links that will help people get context for the discussion, and what kind of feedback you are looking for from others participating in the discussion.

Core block selection process

@elrae raises the question of how decisions on new Core blocks are made and how relevance and prioritization are determined (e.g., Math block, โ€œMarqueeโ€ in Issue 71026).

Open floor ย ๐ŸŽ™๏ธ

Any topic can be raised for discussion in the comments, as well as requests for assistance on tickets. Tickets in the milestone for the next major or maintenance release will be prioritized.

Please include details of tickets / PRs and the links in the comments, and indicate whether you intend to be available during the meeting for discussion or will be async.

#6-9, #agenda, #core, #dev-chat

More-reliable email in WordPress 6.9

Emails sent from WordPress will be more reliable in WordPress 6.9 thanks to a few updates and bugbug A bug is an error or unexpected result. Performance improvements, code optimization, and are considered enhancements, not defects. After feature freeze, only bugs are dealt with, with regressions (adverse changes from the previous version) being the highest priority.-fixes to the wp_mail() function.

The sender address is extensibly configured.

The sender address, also known as the Envelope-From, the MAIL FROM, the Return-Path (and even more), is the address where other email servers send โ€œbounce messagesโ€ when they canโ€™t deliver a message. Since WordPress 4.7.0 this value was being set by the outgoing mail server and would often end up misconfigured1. That doesnโ€™t sound like it should be a big problem โ€” a site may not receive those notifications from failed delivery โ€” but itโ€™s a bigger problem because of the Sender Policy Framework (SPF) and DMARC systems which help prevent the transmission of spam. They reject these emails entirely.

Thanks to the change in [61010], WordPress 6.9 sets the sender address in an extensibleExtensible This is the ability to add additional functionality to the code. Plugins extend the WordPress core software. way:

  • If a From email headerHeader The header of your site is typically the first thing people will experience. The masthead or header art located across the top of your page is part of the look and feel of your website. It can influence a visitorโ€™s opinion about your content and you/ your organizationโ€™s brand. It may also look different on different screen sizes. is present it uses the From address. Otherwise it defaults to wordpress@home_url(), where home_url() is โ€œthe URLURL A specific web address of a website or web page on the Internet, such as a websiteโ€™s URL www.wordpress.org for the current site where the front end is accessible.โ€
  • Plugins can then filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. the sender address via the wp_mail_from filter in the case the inferred or default address is incorrect2.

For those with custom email configurations it may be necessary to hook into the wp_mail_from filter. If your site was relying on a pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party to work around this issue before, or you relied on the phpmailer_init filter to do so, you may no longer need to do that. Otherwise, without any effort on your part, WordPress 6.9 should become more reliable out-of-the-box at sending emails.

The Encoding headers are protected between calls.

wp_mail() calls a $phpmailer global object to actually send emails, meaning that certain state is shared between calls for a given PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher request. Internal logic in the PHPMailer class looks for certain factors in a message that it uses to set or change the Encoding headers in outbound emails. Because this object is global, those encoding changes persisted and, in some cases, would apply to successive emails and cause problems when trying to read them.

In [61131] the internal encoding is reset before sending emails so that PHPMailer sends the appropriate encoding type for each email, based solely on the server configuration and specifics in that message.

Multipart messages are assigned the proper Content-Type.

For the past seventeen years there was a lurking bug in how WordPress interacts with PHPMailer for multipart messages. Ironically, the bug was introduced in a patchpatch A special text file that describes changes to code, by identifying the files and lines which are added, removed, and altered. It may also be referred to as a diff. A patch can be applied to a codebase for testing. meant to address this specific case, but an oversight left WordPress sending a corrupted ContentType to PHPMailer. In these cases, PHPMailer would further corrupt the outbound message because of this invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid. content type. In rare cases this led to a duplicate Content-Type header, but the normative expression was corrupting the multipart boundaries.

This complicated interaction is resolved in [61201] which simplifies the previous fix by relying on PHPMailerโ€™s facilities for setting the content type rather than attempting (erroneously) to manually specify that header.

Acknowledgements

Props to @jorbin, @sirlouen, @stankea, and @westonruter for reviewing this post, and to @websupporter and @stankea for providing expertise knowledge on the interactions of the sender address and SPF/DMARC/DKIM.

  1. Many mail servers auto-generate a sender address from the system user running on the server and the local server hostname, such as www@node-14-dc3.example.com. โ†ฉ๏ธŽ
  2. This could be the case for sites with more advanced email setups, particularly those which send emails from a subdomain or different domain than on which the site is hosted. โ†ฉ๏ธŽ

#6-9, #dev-notes, #dev-notes-6-9, #email

Modernizing UTF-8 support in WordPress 6.9

A number of changes in WordPress 6.9 are coming which modernize WordPressโ€™ text encoding and UTF-8 handling. These improvements establish more reliable and consistent text processing across WordPressโ€™ widely-supported environments, benefiting plugins and themes that handle international content, emoji, diacritics, and more.

TL;DR

  • UTF-8 handling in WordPress no longer depends on the running environment thanks to a new fallback pipeline written in pure PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher. This means that code which works on your development server will work everywhere itโ€™s deployedDeploy Launching code from a local development environment to the production web server, so that it's available to visitors..
  • Some legacy functions are misleading in their design and are difficult to use properly; these have been deprecated and replaced by more specific and purpose-built alternatives.
    • Prefer wp_is_valid_utf8() instead of seems_utf8().
    • Prefer wp_scrub_utf8() instead of wp_check_invalid_utf8().
    • Prefer mb_convert_encoding() instead of utf8_encode() and utf8_decode().

While humbler than some of the other exciting features in this release, this overhaul of UTF-8 support reflects WordPressโ€™ commitment to a stable and trustworthy internationalized experience.

Read on to learn more about these changes and how to avoid common mistakes and misunderstandings around strings and text.

Login to Reply<\/a><\/li><\/ul><\/div>","commentTrashedActions":"