Title: dev-notes-6-9 – Make WordPress Core

---

#  Tag Archives: dev-notes-6-9

 [  ](https://profiles.wordpress.org/ramonopoly/) [ramonopoly](https://profiles.wordpress.org/ramonopoly/)
2:33 am _on_ December 10, 2025     
Tags: [6-9 ( 87 )](https://make.wordpress.org/core/tag/6-9/),
[dev-notes ( 621 )](https://make.wordpress.org/core/tag/dev-notes/), dev-notes-6-
9   

# 󠀁[Adjacent Post Navigation Changes in WordPress 6.9 and Compatibility Issues](https://make.wordpress.org/core/2025/12/10/adjacent-post-navigation-changes-in-wordpress-6-9-and-compatibility-issues/)󠁿

## TL;DR

WordPress 6.9 introduced a fix for adjacent post navigation when posts have identical
publication dates. While this resolved a long-standing 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.,
it inadvertently caused infinite loops in some extensions that modify the `get_adjacent_post()``
WHERE` clause.

## What Changed in WordPress 6.9

In [WordPress 6.9 (Trac #8107)](https://core.trac.wordpress.org/ticket/8107), a 
bug fix landed where next/previous post navigation failed when multiple posts shared
identical `post_date` values. This commonly occurred when bulk-publishing draft 
posts.

### The Technical Change

The `get_adjacent_post()` function’s `WHERE` clause was modified to include ID-based
comparison as a tiebreaker:

**Before (WordPress 6.8 and earlier):**

    ```language-sql
    WHERE p.post_date > '2024-01-01 12:00:00' 
      AND p.post_type = 'post'
    ```

**After (WordPress 6.9):**

    ```language-sql
    WHERE (
        p.post_date > '2024-01-01 12:00:00' 
        OR (
          p.post_date = '2024-01-01 12:00:00' 
          AND p.ID > 123
        )
      ) 
      AND p.post_type = 'post'
    ```

This ensures deterministic ordering when posts have identical dates, using the post
ID as a secondary sort criterion.

Additionally, the `ORDER BY` clause was updated:

    ```language-sql
    -- Before
    ORDER BY p.post_date DESC 
    LIMIT 1

    -- After  
    ORDER BY p.post_date DESC, 
             p.ID DESC 
    LIMIT 1
    ```

## The Problem: Infinite Loops in Some Themes/Plugins

As [Trac ticket #64390](https://core.trac.wordpress.org/ticket/64390) documents,
some plugins and themes modify adjacent post navigation to change behavior. For 
example, WooCommerce’s Storefront theme navigates between products instead of regular
posts. These plugins use the `get_{$adjacent}_post_where` filterFilter Filters are
one of the two types of Hooks [https://codex.wordpress.org/Plugin_API/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. to replace the current post’s date with a different post’s date.

Here’s what was happening:

 1. 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/](https://wordpress.org/plugins/)
    or can be cost-based plugin from a third-party. hooksHooks In WordPress theme and
    development, hooks are functions that can be applied to an action or a Filter in
    WordPress. Actions are functions performed when a certain event occurs in WordPress.
    Filters allow you to modify certain functions. Arguments used to hook both filters
    and actions look the same. into `get_previous_post_where` filter.
 2. Plugin does string replacement: replaces `$current_post->post_date` with `$target_product-
    >post_date`.
 3. **Problem**: The new `WHERE` clause structure includes the post date in TWO places(
    date comparison `AND ID` comparison).
 4. Simple string replacement modified the date comparison but left the ID comparison
    unchanged.
 5. Query returns the same post repeatedly → infinite loopLoop The Loop is PHP code
    used by WordPress to display posts. Using The Loop, WordPress processes each post
    to be displayed on the current page, and formats it according to how it matches
    specified criteria within The Loop tags. Any HTML or PHP code in the Loop will 
    be processed on each post. [https://codex.wordpress.org/The_Loop](https://codex.wordpress.org/The_Loop).

### Real-World Example: Storefront Theme

The [fix](https://github.com/woocommerce/storefront/pull/2202/files) to the WooCommerce
Storefront theme illustrates this issue. They had to add special handling for the
ID comparison:

    ```php
    // Replace the post date (works as before)
    $where = str_replace( $post->post_date, $new->post_date, $where );

    // NEW: Also need to replace the ID comparison (WordPress 6.9+)
    if ( strpos( $where, 'AND p.ID ' ) !== false ) {
        $search = sprintf( 'AND p.ID %s ', $this->previous ? '<' : '>' );
        $target = $search . $post->ID;
        $replace = $search . $new->ID;
        $where = str_replace( $target, $replace, $where );
    }
    ```

## For Plugin Developers: Detecting and Fixing the Issue

### How to Detect If Your Plugin Is Affected

Your plugin is likely affected if it:

 1. Uses the `[get_{$adjacent}_post_where](https://developer.wordpress.org/reference/hooks/get_adjacent_post_where/)`
    filter.
 2. Performs string replacement on post dates in the `WHERE` clause.
 3. Changes which post is considered “adjacent” (like navigating between custom post
    types instead).

To test if your plugin works correctly with WordPress 6.9:

 1. Create 3-4 posts with identical publication dates (bulk publish drafts).
 2. Navigate between them using your plugin’s adjacent post functionality.
 3. Verify that navigation moves to different posts (not the same post repeatedly).
 4. Check for infinite loops or performance issues.

### Quick Fix: Handle the ID Comparison

If you’re doing date replacement in the `WHERE` clause, you also need to handle 
the ID comparison. There are numerous ways to tie a knot, but the following example
is loosely inspired by [Storefront’s recent fix](https://github.com/woocommerce/storefront/pull/2202/files#diff-ba5e7e4797948a33b056729a21d26c58de8bdbef15cbe182517b92e9ebeb1066R149).

    ```php
    add_filter( 'get_next_post_where', 'example_custom_adjacent_post_where', 10, 5 );
    add_filter( 'get_previous_post_where', 'example_custom_adjacent_post_where', 10, 5 );

    function example_custom_adjacent_post_where( $where, $in_same_term, $excluded_terms, $taxonomy, $post ) {

        // IMPORTANT: Replace this with your logic to find the desired adjacent post.
        $adjacent_post = example_find_adjacent_post_function( $post );

        if ( $adjacent_post instanceof WP_Post ) {
            // Replace the date comparison.
            $where = str_replace( $post->post_date, $adjacent_post->post_date, $where );

            // Replace the post ID in the comparison.
            $where = preg_replace(
                "/AND p\.ID (<|>) {$post->ID}\)/",
                "AND p.ID $1 {$adjacent_post->ID})",
                $where
            );
        }

        return $where;
    }
    ```

You could also add a `version_compare( $wp_version, '6.9', '>=' )` test if you’d
like to support multiple versions.

**_Important_**: don’t forget to first test any code on your site, and customize
it according to your needs.

## Next time

At the time, this was not a known breaking change, and was classed as a bug fix.

However as [@jmdodd](https://profiles.wordpress.org/jmdodd/) [points out in the ticket](https://core.trac.wordpress.org/ticket/64390),
changes to `WP_Query`, especially SQL changes should be, by default, communicated
more widely. Going forward:

 1. Reach out to known plugins using the `get_{$adjacent}_post_where` filter.
 2. Include a migrationMigration Moving the code, database and media files for a website
    site from one server to another. Most typically done when changing hosting companies.
    guidance in the 6.9 field guideField guide The field guide is a type of blogpost
    published on Make/Core during the release candidate phase of the [WordPress release cycle](https://make.wordpress.org/core/handbook/about/release-cycle/).
    The field guide generally lists all the dev notes published during the beta cycle.
    This guide is linked in the about page of the corresponding version of WordPress,
    in the release post and in the HelpHub version page. (as applicable).
 3. Test against any known, popular plugins that modify adjacent post queries.

## What’s Next and Getting Help

[Discussions have started on the ticket](https://core.trac.wordpress.org/ticket/64390)
about ways to make this more robust in future WordPress versions. If you’re experiencing
issues related to this change:

 1. Check [Trac ticket #64390](https://core.trac.wordpress.org/ticket/64390) for the
    latest updates.
 2. Ask questions in the [#core channel](https://wordpress.slack.com/archives/C02RQBWTW)
    on WordPress SlackSlack Slack is a Collaborative Group Chat Platform [https://slack.com/](https://slack.com/).
    The WordPress community has its own Slack Channel at [https://make.wordpress.org/chat/](https://make.wordpress.org/chat/).
 3. Review the [original fix PR #10394](https://github.com/WordPress/wordpress-develop/pull/10394).

Thank you for your patience and understanding. If you maintain a plugin affected
by this change, please update it using the guidance above, and don’t hesitate to
reach out if you need assistance.

Thanks to [@westonruter](https://profiles.wordpress.org/westonruter/) [@isabel_brison](https://profiles.wordpress.org/isabel_brison/)
[@andrewserong](https://profiles.wordpress.org/andrewserong/) [@jmdodd](https://profiles.wordpress.org/jmdodd/)
for helping to prepare this post.

[#6-9](https://make.wordpress.org/core/tag/6-9/), [#dev-notes](https://make.wordpress.org/core/tag/dev-notes/),
[#dev-notes-6-9](https://make.wordpress.org/core/tag/dev-notes-6-9/)

 [  ](https://profiles.wordpress.org/wildworks/) [Aki Hamano](https://profiles.wordpress.org/wildworks/)
4:10 am _on_ December 1, 2025     
Tags: [6-9 ( 87 )](https://make.wordpress.org/core/tag/6-9/),
[dev-notes ( 621 )](https://make.wordpress.org/core/tag/dev-notes/), dev-notes-6-
9   

# 󠀁[Ability to Hide Blocks in WordPress 6.9](https://make.wordpress.org/core/2025/12/01/ability-to-hide-blocks/)󠁿

WordPress 6.9 now includes a built-in feature to hide blocks, making it easy to 
tuck content away without deleting it. You can now hide blocks: select a 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., click the ellipsis,
and choose “Hide”. Hidden blocks are visually removed from the editor, and fully
omitted from the published markup. Scripts and styles for hidden blocks are also
omitted from the rendered page by default (see [WordPress 6.9 Frontend Performance Field Guide](https://make.wordpress.org/core/2025/11/18/wordpress-6-9-frontend-performance-field-guide/#omit-styles-and-scripts-for-hidden-blocks-by-default)
for more details).

To unhide a block, open the List View, identify hidden blocks via the “Hidden” icon
next to them, open the ellipsis menu again, and choose “Show”. You can also toggle
Hide/Show from the keyboard: use Ctrl + Shift + H on Windows or Linux, ⌘ + Shift
+ H on macOS.

## How to disable the hide option

Because it is implemented as a standard Block 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. support flag, opting into
or out of this capabilitycapability A **capability** is permission to perform one
or more types of task. Checking if a user has a capability is performed by the `
current_user_can` function. Each user of a WordPress site might have some permissions
but not others, depending on their role. For example, users who have the Author 
role usually have permission to edit their own posts (the “edit_posts” capability),
but not permission to edit other users’ posts (the “edit_others_posts” capability).
aligns with the rest of the block supports.

The support is enabled by default for every block type except for a short list of
coreCore Core is the set of software required to run WordPress. The Core Development
Team builds WordPress. blocks. To disable the support selectively, hook into the
[`block_type_metadata()` filter](https://developer.wordpress.org/reference/hooks/block_type_metadata/),
adjust the metadata, and update the `supports.visibility` flag:

    ```php
    function disable_block_visibility_support( $metadata ) {
    	// Disable visibility support for the core/group block.
    	if ( isset( $metadata['name'] ) && 'core/group' === $metadata['name'] ) {
    		$metadata['supports']['visibility'] = false;
    	}
    	return $metadata;
    }
    add_filter( 'block_type_metadata', 'disable_block_visibility_support' );
    ```

For additional implementation details and history, see [Gutenberg PR #71203](https://github.com/WordPress/gutenberg/pull/71203).

---

Props to [@joen](https://profiles.wordpress.org/joen/) for co-authoring the note.

Props to [@westonruter](https://profiles.wordpress.org/westonruter/), [@ramonopoly](https://profiles.wordpress.org/ramonopoly/)
for review.

[#6-9](https://make.wordpress.org/core/tag/6-9/), [#dev-notes](https://make.wordpress.org/core/tag/dev-notes/),
[#dev-notes-6-9](https://make.wordpress.org/core/tag/dev-notes-6-9/)

 [  ](https://profiles.wordpress.org/priethor/) [Héctor Prieto](https://profiles.wordpress.org/priethor/)
12:18 pm _on_ November 25, 2025     
Tags: [6-9 ( 87 )](https://make.wordpress.org/core/tag/6-9/),
[dev-notes ( 621 )](https://make.wordpress.org/core/tag/dev-notes/), dev-notes-6-
9   

# 󠀁[Miscellaneous Editor Changes in WordPress 6.9](https://make.wordpress.org/core/2025/11/25/miscellaneous-editor-changes-in-wordpress-6-9/)󠁿

 1. [Block Variations: Have getActiveBlockVariation fall back to default variation](https://make.wordpress.org/core/2025/11/25/miscellaneous-editor-changes-in-wordpress-6-9/#block-variations-have-getactiveblockvariation-fall-back-to-default-variation)
 2. [Core-data: Media Entity Deprecation](https://make.wordpress.org/core/2025/11/25/miscellaneous-editor-changes-in-wordpress-6-9/#core-data-media-entity-deprecation)
 3.  a. [What is being deprecated?](https://make.wordpress.org/core/2025/11/25/miscellaneous-editor-changes-in-wordpress-6-9/#what-is-being-deprecated)
     b. [Why is this being deprecated?](https://make.wordpress.org/core/2025/11/25/miscellaneous-editor-changes-in-wordpress-6-9/#why-is-this-being-deprecated)
     c. [How to update your code to use the attachment entity](https://make.wordpress.org/core/2025/11/25/miscellaneous-editor-changes-in-wordpress-6-9/#how-to-update-your-code-to-use-the-attachment-entity)
     d.  a. [Replacing API calls](https://make.wordpress.org/core/2025/11/25/miscellaneous-editor-changes-in-wordpress-6-9/#replacing-api-calls)
         b. [Changes to the caption property when using the getEditedEntityRecord selector](https://make.wordpress.org/core/2025/11/25/miscellaneous-editor-changes-in-wordpress-6-9/#changes-to-the-caption-property-when-using-the-geteditedentityrecord-selector)
 4. [Block Editor: Support passing updater function to setAttributes](https://make.wordpress.org/core/2025/11/25/miscellaneous-editor-changes-in-wordpress-6-9/#block-editor-support-passing-updater-function-to-setattributes)
 5. [SelectControl: Moved class names to the component root](https://make.wordpress.org/core/2025/11/25/miscellaneous-editor-changes-in-wordpress-6-9/#selectcontrol-moved-class-names-to-the-component-root)
 6. [Registering custom social icons](https://make.wordpress.org/core/2025/11/25/miscellaneous-editor-changes-in-wordpress-6-9/#registering-custom-social-icons)

### 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. Variations: Have `getActiveBlockVariation` fall back to default variation

WordPress 6.9 introduces a [small change](https://github.com/WordPress/gutenberg/pull/63858)
to active block variation detection.

To understand what that change looks like, recall that a block variation can include
an [`isActive` criterion](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/#using-isactive)
that will be used to determine if a given block instance matches the variation.

The change concerns the case in which none of the `isActive` criteria of a block
type’s variations match a given block instance. In this case, WordPress 6.9 will
use the variation with the [`isDefault` property](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/#using-isdefault)
set to `true` as fallback, if any.

Two limitations apply:

 1. The variation with the `isDefault` property is only used as fallback if it doesn’t
    _also_ include an `isActive` criterion, as that would mean that the variation did
    not match that criterion (and thus cannot be assumed to be active).
 2. The fallback is only applied for the `block` and `transform` scopes but not to 
    the `inserter`, as to not affect the block name displayed there.

In practice, the updated behavior should be consistent with users’ and developers’
expectations, as the `isDefault` variation is typically used to set a default block
variation different from the “vanilla” block type.

Together with the improvements made to active block variation detection [in WordPress 6.6](https://make.wordpress.org/core/2024/06/18/improvements-to-active-block-variation-detection/),
this change allows block authors to express the criteria for active block detection
in a very succinct and JSONJSON JSON, or JavaScript Object Notation, is a minimal,
readable format for structuring data. It is used primarily to transmit data between
a server and web application, as an alternative to XML.-only manner. For an example,
see how these principles were applied to [rewrite Group block variations](https://github.com/WordPress/gutenberg/pull/63100).

### CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress.-data: Media Entity Deprecation

#### What is being deprecated?

In WordPress 6.9, the `@wordpress/core-data` package’s `media` entity is being deprecated.
This entity is usually accessed through a range of APIs:

 * The `getMedia` and `getMediaItems` selectors or resolvers.
 * The `saveMedia` and `deleteMedia` actions.
 * The `getEntityRecord`, `getEntityRecords` and other selectors or resolvers when
   passed the `'root'` and `'media'` params (e.g. `getEntityRecords( 'root', 'media');`).
 * The `editEntityRecord`, `saveEntityRecord`, `deleteEntityRecord` and other actions
   when passed the `'root'` and `'media'` params (e.g. `deleteEntityRecord( 'root','
   media', 123)`).

These 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. calls will continue to work in WordPress 6.9, but will now log a deprecation
message that recommends switching to a different signature.

#### Why is this being deprecated?

The `media` entity was found to be duplicating another entity, `attachment`. This
attachment entity is usually accessed through API calls like `getEntityRecords( '
postType', 'attachment' );`. These two entities both internally use the `media` 
REST APIREST API The REST API is an acronym for the RESTful Application Program 
Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is
how the front end of an application (think “phone app” or “website”) can communicate
with the data store (think “database” or “file system”) [https://developer.wordpress.org/rest-api/](https://developer.wordpress.org/rest-api/)
endpoint and return results for `attachment` post types.

The entity system maintains a cache of REST API data, and the two separate entity
types result in two separate caches that might contain different states for the 
same data. If the caches become desynchonized, this can result in noticeable bugs
where a user interface might show outdated data, or old data overwrites newer data
when saved.

Various solutions for fixing this issue were explored, but the option that was found
to be safest was to deprecate the media entity in favor of the attachment entity.

#### How to update your code to use the `attachment` entity

##### Replacing API calls

The following code snippet shows some examples of how to update your API calls:

    ```notranslate
    wp.data.select( 'core' ).getMedia( 123 ); // now deprecated
    wp.data.select( 'core' ).getEntityRecord( 'root', 'media', 123 ); // now deprecated
    wp.data.select( 'core' ).getEntityRecord( 'postType', 'attachment', 123 ); // recommended update

    wp.data.select( 'core' ).getMediaItems(); // now deprecated
    wp.data.select( 'core' ).getEntityRecords( 'root', 'media' ); // now deprecated
    wp.data.select( 'core' ).getEntityRecords( 'postType', 'attachment' ); // recommended update

    wp.data.dispatch( 'core' ).saveMedia( 123, { // ... media data } ); // now deprecated
    wp.data.dispatch( 'core' ).saveEntityRecord( 'root', 'media', 123, { // ... media data } ); // now deprecated
    wp.data.dispatch( 'core' ).saveEntityRecord( 'postType', 'attachment', 123,  { // ... media data } ); // recommended update

    wp.data.dispatch( 'core' ).deleteMedia( 123 ); // now deprecated
    wp.data.dispatch( 'core' ).deleteEntityRecord( 'root', 'media', 123 ); // now deprecated
    wp.data.dispatch( 'core' ).deleteEntityRecord( 'postType', 'attachment', 123 ); // recommended update
    ```

##### Changes to the `caption` property when using the `getEditedEntityRecord` selector

When making an API call for the ‘edited’ version of an entity record (e.g. `getEditedEntityRecord('
root', 'media', 123 )`), the core data package converts the `caption` property to
a string:

    ```wp-block-code
    caption: "My image's caption"
    ```

The attachment entity doesn’t perform the same processing, an API call like `getEditedEntityRecord('
postType', 'attachment', 123 )` returns the `caption` in its object form:

    ```notranslate
    caption: {
        raw: "My image's caption",
        rendered: "My image's caption"
    }
    ```

The `caption.raw` property corresponds to the string value that the `media` entity
returns for the `caption`.

When switching to the ‘attachment’ entity, some code may need to be updated to account
for this difference.

### Block Editor: Support passing updater function to `setAttributes`

Starting from WordPress 6.9, the `setAttribute` prop passed to a block’s `Edit` 
component will now support an updater function as an argument.

The updater is a pure function; it takes only the current attributes as its argument
and returns the updated attributes.

    ```notranslate
    // Toggle a setting when the user clicks the button.
    const toggleSetting = () =>
    	setAttributes( ( currentAttr ) => ( {
    		mySetting: ! currentAttr.mySetting,
    	} ) );

    // Append item to the list.
    const addListItem = ( newListItem ) =>
    	setAttributes( ( currentAttr ) => ( {
    		list: [ ...currentAttr.list, newListItem ],
    	} ) );
    ```

### `SelectControl`: Moved class names to the component root

The `SelectControl` component’s class assignments have been adjusted for better 
consistency with other form components, such as `TextControl`. Both the default 
class name (`components-select-control`) and any custom class name passed via the`
className` prop are now applied to the root element of the component, rather than
to the internal element.

While this update does not alter the component’s behavior or visual design, custom
CSSCSS Cascading Style Sheets. that previously depended on the inner structure may
need to be updated.

Before:

    ```notranslate
    <div class="components-base-control">
      <div class="components-base-control__field">
        <div class="components-flex components-input-base components-select-control my-custom-classname">
          <div class="components-flex-item">
            <label class="components-truncate components-text components-input-control__label">Label</label>
          </div>
          <div class="components-input-control__container">
            <select class="components-select-control__input"></select>
            <div aria-hidden="true" class="components-input-control__backdrop"></div>
          </div>
        </div>
      </div>
    </div>
    ```

After:

    ```notranslate
    <div class="components-base-control components-select-control my-custom-classname">
      <div class="components-base-control__field">
        <div class="components-flex components-input-base">
          <div class="components-flex-item">
            <label class="components-truncate components-text components-input-control__label">Label</label>
          </div>
          <div class="components-input-control__container">
            <select class="components-select-control__input"></select>
            <div aria-hidden="true" class="components-input-control__backdrop"></div>
          </div>
        </div>
      </div>
    </div>
    ```

### Registering custom social icons

WordPress 6.9 adds support for registering custom social icons to the Social Icons
block. With this update, developers can create plugins to define new services and
SVGs, and expose them to both the editor and frontend through block variations and
PHPPHP The web scripting language in which WordPress is primarily architected. WordPress
requires PHP 7.4 or higher filters. For styling, matching brand colors can be handled
in CSS and loaded for both views.[](https://developer.wordpress.org/news/2025/08/registering-custom-social-icons-in-wordpress-6-9/)​

Example for Ko-fi variation:

    ```notranslate
    registerBlockVariation('core/social-link', {
    	name: 'kofi',
    	title: 'Ko-fi',
    	icon: (
    		<SVG role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
    			<Path d="M11.351 2.715c-2.7 0-4.986.025-6.83.26C2.078 3.285 0 5.154 0 8.61c0 3.506.182 6.13 1.585 8.493 1.584 2.701 4.233 4.182 7.662 4.182h.83c4.209 0 6.494-2.234 7.637-4a9.5 9.5 0 0 0 1.091-2.338C21.792 14.688 24 12.22 24 9.208v-.415c0-3.247-2.13-5.507-5.792-5.87-1.558-.156-2.65-.208-6.857-.208m0 1.947c4.208 0 5.09.052 6.571.182 2.624.311 4.13 1.584 4.13 4v.39c0 2.156-1.792 3.844-3.87 3.844h-.935l-.156.649c-.208 1.013-.597 1.818-1.039 2.546-.909 1.428-2.545 3.064-5.922 3.064h-.805c-2.571 0-4.831-.883-6.078-3.195-1.09-2-1.298-4.155-1.298-7.506 0-2.181.857-3.402 3.012-3.714 1.533-.233 3.559-.26 6.39-.26m6.547 2.287c-.416 0-.65.234-.65.546v2.935c0 .311.234.545.65.545 1.324 0 2.051-.754 2.051-2s-.727-2.026-2.052-2.026m-10.39.182c-1.818 0-3.013 1.48-3.013 3.142 0 1.533.858 2.857 1.949 3.897.727.701 1.87 1.429 2.649 1.896a1.47 1.47 0 0 0 1.507 0c.78-.467 1.922-1.195 2.623-1.896 1.117-1.039 1.974-2.364 1.974-3.897 0-1.662-1.247-3.142-3.039-3.142-1.065 0-1.792.545-2.338 1.298-.493-.753-1.246-1.298-2.312-1.298"/>
    		</SVG>
    	),
    	attributes: {
    		service: 'kofi',
    	},
    	isActive: ['service']
    });
    ```

Filters and CSS support synchronization with the frontend output. For more comprehensive
references and setup routines, see [this Developer Blog post](https://developer.wordpress.org/news/2025/08/registering-custom-social-icons-in-wordpress-6-9/).
[](https://make.wordpress.org/core/?p=120014&preview=1&_ppp=b3321a59e1)​

---

Props to content authors [@bernhard-reiter](https://profiles.wordpress.org/bernhard-reiter/),
[@greenshady](https://profiles.wordpress.org/greenshady/), [@mamaduka](https://profiles.wordpress.org/mamaduka/),
[@talldanwp](https://profiles.wordpress.org/talldanwp/), [@wildworks](https://profiles.wordpress.org/wildworks/)

6-9, [#dev-notes](https://make.wordpress.org/core/tag/dev-notes/), [#dev-notes-6-9](https://make.wordpress.org/core/tag/dev-notes-6-9/)

[#6-9](https://make.wordpress.org/core/tag/6-9/)

 [  ](https://profiles.wordpress.org/dmsnell/) [Dennis Snell](https://profiles.wordpress.org/dmsnell/)
5:08 pm _on_ November 21, 2025     
Tags: [6-9 ( 87 )](https://make.wordpress.org/core/tag/6-9/),
[dev-notes ( 621 )](https://make.wordpress.org/core/tag/dev-notes/), dev-notes-6-
9, [html-api ( 6 )](https://make.wordpress.org/core/tag/html-api/)   

# 󠀁[Updates to the HTML API in 6.9](https://make.wordpress.org/core/2025/11/21/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](https://core.trac.wordpress.org/ticket/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:

    ```php
    $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 builders^([1](https://make.wordpress.org/core/tag/dev-notes-6-9/?output_format=md#5810a71a-cd37-4821-86e7-4354e6977819))”
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:

    ```php
    // 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](https://www.javascript.com/)󠁿 `.dataset` properties.

HTML provides a convenient mechanism tying HTML and JavaScript together through 
the [custom data attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/data-*)
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](https://software.hixie.ch/utilities/js/live-dom-viewer/?%3Cspan%20data-order%3D%22Carrots%20please!%22%3EWhat%20should%20we%20order%3F%3C%2Fspan%3E%0A%3Cscript%3E%0Adocument.body.addEventListener(%20%27click%27%2C%20event%20%3D%3E%20alert(%20event.target.dataset.order%20)%20)%3B%0A%3C%2Fscript%3E)
object in JavaScript through the `.dataset` property:

    ```language-markup
    <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:

    ```php
    // 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.

    ```php
    $this->assertEqualHTML(
      "<img src='puppy&period;jpg'   loading=lazy>",
      '<img loading="l&#97zy"src="puppy.jpg"/>'
    );
    ```

    ```wp-block-code
     ✔︎ 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.

    ```php
    $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/>'
    );
    ```

    ```wp-block-code
     ✘ 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](https://sirre.al/2025/08/06/safe-json-in-script-tags-how-not-to-break-a-site/)(
   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](https://core.trac.wordpress.org/ticket/61501),
   [PR#9953](https://github.com/WordPress/wordpress-develop/pull/9953)]
 * The `WP_UnitTestClass` now contains an `assertEqualHTML()` method which determines
   if two strings represent the same normative HTML. [[#63527](https://core.trac.wordpress.org/ticket/63527),
   [PR#8882](https://github.com/WordPress/wordpress-develop/pull/8882)]
 * Multiple length checks are safely skipped when processing SCRIPT content due 
   to an early minimum-length check. [[#63738](https://core.trac.wordpress.org/ticket/63738),
   [PR#9230](https://github.com/WordPress/wordpress-develop/pull/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](https://core.trac.wordpress.org/ticket/63738), [PR#9231](https://github.com/WordPress/wordpress-develop/pull/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](https://core.trac.wordpress.org/ticket/63823), [PR#9456](https://github.com/WordPress/wordpress-develop/pull/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](https://core.trac.wordpress.org/ticket/63854),
   [PR#9545](https://github.com/WordPress/wordpress-develop/pull/9545)]
 * `set_modifiable_text()` rejects additional contents inside a SCRIPT element when
   the contents could disturb its normal closing. [[#63738](https://core.trac.wordpress.org/ticket/63738),
   [PR#9560](https://github.com/WordPress/wordpress-develop/pull/9560)]

### Bug Fixes

 * Attempting to avoid the [HTTP _Referer_ problem](https://en.wikipedia.org/wiki/HTTP_referer#Etymology),
   quirks mode is referred to as `indicated_compatibility_mode`. [[#63391](https://core.trac.wordpress.org/ticket/63391),
   [PR#9401](https://github.com/WordPress/wordpress-develop/pull/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](https://core.trac.wordpress.org/ticket/63630), [PR#9099](https://github.com/WordPress/wordpress-develop/pull/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](https://core.trac.wordpress.org/ticket/63738), [PR#9397](https://github.com/WordPress/wordpress-develop/pull/9397)]
 * `wp_kses()` now allows some previously-missing HTML5 semantic tags and their 
   attributes. [[#63786](https://core.trac.wordpress.org/ticket/63786), [PR#9379](https://github.com/WordPress/wordpress-develop/pull/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](https://core.trac.wordpress.org/ticket/64054),
   [PR#10143](https://github.com/WordPress/wordpress-develop/pull/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](https://core.trac.wordpress.org/ticket/59622), [#63694](https://core.trac.wordpress.org/ticket/63694),
   [PR#5486](https://github.com/WordPress/wordpress-develop/pull/5486), [PR#9251](https://github.com/WordPress/wordpress-develop/pull/9251),
   [PR#9255](https://github.com/WordPress/wordpress-develop/pull/9255), [PR#9257](https://github.com/WordPress/wordpress-develop/pull/9257),
   [PR#9258](https://github.com/WordPress/wordpress-develop/pull/9258), [PR#9259](https://github.com/WordPress/wordpress-develop/pull/9259),
   [PR#9264](https://github.com/WordPress/wordpress-develop/pull/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](https://core.trac.wordpress.org/ticket/63694),
   [PR#9272](https://github.com/WordPress/wordpress-develop/pull/9272)]
 * Processing for image blocks in classic themes is now performed via the HTML API
   rather than with PCREs. [[#63694](https://core.trac.wordpress.org/ticket/63694),
   [PR#10218](https://github.com/WordPress/wordpress-develop/pull/10218)]

## Acknowledgements

Props to [@jonsurrell](https://profiles.wordpress.org/jonsurrell/) and [@westonruter](https://profiles.wordpress.org/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. [↩︎](https://make.wordpress.org/core/tag/dev-notes-6-9/?output_format=md#5810a71a-cd37-4821-86e7-4354e6977819-link)

[#6-9](https://make.wordpress.org/core/tag/6-9/), [#dev-notes](https://make.wordpress.org/core/tag/dev-notes/),
[#dev-notes-6-9](https://make.wordpress.org/core/tag/dev-notes-6-9/), [#html-api](https://make.wordpress.org/core/tag/html-api/)

 [  ](https://profiles.wordpress.org/johnbillion/) [John Blackbourn](https://profiles.wordpress.org/johnbillion/)
3:38 pm _on_ November 21, 2025     
Tags: [6-9 ( 87 )](https://make.wordpress.org/core/tag/6-9/),
[dev-notes ( 621 )](https://make.wordpress.org/core/tag/dev-notes/), dev-notes-6-
9, [php-compatibility ( 5 )](https://make.wordpress.org/core/tag/php-compatibility/)

# 󠀁[PHP 8.5 support in WordPress 6.9](https://make.wordpress.org/core/2025/11/21/php-8-5-support-in-wordpress-6-9/)󠁿

[PHP 8.5 was released on November 20th](https://www.php.net/archive/2025.php#2025-11-20-3).
Contributors to WordPress have been busy in recent months preparing for this version
and we’re happy to report that all issues reported against PHPPHP The web scripting
language in which WordPress is primarily architected. WordPress requires PHP 7.4
or higher 8.5 have been addressed in WordPress 6.9 RC2. Compared to previous PHP
releases relatively few changes were required, mostly to address new deprecations
and warnings. Take a look at [the PHP 8.5 support tracking ticket](https://core.trac.wordpress.org/ticket/63061)
if you’re interested.

> Due to the acknowledgement that WordPress is rarely used in isolation (without
> any theme or plugins), support is labelled as “betaBeta A pre-release of software
> that is given out to a large group of users to trial under real conditions. Beta
> versions have gone through alpha testing in-house and are generally fairly close
> in look, feel and function to the final product; however, design changes often
> occur as part of the process. support” until at least 10% of all WordPress sites
> are running that version or later, as this indicates good compatibility across
> the wider ecosystem of plugins and themes.
> _[PHP Compatibility and WordPress Versions page in the WordPress Core Handbook](https://make.wordpress.org/core/handbook/references/php-compatibility-and-wordpress-versions/)_

Following the established guidelines, support for any given version of PHP is labelled
as “beta support” until at least 10% of all WordPress sites are running that version
or later. When WordPress 6.9 ships on December 2nd, support for PHP 8.5 and 8.4 
will be labelled as “beta support”. PHP versions 8.3 back to 7.2 are fully supported.

If you discover a 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. or compatibility issue while running WordPress with 
PHP 8.5, [please create a ticket on Trac](https://core.trac.wordpress.org/newticket?keywords=php85).

## Summary

As always, reading through the [complete upgrade document](https://github.com/php/php-src/blob/PHP-8.5/UPGRADING)
is recommended.

Even as WordPress CoreCore Core is the set of software required to run WordPress.
The Core Development Team builds WordPress. continues to expand its support for 
new versions of PHP, support for older versions will remain as-is in WordPress 6.9,
staying at PHP 7.2.24 and higher. This will continue to be evaluated and no change
will be made until usage numbers show that the impact on users will be minimal.

**WordPress continues to encourage all users to run the latest and greatest versions
of PHP, including PHP 8.5.**

_Props [@desrosj](https://profiles.wordpress.org/desrosj/), [@jorbin](https://profiles.wordpress.org/jorbin/)
for reviewing this post._

[#6-9](https://make.wordpress.org/core/tag/6-9/), [#dev-notes](https://make.wordpress.org/core/tag/dev-notes/),
[#dev-notes-6-9](https://make.wordpress.org/core/tag/dev-notes-6-9/), [#php-compatibility](https://make.wordpress.org/core/tag/php-compatibility/)

 [  ](https://profiles.wordpress.org/joedolson/) [Joe Dolson](https://profiles.wordpress.org/joedolson/)
9:10 pm _on_ November 19, 2025     
Tags: [6-9 ( 87 )](https://make.wordpress.org/core/tag/6-9/),
[accessibility ( 58 )](https://make.wordpress.org/core/tag/accessibility/), [dev-notes ( 621 )](https://make.wordpress.org/core/tag/dev-notes/),
dev-notes-6-9   

# 󠀁[Accessibility Improvements in WordPress 6.9](https://make.wordpress.org/core/2025/11/19/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/](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](https://core.trac.wordpress.org/ticket/47101) – Improve accessibility
   when deleting terms via AJAX: color contrast & spoken message.
 * [#48655](https://core.trac.wordpress.org/ticket/48655) – Improve the “Add-item”
   function in menus (esp. for pages)
 * [#63118](https://core.trac.wordpress.org/ticket/63118) – Hide “Skip to Toolbar”
   shortcut on small screens within adminadmin (and super admin)
 * [#63126](https://core.trac.wordpress.org/ticket/63126) – Theme preview model 
   and Media library model having issues with Shift/Ctrl + Shift next and previous
   arrows.
 * [#63449](https://core.trac.wordpress.org/ticket/63449) – Low color contrast for
   <code> elements in description text on Settings > General page
 * [#63546](https://core.trac.wordpress.org/ticket/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/](https://wordpress.org/plugins/)
   or can be cost-based plugin from a third-party.-editor.php
 * [#63603](https://core.trac.wordpress.org/ticket/63603) – Replace deprecated /
   non-standard CSS for `speak` and `aural`
 * [#63723](https://core.trac.wordpress.org/ticket/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](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](https://core.trac.wordpress.org/ticket/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](https://core.trac.wordpress.org/ticket/47579) – Customizer “Select logo”
   and “Select site icon” look like drop areas, but are buttons.
 * [#50696](https://core.trac.wordpress.org/ticket/50696) – UIUI User interface &
   Accessibility issues in customizer menus section
 * [#63011](https://core.trac.wordpress.org/ticket/63011) – Customizer: The back
   button is not keyboard focusable
 * [#63832](https://core.trac.wordpress.org/ticket/63832) – Loss of focus when setting
   or changing the Site Logo or Site Icon in Customizer

### Editing

 * [#63460](https://core.trac.wordpress.org/ticket/63460) – Increase color contrast
   for embed template
 * [#61959](https://core.trac.wordpress.org/ticket/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](https://core.trac.wordpress.org/ticket/63281) – Password field has wrong
   focus on installations
 * [#63286](https://core.trac.wordpress.org/ticket/63286) – User profile first name,
   last name, nickname and email fields should have autocomplete attributes for 
   accessibility
 * [#48345](https://core.trac.wordpress.org/ticket/48345) – Add Caps lock message
   to login screen

### Media

 * [#63114](https://core.trac.wordpress.org/ticket/63114) – No screen reader announcements
   for upload image errors
 * [#63238](https://core.trac.wordpress.org/ticket/63238) – Remove `target=”_blank”`
   from Browser Uploader Link
 * [#63239](https://core.trac.wordpress.org/ticket/63239) – Button focus visibility
   issue in media upload page
 * [#63571](https://core.trac.wordpress.org/ticket/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](https://core.trac.wordpress.org/ticket/63973) – Add Media Button missing
   aria-haspopup and aria-controls

### Miscellaneous

 * [#40428](https://core.trac.wordpress.org/ticket/40428) – Introduce best practices
   to hide CSS generated content from assistive technologies
 * [#44267](https://core.trac.wordpress.org/ticket/44267) – Privacy Request List
   Table: A way to show the time of request when it’s older than 24 hours.
 * [#63030](https://core.trac.wordpress.org/ticket/63030) – Update CSS for `::-moz-
   placeholder` color
 * [#63620](https://core.trac.wordpress.org/ticket/63620) – Remove translator comments
   when hidden text matches visible text
 * [#63950](https://core.trac.wordpress.org/ticket/63950) – Tabbing through database
   upgrade screen shows “WordPress” text over logo

### Bundled Themes

 * [#10219](https://core.trac.wordpress.org/ticket/10219) – “Older Entries” and “
   Newer Entries” links are wrong when entries displayed in ascending order
 * [#44656](https://core.trac.wordpress.org/ticket/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](https://core.trac.wordpress.org/ticket/52116) – Twenty Twenty: Menu 
   + Search can cause a scroll jump on close
 * [#63875](https://core.trac.wordpress.org/ticket/63875) – Twenty Twenty-Two and
   Twenty Twenty-Five: <pre> tag overflows container, causing horizontal scroll

### Widgets

 * [#63531](https://core.trac.wordpress.org/ticket/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/](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](https://github.com/WordPress/gutenberg/pull/68662) – Cover: Fix placeholder
   color options keyboard accessibility
 * [#68909](https://github.com/WordPress/gutenberg/pull/68909) – Site Title: Fix
   logic for ‘aria-current’ attribute
 * [#69628](https://github.com/WordPress/gutenberg/pull/69628) – Site Title: Prevent
   saving and rendering a value made of only spaces
 * [#69689](https://github.com/WordPress/gutenberg/pull/69689) – Navigation Link,
   Navigation Submenu: Remove the title attribute controls
 * [#69821](https://github.com/WordPress/gutenberg/pull/69821) – Social Icons: Remove
   custom placeholder state
 * [#69837](https://github.com/WordPress/gutenberg/pull/69837) – Navigation block:
   fix submenu Escape key behavior
 * [#70139](https://github.com/WordPress/gutenberg/pull/70139) – Button Block: Add
   HTML Element selection in Advanced settings
 * [#70192](https://github.com/WordPress/gutenberg/pull/70192) – Button: Avoid focus
   loss when unlinking using keyboard
 * [#70210](https://github.com/WordPress/gutenberg/pull/70210)  – Columns block:
   Don’t use ToolsPanelItem for Columns setting
 * [#70730](https://github.com/WordPress/gutenberg/pull/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](https://github.com/WordPress/gutenberg/pull/64119) – Add Accordions 
   Block
 * [#73177](https://github.com/WordPress/gutenberg/pull/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](https://github.com/WordPress/gutenberg/pull/67792) – Improve the EntitiesSavedStates
   modal dialog design and labeling
 * [#69011](https://github.com/WordPress/gutenberg/pull/69011) – Remove non translatable
   additional info from font size picker visual label and improve labeling
 * [#69441](https://github.com/WordPress/gutenberg/pull/69441) – ARIA: Fix invalid`
   DropdownMenu` children structure
 * [#68633](https://github.com/WordPress/gutenberg/pull/68633) – Global Styles: 
   Prevent Unwanted ItemGroup List Rendering in Border Panel
 * [#68542](https://github.com/WordPress/gutenberg/pull/68542) – Button: Update 
   hover styles to account for pressed state for `tertiary button`
 * [#69609](https://github.com/WordPress/gutenberg/pull/69609) – ActionModal: Add
   support for customisable `focusOnMount`
 * [#69904](https://github.com/WordPress/gutenberg/pull/69904) – Add new HTMLElementControl
   component
 * [#70591](https://github.com/WordPress/gutenberg/pull/70591) – `FormTokenField`:
   Fix focus lost on tab when `__experimentalExpandOnFocus` is set
 * [#70096](https://github.com/WordPress/gutenberg/pull/70096) – Components: Fix
   label and placeholder handling in `LinkControlSearchInput`
 * [#70660](https://github.com/WordPress/gutenberg/pull/70660) – Autocomplete: Prevent
   text cursor position loss when clicking to insert an item
 * [#70146](https://github.com/WordPress/gutenberg/pull/70146) – Color Picker: Improve
   color picker slider focus styles

### Data Views

 * [#67874](https://github.com/WordPress/gutenberg/pull/67874) – Display Checkbox
   by default in dataviews
 * [#69876](https://github.com/WordPress/gutenberg/pull/69876) – DataViews: Always
   show primary action for list layout if hover isn’t supported
 * [#71561](https://github.com/WordPress/gutenberg/pull/71561) – DataViews: Custom`
   empty` elements are no longer wrapped in `<p>` tags to improve accessibility
 * [#72417](https://github.com/WordPress/gutenberg/pull/72417) – DataViews: Use 
   Text-Based Links for Primary Actions
 * [#72501](https://github.com/WordPress/gutenberg/pull/72501) – Dataviews: Make
   bulk actions text based.

### Editor

 * [#68481](https://github.com/WordPress/gutenberg/pull/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](https://github.com/WordPress/gutenberg/pull/68975) – Close patterns 
   modal on insertion and focus on inserted pattern
 * [#69305](https://github.com/WordPress/gutenberg/pull/69305) – Swap fullscreen
   mode snackbar notice message.
 * [#69334](https://github.com/WordPress/gutenberg/pull/69334) – InputControl: Ensure
   consistent placeholder color
 * [#69378](https://github.com/WordPress/gutenberg/pull/69378) – Button: Remove 
   fixed width from small and compact buttons with icons
 * [#69451](https://github.com/WordPress/gutenberg/pull/69451) – Editor: Refactor
   the ‘PostVisibility’ component
 * [#69520](https://github.com/WordPress/gutenberg/pull/69520) – Fix shift+tab from
   post title
 * [#69724](https://github.com/WordPress/gutenberg/pull/69724) – Post Template Panel:
   Preserve parent modal when closing template creation dialog
 * [#68631](https://github.com/WordPress/gutenberg/pull/68631) – Global Styles: 
   Fix incorrect usage of ItemGroup in the Background image panel
 * [#69813](https://github.com/WordPress/gutenberg/pull/69813) – Background Image
   Panel: fix focus loss
 * [#70128](https://github.com/WordPress/gutenberg/pull/70128) – Global Styles: 
   Move `Randomize colors` button to Edit Palette panel
 * [#70133](https://github.com/WordPress/gutenberg/pull/70133) – Editor: Add label
   in`TextareaControl` in CollabSidebar
 * [#69278](https://github.com/WordPress/gutenberg/pull/69278) – Toolbar: Adjust
   colors for dark mode support
 * [#70451](https://github.com/WordPress/gutenberg/pull/70451)  – feat: clarify 
   label & add help text with link for Link Rel

### Miscellaneous

 * [#69440](https://github.com/WordPress/gutenberg/pull/69440) – Make password protected
   input fields consistent.
 * [#70091](https://github.com/WordPress/gutenberg/pull/70091) – Templates: Add 
   back button & fix focus loss when navigating through template creation flow

## Acknowledgements

Props to [@jorbin](https://profiles.wordpress.org/jorbin/) and [@jeffpaul](https://profiles.wordpress.org/jeffpaul/)
for reviewing this post.

[#6-9](https://make.wordpress.org/core/tag/6-9/), [#accessibility](https://make.wordpress.org/core/tag/accessibility/),
[#dev-notes](https://make.wordpress.org/core/tag/dev-notes/), [#dev-notes-6-9](https://make.wordpress.org/core/tag/dev-notes-6-9/)

 [  ](https://profiles.wordpress.org/joedolson/) [Joe Dolson](https://profiles.wordpress.org/joedolson/)
9:10 pm _on_ November 19, 2025     
Tags: [6-9 ( 87 )](https://make.wordpress.org/core/tag/6-9/),
[dev-notes ( 621 )](https://make.wordpress.org/core/tag/dev-notes/), dev-notes-6-
9   

# 󠀁[Admin menu search query changed](https://make.wordpress.org/core/2025/11/19/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](https://codex.wordpress.org/Database_Description#Table:_wp_posts).

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](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.

    ```php
    /**
     * 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:

    ```php
    /**
     * 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](https://core.trac.wordpress.org/ticket/48655).

## Acknowledgements

Props to [@jorbin](https://profiles.wordpress.org/jorbin/) for reviewing this post.

[#6-9](https://make.wordpress.org/core/tag/6-9/), [#dev-notes](https://make.wordpress.org/core/tag/dev-notes/),
[#dev-notes-6-9](https://make.wordpress.org/core/tag/dev-notes-6-9/)

 [  ](https://profiles.wordpress.org/joedolson/) [Joe Dolson](https://profiles.wordpress.org/joedolson/)
9:10 pm _on_ November 19, 2025     
Tags: [6-9 ( 87 )](https://make.wordpress.org/core/tag/6-9/),
[dev-notes ( 621 )](https://make.wordpress.org/core/tag/dev-notes/), dev-notes-6-
9   

# 󠀁[Legacy Internet Explorer Code Removed](https://make.wordpress.org/core/2025/11/19/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](https://make.wordpress.org/core/2021/04/22/ie-11-support-phase-out-plan/),
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](https://core.trac.wordpress.org/ticket/16024),
and for styles sometime around version 2.6.0, but was made [more easily available in WordPress 3.6](https://core.trac.wordpress.org/ticket/18753).

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.](https://core.trac.wordpress.org/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](https://core.trac.wordpress.org/ticket/58836).

## IE Compatibility Removals

Compatibility scripts were [removed from the Media Elements instantiation process in #63471](https://core.trac.wordpress.org/ticket/63471).

[#62128](https://core.trac.wordpress.org/ticket/62128) removed IE-specific hacks
and EOT file rules from the Genericons stylesheet [for four bundled themes, from Twenty Thirteen to Twenty Sixteen](https://core.trac.wordpress.org/ticket/62128).

## Acknowledgements

Props to [@jorbin](https://profiles.wordpress.org/jorbin/), [@westonruter](https://profiles.wordpress.org/westonruter/),
[@jonsurrell](https://profiles.wordpress.org/jonsurrell/) and [@sabernhardt](https://profiles.wordpress.org/sabernhardt/)
for reviewing this post.

[#6-9](https://make.wordpress.org/core/tag/6-9/), [#dev-notes](https://make.wordpress.org/core/tag/dev-notes/),
[#dev-notes-6-9](https://make.wordpress.org/core/tag/dev-notes-6-9/)

 [  ](https://profiles.wordpress.org/dmsnell/) [Dennis Snell](https://profiles.wordpress.org/dmsnell/)
6:11 pm _on_ November 19, 2025     
Tags: [6-9 ( 87 )](https://make.wordpress.org/core/tag/6-9/),
[block-api ( 5 )](https://make.wordpress.org/core/tag/block-api/), [dev-notes ( 621 )](https://make.wordpress.org/core/tag/dev-notes/),
dev-notes-6-9   

# 󠀁[Introducing the streaming block parser in WordPress 6.9](https://make.wordpress.org/core/2025/11/19/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.

 [Continue reading →](https://make.wordpress.org/core/2025/11/19/introducing-the-streaming-block-parser-in-wordpress-6-9/#more-119384)

[#6-9](https://make.wordpress.org/core/tag/6-9/), [#block-api](https://make.wordpress.org/core/tag/block-api/),
[#dev-notes](https://make.wordpress.org/core/tag/dev-notes/), [#dev-notes-6-9](https://make.wordpress.org/core/tag/dev-notes-6-9/)

 [  ](https://profiles.wordpress.org/sabernhardt/) [Stephen Bernhardt](https://profiles.wordpress.org/sabernhardt/)
4:05 pm _on_ November 19, 2025     
Tags: [6-9 ( 87 )](https://make.wordpress.org/core/tag/6-9/),
[dev-notes ( 621 )](https://make.wordpress.org/core/tag/dev-notes/), dev-notes-6-
9   

# 󠀁[URL-escaping functions can support HTTPS as the default protocol in WordPress 6.9](https://make.wordpress.org/core/2025/11/19/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.

    ```notranslate
    <?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:

    ```notranslate
    <?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](https://core.trac.wordpress.org/ticket/52886).

---

Props to [@desrosj](https://profiles.wordpress.org/desrosj/) for co-authoring the
note, writing the code examples and expanding on details. Props to [@jorbin](https://profiles.wordpress.org/jorbin/)
for review.

[#6-9](https://make.wordpress.org/core/tag/6-9/), [#dev-notes](https://make.wordpress.org/core/tag/dev-notes/),
[#dev-notes-6-9](https://make.wordpress.org/core/tag/dev-notes-6-9/)

# Post navigation

[← Older posts](https://make.wordpress.org/core/tag/dev-notes-6-9/page/2/?output_format=md)