Pattern Overrides in WP 7.0: Support for Custom Blocks

As of WordPress 7.0, any 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. attribute that supports Block Bindings also supports Pattern Overrides. So now, you can use Pattern Overrides for any block you want โ€” even custom blocks โ€” the previous limit to a hardcoded set of CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. blocks no longer holds you back. To get started, opt in through the server-side block_bindings_supported_attributes filter(s).

The underlying Block Bindings mechanism will make sure that:

  • In dynamic blocks, the correct, bound attribute values will be passed to render_callback().
  • In static blocks, 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. is used to locate attributes sourced from html, rich-text, or attribute sources via their selectors in the persisted markup, replacing their values with the respective bound attribute values.

Bound attribute values should appear correctly in the rendered blocksโ€™ markup in these cases. You shouldnโ€™t need any other modifications.

For static blocks with unsourced attributes, or with sourced attributes whose selectors are more complex than the HTML API currently understands, you might need to add a render_callback() or a render_block 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. to make sure bound attribute values are correctly handled. Itโ€™s best if you first try without (i.e. by only adding the attribute via block_bindings_supported_attributes filter). Then, if the bound attribute value doesnโ€™t render, add the callback or the filter that guarantees the render.


Props to @fabiankaegy and @marybaum for reviewing this dev notedev 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.!

#7-0, #dev-notes, #dev-notes-7-0

Pattern Editing in WordPress 7.0

WordPress 7.0 expandsย contentOnlyย editing to unsynced patterns and template parts.

The key behavioral change is that unsynced patterns and template parts inserted into the editor now default toย contentOnlyย mode, prioritizing the editing of text and media without exposing the deeper 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 or style controls.

Pattern-level editing modes

At times a user will want to make design changes to a pattern, and this works differently depending on the type of pattern.

  • Unsynced โ€” A user can click an โ€˜Edit patternโ€™ button or double click the body of a pattern, and a spotlight mode engages. In this mode users have full editing capabilitiescapability 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)..
  • Synced (synced patterns / template parts) โ€” Users can click the โ€˜Edit originalโ€™ button and are taken into an isolated editor when they can make any changes to the underlying pattern. The editor 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. provides navigation back to the originating document. Changes to synced patterns apply globally.

What developers need to do

Block authors

If your block is nested in aย contentOnlyย pattern and should be editable, ensure attributes that represent a blockโ€™s content haveย "role": "content"ย set inย block.json. This is unchanged from WordPress 6.7, but is now more important asย contentOnlyย mode is applied more broadly by default.

{
  "attributes": {
    "url": {
      "type": "string",
      "role": "content"
    },
    "label": {
      "type": "string",
      "role": "content"
    }
  }
}

Blocks without anyย "role": "content"ย attributes will be hidden from List View and non-selectable inside aย contentOnlyย container.

At times a block may not have an appropriate attribute to which to applyย "role": "content". Aย "contentRole": trueย property can be added to the block supports declaration, and this has the same effect asย "role": "content".

{
  "supports": {
    "contentRole": true
  }
}

Developers should preferย "role": "content"ย where possible.

Parent / child contentOnly blocks

Many blocks are considered โ€˜contentโ€™, but consist of both parent and child block types. Some examples of CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. blocks are:

  • List and List Item
  • Gallery and Image
  • Buttons and Button

Whenever both a parent and child block have aย "role": "content"ย attribute orย "contentRole": trueย block supports,ย contentOnlyย mode allows insertion of child blocks. This behavior has been present since WordPress 6.9, but is now more prominent.

Block developers can take advantage of this behavior.

List View block support

New for WordPress 7.0, block developers can add aย "listView": trueย block supports declaration. This adds a List View tab to the block inspector with a dedicated List View UIUI User interface for the block that allows users to easily rearrange and add inner blocks. This List View is also displayed in Patterns and is recommended for any block that acts as a container for a list of child blocks.

{
  "supports": {
    "listView": true
  }
}

Theme / pattern authors

Patterns that previously relied on unrestricted editing of their inner blocks will now be presented to users inย contentOnlyย mode by default. Review your registered patterns and consider:

  1. Testing that the content users are expected to change is accessible inย contentOnlyย mode.
  2. Auditing patterns containing Buttons, List, Social Icons, and Navigation blocks specifically โ€” these have had targetedย contentOnlyย improvements and may behave differently than before.
  3. Restrict the allowed blocks if users shouldnโ€™t be able to insert blocks in a specific area of a pattern. If assembling a pattern in a block editor, this can be done using the โ€˜Manage allowed blocksโ€™ feature in the Advanced section of the block inspector for any blocks that haveย "allowedBlocks": trueย block support. Through code, theย "allowedBlocks":[]ย attribute can be added to prevent insertion of inner blocks.

Site admins

A new block editor setting,ย disableContentOnlyForUnsyncedPatterns, allows opting out ofย contentOnlyย mode for unsynced patterns. Via PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher, use theย block_editor_settings_allย 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.:

add_filter( 'block_editor_settings_all', function( $settings ) {
    $settings['disableContentOnlyForUnsyncedPatterns'] = true;
    return $settings;
} );

Or via 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:

wp.data.dispatch( 'core/block-editor' ).updateSettings( {
    disableContentOnlyForUnsyncedPatterns: true,
} );

Whenย disableContentOnlyForUnsyncedPatternsย isย true, blocks withย patternNameย metadata are no longer treated as section blocks and their children are not placed intoย contentOnlyย editing mode. Template parts and synced patterns (core/block) are unaffected โ€” they remain section blocks regardless of this setting.

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. developers

If your plugin interacts with pattern editing state โ€” toolbar controls, 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. panels, List View visibility, or entity navigation โ€” test against the new editing modes. Theย contentOnlyย state is now applied more broadly, and UI components that assume full block access inside patterns may not render as expected.

Props to @talldanwpย and @andrewserong for helping to write this dev notedev 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..


References

#7-0, #dev-notes, #dev-notes-7-0

Block Visibility in WordPress 7.0

As of WordPress 6.9, you can hide any 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. entirely withย blockVisibility: falseย in block metadata. In WordPress 7.0, viewport-based visibility rules give your users the power to show or hide blocks per device type โ€” desktop, tablet, or mobile โ€” without affecting other viewports.

โ€œHideโ€ and โ€œShowโ€ controls are available in the block toolbar, the List View, and command palette to launch the block visibility options modal. In List View, blocks with active visibility rules show icons that indicate which viewports they are hidden on.

Note: Blocks hidden by viewport areย rendered in the DOM.ย The hiding happens in the CSSCSS Cascading Style Sheets..

Thatโ€™s different fromย blockVisibility: false. That keeps the block from rendering in the DOM, thus it canโ€™t ever show on the front end.

Updatedย blockVisibilityย metadata structure

The existing hide-everywhere behavior has NOT changed:

{
  "metadata": {
    "blockVisibility": false
  }
}

But in WordPress 7.0, a newย viewportย key gives you and your 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.-literate users finer control, per breakpoint:

{
  "metadata": {
    "blockVisibility": {
      "viewport": {
        "mobile": false,
        "tablet": true,
        "desktop": true
      }
    }
  }
}

Theย viewportย key is deliberately nested, leaving room for more sources (e.g., user role, time-based rules) to come in 7.1 and beyond.

The three supported viewport keys areย mobile,ย tablet, andย desktop. In 7.0 these map to fixed breakpoints, but you can expect configurable breakpoints andย theme.jsonย integration in WordPress 7.1 โ€” seeย #75707.

Hereโ€™s how this all looks in serialized block markup:

<!-- wp:paragraph {"metadata":{"blockVisibility":{"viewport":{"mobile":false}}}} -->
<p>Hidden on mobile.</p>
<!-- /wp:paragraph -->

How to get your theme or 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. ready

Does your theme or plugin generate, transform, or parse block markup server-side? Then itsย blockVisibilityย metadata field might now contain a boolean (false) or an object ({ viewport: { ... } }). If your code assumes a scalar value, youโ€™ll want to update it to handle both forms.

Blocks and patterns that include hardcodedย blockVisibilityย metadata will work out of the box, and so will your reusable blocks that have visibility rules.

If your blocks donโ€™t interact with markup on the server

Then you donโ€™t have to do anything! Viewport visibility is part of theย blockVisibilityย block support and applies automatically. You donโ€™t need a separate opt-in inย block.json.

Coming soon! To a future release near you

Current plans call for configurable breakpoints andย theme.jsonย integration for block visibility to land in WordPress 7.1. At that point, youโ€™ll be able to let your themes and other products define almost any viewport labels and breakpoints you need, far beyond the fixed mobile/tablet/desktop defaults. Followย #75707ย for progress.

Props to @andrewserong and @marybaum for helping to write this dev notedev 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..


References

#7-0, #dev-notes, #dev-notes-7-0

Dimensions Support Enhancements in WordPress 7.0

WordPress 7.0 expands the Dimensions 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. supports system with three significant improvements: width and height are now available as standard block supports under dimensions, and themes can now define dimension size presets to give users a consistent set of size options across their site.


Background

Previously, blocks that needed width or height controls implemented them as custom block attributes with their own editor UIUI User interface. This led to duplicated code, inconsistent experiences across blocks, and no straightforward way to define width or height values through Global Styles or theme.json. The broader 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. goal is to handle these concerns uniformly through block supports, the same system that already covers spacing, typography, color, and more.


Width Block Support

PR: #71905

dimensions.width is now a first-class block support. Block authors can opt in by adding "width": true under the dimensions key in block.json:

{
    "supports": {
        "dimensions": {
            "width": true
        }
    }
}

Once opted in, the block gains a width input in the Dimensions panel of the block inspector and in the Styles panel of the Site Editor (under Styles > Blocks > Block Name). Theme authors can define default width values for specific block types via theme.json:

{
    "styles": {
        "blocks": {
            "core/paragraph": {
                "dimensions": {
                    "width": "300px"
                }
            }
        }
    }
}

Block-level values set in the editor will override the theme defaults, following the same cascade as other block supports.

Themes can also disable the width control globally using the settings API:

{
    "settings": {
        "dimensions": {
            "width": false
        }
    }
}

The width support respects the full range of block support configuration options:

{
    "supports": {
        "dimensions": {
            "width": true,
            "__experimentalSkipSerialization": true,
            "__experimentalDefaultControls": {
                "width": false
            }
        }
    }
}

Height Block Support

PR: #71914

dimensions.height follows the same pattern as width. Block authors opt in via block.json:

{
    "supports": {
        "dimensions": {
            "height": true
        }
    }
}

Theme authors can set default height values per block in theme.json:

{
    "styles": {
        "blocks": {
            "core/paragraph": {
                "dimensions": {
                    "height": "300px"
                }
            }
        }
    }
}

And the support can be disabled theme-wide:

{
    "settings": {
        "dimensions": {
            "height": false
        }
    }
}

Like the width support, height respects __experimentalSkipSerialization and __experimentalDefaultControls.


Dimension Size Presets

PR: #73811

Alongside the new width and height supports, themes can now define a set of named dimension size presets via theme.json. These presets appear in the width and height controls, giving users a consistent palette of sizes to choose from rather than requiring manual entry of values each time.

Define presets under settings.dimensions.dimensionSizes:

{
    "settings": {
        "dimensions": {
            "dimensionSizes": [
                {
                    "name": "Small",
                    "slug": "small",
                    "size": "240px"
                },
                {
                    "name": "Medium",
                    "slug": "medium",
                    "size": "480px"
                },
                {
                    "name": "Large",
                    "slug": "large",
                    "size": "720px"
                }
            ]
        }
    }
}

Each preset requires three fields:

FieldDescription
nameHuman-readable label shown in the UI
slugMachine-readable identifier (used to generate a CSSCSS Cascading Style Sheets. custom property)
sizeAny valid CSS length value (px, %, em, rem, vw, vh, etc.)

The presets generate CSS custom properties following the --wp--preset--dimension-size--{slug} naming convention, consistent with other theme.json presets.

Control rendering: The number of presets defined affects how the control is rendered:

  • Fewer than 8 presets: A slider control is shown, allowing users to step through the preset values.
  • 8 or more presets: A select list (dropdown) is shown instead to keep the UI manageable.

In both cases, users can still enter a custom value directly.


Backwards Compatibility

These are additive changes. No existing blocks are broken. Blocks that do not opt in to dimensions.width or dimensions.height in their block.json are unaffected.

Blocks that currently implement custom width or height controls as attributes are encouraged to evaluate migrating to the new block supports, but this is not required in WordPress 7.0.

The dimensionSizes preset key is new; themes without it simply have no presets defined, which is the default behavior โ€” users can still enter free-form values in the width and height controls.


Summary

Featureblock.json keytheme.json settings keytheme.json styles key
Width block supportsupports.dimensions.widthsettings.dimensions.widthstyles.blocks.{name}.dimensions.width
Height block supportsupports.dimensions.heightsettings.dimensions.heightstyles.blocks.{name}.dimensions.height
Dimension size presetsโ€”settings.dimensions.dimensionSizesโ€”

Further Reading


Props to @aaronrobertshaw and @ryanwelcher for the width and height block support implementations, @aaronrobertshaw for dimension presets, and @andrewserong and @ramonopoly for technical review and proofreading.

#7-0, #dev-notes, #dev-notes-7-0

Custom CSS for Individual Block Instances in WordPress 7.0

WordPress 7.0 introduces the ability to add custom CSSCSS Cascading Style Sheets. directly to individual 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. instances from within the post and site editors. This closes a long-standing gap in the block styling system: while Global Styles has supported block-type-level custom CSS since WordPress 6.2, there was no built-in way to target a single specific block on a specific page without a multi-step workaround.

GitHubGitHub GitHub is a website that offers online implementation of git repositories that can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the โ€˜pull requestโ€™ where code changes done in branches by contributors can be reviewed and discussed before being merged by the repository owner. https://github.com/ issue: #56127 | PR: #73959

The Problem

Previously, applying one-off CSS to a specific block instance required a workaround: add a custom class name to the block, then write a matching rule in the Site Editorโ€™s global Custom CSS field. This two-step process was not obvious to most users, and was entirely unavailable to content editors who lack access to the Site Editor.

Plugins emerged to fill this gap, confirming genuine demand for the feature.

What Changed

A new customCSS block support is registered. It provides a Custom CSS input inside the Advanced panel of the block inspector โ€” the same panel that already contains the โ€œAdditional CSS Class(es)โ€ field.

The panel behaves the same way as the block-type custom CSS field in Global Styles:

  • Only CSS declarations are needed โ€” no selector is required.
  • Nested selectors can be written using & (e.g., & a { color: red; } targets anchor tags inside the block).
  • HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. markup in the CSS field is rejected.
  • The field is only visible to users with the edit_css 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)..

How It Works

Storage

Custom CSS is stored in the blockโ€™s existing style attribute, under the css key โ€” the same attribute that stores other block-level style overrides:

<!-- wp:heading {"level":6,"style":{"css":"color: blue;\n"}} -->
<h6 class="wp-block-heading has-custom-css">Heading</h6>
<!-- /wp:heading -->

Frontend Output

At render time, a unique class is generated for the block instance using a hash of the blockโ€™s content and attributes. The class is applied to the blockโ€™s outermost HTML element alongside a has-custom-css marker class:

<h6 class="wp-block-heading has-custom-css wp-custom-css-8841bf3c3cc97689d62771455cc88782">
    Heading
</h6>

<style id="wp-block-custom-css">
    :root :where(.wp-custom-css-8841bf3c3cc97689d62771455cc88782) {
        color: blue;
    }
</style>

The generated stylesheet is registered with a dependency on global-styles, ensuring block instance CSS loads after โ€” and can therefore override โ€” both WordPress defaults and Global Styles block-type CSS.

Editor Preview

The custom CSS is also applied live in the editor using a scoped style override, so changes are reflected immediately without saving.

Opt-Out

The customCSS support is enabled by default for all blocks. Block authors who need to opt out โ€” for example, blocks that render raw content or have no meaningful outer element โ€” can disable it in block.json:

{
    "supports": {
        "customCSS": false
    }
}

The following coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. blocks opt out by default: core/freeform, core/html, core/missing, core/more, core/nextpage, core/shortcode, and core/block (the Reusable Block wrapper).

Capability Check

The Custom CSS panel is gated by the edit_css capability. Users without it will not see the field in the block inspector. This is the same capability used to control access to the Custom CSS field in the 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. and in Global Styles.

For 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. and Theme Developers

No action is required for most blocks and themes. The support is enabled automatically.

If you maintain a block that should not expose a custom CSS input โ€” because it wraps raw or opaque content, or because adding a class to its root element would break its rendering โ€” add "customCSS": false to your blockโ€™s supports in block.json.

If you render blocks server-side using render_callback or render in block.json, the class will be injected into the first HTML element in the rendered output via WP_HTML_Tag_Processor. Ensure your block renders a standard HTML element as its outermost 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.).

Further Reading

Props to @mtias and @glendaviesnz for the implementation, @aaronrobertshaw and @scruffian for technical review and proofreading.

#7-0, #dev-notes, #dev-notes-7-0

New Block Support: Text Indent (textIndent)

WordPress 7.0 introduces a new textIndent 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. support for typography, allowing blocks to opt in to text-indent CSSCSS Cascading Style Sheets. support. The Paragraph block is the first coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. block to adopt this support.

Background

Text indentation is a standard typographic convention, particularly in long-form publishing. It has been one of the most-requested typography features for WordPress blocks since 2021 (#37462).

With this release, WordPress now supports it natively through a new block support. No custom CSS required.

The textIndent Block Support

Any block can now declare support for textIndent in its block.json:

{
  "supports": {
    "typography": {
      "textIndent": true
    }
  }
}

When a block declares this support, the block editor will show a Line Indent control in the Typography panel of the block 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., and the blockโ€™s style.typography.textIndent attribute will be serialised as a text-indent CSS property.

This follows the same pattern as other typography block supports such as letterSpacing, textDecoration, and textTransform.

Paragraph Block: Selector Behaviour and the textIndent Setting

The textIndent support has a unique consideration specific to the core Paragraph block: in traditional typographic conventions of English and some other left-to-right (LTR) languages, only subsequent paragraphs (those that follow another paragraph) are typically indented, while the very first paragraph in a sequence is not. In some right-to-left (RTL) languages and publishing traditions, such as Arabic and Hebrew, however, it is common to indent all paragraphs.

To accommodate both conventions, a typography.textIndent setting controls which CSS selector is used when generating the text-indent rule. This setting is distinct from the style value (the actual indent amount) and applies at the Global Styles level.

Setting valueSelector usedBehaviour
"subsequent" (default).wp-block-paragraph + .wp-block-paragraphOnly paragraphs immediately following another paragraph are indented
"all".wp-block-paragraphAll paragraphs are indented

Note: This selector behaviour is specific to core/paragraph. Third-party blocks that opt in to textIndent support will have text-indent applied using their own block selector, but the subsequent/all switching logic is not currently available to them.

In Global Styles, an โ€œIndent all paragraphsโ€ toggle lets authors switch between the two modes interactively.

Configuring via theme.json

Themes can enable and configure Line Indent support through theme.json.

Enable the control with default (subsequent) behaviour:

{
  "settings": {
    "typography": {
      "textIndent": true
    }
  }
}

Enable with all-paragraphs mode:

{
  "settings": {
    "typography": {
      "textIndent": "all"
    }
  }
}

Set a default indent value globally for paragraphs:

{
  "settings": {
    "typography": {
      "textIndent": "subsequent"
    }
  },
  "styles": {
    "blocks": {
      "core/paragraph": {
        "typography": {
          "textIndent": "1.5em"
        }
      }
    }
  }
}

Backward Compatibility

This is a new opt-in feature. No existing block behaviour changes unless a block explicitly declares "textIndent": true in its supports.typography definition. There are no breaking changes to existing APIs.

Further Reading

  • GitHubGitHub GitHub is a website that offers online implementation of git repositories that can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the โ€˜pull requestโ€™ where code changes done in branches by contributors can be reviewed and discussed before being merged by the repository owner. https://github.com/ issue: #37462
  • Implementing PR: #74889

Props @aaronrobertshaw for development. Props @wildworks, @andrewserong, and @ramonopoly for technical reviews and proofreading.

#7-0, #dev-notes, #dev-notes-7-0

Real-Time Collaboration in the Block Editor

Real-time collaboration (RTC) in 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 allows multiple users to edit content simultaneously by utilizing Yjs.

This dev notedev 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. covers three important aspects of the collaboration system that 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. and theme developers should be aware of:

  • How 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. boxes affect collaboration mode
  • The sync.providers 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. for customized sync transport
  • Common issues when building plugins that can run in a collaborative environment

Collaboration is disabled when meta boxes are present

The Problem

Classic WordPress meta boxes are not synced by the real-time collaboration system. To avoid data loss, collaboration is disabled when meta boxes are detected on a post.

Locked post modal when someone takes over a post
Locked post modal when trying to take over a post

What developers need to know

To allow collaboration, consider migrating meta box functionality to registered post meta with show_in_rest set to true, and use 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. plugins or block-based alternatives that read from WordPress data stores.

For example:

register_post_meta( 'post', 'example_subtitle', [
	'show_in_rest' => true, // Required for syncing.  
	'single' => true,  
	'type' => 'string',
	'revisions_enabled' => true, // Recommended to track via revision history.
] );

For more details on migrating from meta boxes, see the Meta Boxes guide in the Block Editor Handbook.


The sync.providers filter: Customizing the sync transport layer

Overview

The @wordpress/sync package uses a provider-based architecture for syncing collaborative editing data. By default, WordPress ships with an HTTPHTTP HTTP is an acronym for Hyper Text Transfer Protocol. HTTP is the underlying protocol used by the World Wide Web and this protocol defines how messages are formatted and transmitted, and what actions Web servers and browsers should take in response to various commands. polling provider. The sync.providers filter allows plugins to replace or extend the transport layer. For example, a plugin could switch from HTTP polling to WebSockets for lower-latency collaboration.


How it works

The filter is applied during provider initialization:

const filteredProviderCreators = applyFilters(
'sync.providers',
getDefaultProviderCreators() // array of provider creators
);

A provider creator is a function that accepts a ProviderCreatorOptions object (containing the Yjs ydoc, awareness, objectType, and objectId) and returns a ProviderCreatorResult with destroy and on methods. The destroy method is called when the provider is no longer needed, and the on method allows the editor to listen for connection status events (connecting, connected, disconnected).


Example: WebSocket provider

The following example replaces the default HTTP polling provider with a WebSocket-based transport using the y-websocket library:

import { addFilter } from '@wordpress/hooks';
import { WebsocketProvider } from 'y-websocket';

/**
 * Create a WebSocket provider that connects a Yjs document
 * to a WebSocket server for real-time syncing.
 */
function createWebSocketProvider( { awareness, objectType, objectId, ydoc } ) {
	const roomName = `${ objectType }-${ objectId ?? 'collection' }`;
	const serverUrl = 'wss://example.com/';

	const provider = new WebsocketProvider(
		serverUrl,
		roomName,
		ydoc,
		{ awareness }
	);

	return {
		destroy: () => {
			provider.destroy();
		},
		on: ( eventName, callback ) => {
			provider.on( eventName, callback );
		},
	};
}

addFilter( 'sync.providers', 'my-plugin/websocket-provider', () => {
	return [ createWebSocketProvider ];
} );


What developers need to know

  • The sync.providers filter is only applied when real-time collaboration is enabled.
  • Return an empty array to disable collaboration entirely.
  • Return a custom array to replace the default HTTP polling provider with your own transport (e.g., WebSockets, WebRTC).

Common issues when building plugins compatible with real-time collaboration

When real-time collaboration is active, all connected editors share the same underlying data state via Yjs. Plugins that interact with post data, especially custom post meta, need to follow certain patterns to avoid sync issues

Syncing custom post meta values

In addition to being registered, custom meta field UIUI User interface must be consumed from the WordPress data store and passed to controlled input components.
Always derive the input value directly from the WordPress data store via useSelect. In addition, use value instead of defaultValue on input components so the input always reflects the current data store state.

const metaValue = useSelect(
	select => select( 'core/editor' ).getEditedPostAttribute( 'meta' )?.example_subtitle,
	[]
);

<input
	value={ metaValue || '' }
	onChange={ event => {
		editPost( { meta: { example_subtitle: event.target.value } } );
	} }
/>

Avoiding local component state for shared data

When building a plugin UI that reads from the WordPress data store, avoid copying that data into local ReactReact React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces. https://reactjs.org state with useState. This applies to any shared data, such as post meta or block attributes. Doing so disconnects your component from the shared collaborative state: updates from other clients will update the store, but your component wonโ€™t reflect them after the initial render, leading to stale or conflicting data.

Blocks with side effects on insertion

Custom blocks that trigger side effects on insertion will trigger that side effect for all connected collaborators, since block content syncs immediately upon insertion.

For example, instead of auto-opening a modal when a block is inserted, show a placeholder with a button that opens the modal on click. This ensures side effects are intentional and local to the user taking the action.


Credits

Props @czarate, @alecgeatches, @maxschmeling, @paulkevan, and @shekharwagh for building real-time collaboration in the block editor alongside @ingeniumed, and for technical review and proofreading of this dev note.

Parts of this work are derived from contributions made by @dmonad inย this PR, and utilizes his Yjs library.

Props toย @wildworks and @tyxlaย for proofreading this dev note.

#dev-notes, #dev-notes-7-0, #7-0

Pseudo-element support for blocks and their variations in theme.json

WordPress 7.0 adds support for pseudo-class selectors (:hover, :focus, :focus-visible, and :active) directly on blocks and their style variations in theme.json. Previously, this was only possible for HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. elements like button and link under the styles.elements key. 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.-level interactive states could only be achieved through custom CSSCSS Cascading Style Sheets..

Variation-level pseudo-selectors

Block style variations can also define interactive states. This is particularly useful for variations like โ€œOutlineโ€ that have distinct visual styles requiring different hover behaviors:

{
    "styles": {
        "blocks": {
            "core/button": {
                "variations": {
                    "outline": {
                        "color": {
                            "background": "transparent",
                            "text": "currentColor"
                        },
                        ":hover": {
                            "color": {
                                "background": "currentColor",
                                "text": "white"
                            }
                        }
                    }
                }
            }
        }
    }
}

  • This is a theme.json-only 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.. There is no new UIUI User interface in Global Styles for these states in 7.0. Work on this is happening at #38277 and will be added in a future release.
  • The supported pseudo-selectors for core/button are: :hover, :focus, :focus-visible, and :active. Any others will be ignored.
  • Pseudo-selectors defined at the block level and at the variation level are independent โ€” you can define both without conflictconflict A conflict occurs when a patch changes code that was modified after the patch was created. These patches are considered stale, and will require a refresh of the changes before it can be applied, or the conflicts will need to be resolved..

See #64263 for more details

Props to @scruffian, @onemaggie for the implementation

Props to @mikachan, @scruffian for technical review and proofreading.

#7-0, #dev-notes, #dev-notes-7-0

Breadcrumb block filters

WordPress 7.0 introduces a new Breadcrumbs 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. that can be placed once โ€” such as in a themeโ€™s 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. โ€” and automatically reflects the siteโ€™s navigation hierarchy.

Breadcrumbs block in aย header template partย using Twenty Twenty-Five theme, here showing the trail for a child page

Two filters provide developers with control over the breadcrumb trail output.

block_core_breadcrumbs_items

This 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. allows developers to modify, add, or remove items from the final breadcrumb trail just before rendering. Each item is an array with three properties:

  1. label (string) โ€” the breadcrumb text.
  2. an optional url (string) โ€” the breadcrumb link URLURL A specific web address of a website or web page on the Internet, such as a websiteโ€™s URL www.wordpress.org.
  3. an optional allow_html (bool) โ€” whether to allow HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. in the label. When true, the label will be sanitized with wp_kses_post(), allowing only safe HTML tags. When false or omitted, all HTML will be escaped with esc_html().

Example: Prepend a custom breadcrumb item

  add_filter( 'block_core_breadcrumbs_items', function ( $breadcrumb_items ) {
        array_unshift( $breadcrumb_items, array(
                'label' => __( 'Shop', 'myplugin' ),
                'url'   => home_url( '/shop/' ),
        ) );

        return $breadcrumb_items;
  } );

block_core_breadcrumbs_post_type_settings

When a post type has multiple taxonomies or when a post is assigned to multiple terms within a taxonomyTaxonomy A taxonomy is a way to group things together. In WordPress, some common taxonomies are category, link, tag, or post format. https://codex.wordpress.org/Taxonomies#Default_Taxonomies., there could be numerous ways to construct the breadcrumbs trail. For example in a post that has both categories and tags a user might want to show in the breadcrumbs trail the categories (default), the tags and/or select a specific 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.).

This filter controls which taxonomy and terms appear in the Breadcrumbs block trail for posts that use taxonomy-based breadcrumbs. It applies to non-hierarchical post types (e.g., posts, products) or hierarchical post types when the blockโ€™s โ€œPrefer taxonomy termsโ€ setting is enabled (under advanced settings). It does not affect hierarchical ancestor-based trails (e.g., parent/child pages).

The filter receives three parameters:

  • $settings (array) โ€” an empty array by default. Callbacks should populate the array and return it with the following optional keys:
    • taxonomy (string) โ€” taxonomy slug to use for breadcrumbs.
    • term (string) โ€” term slug to prefer when the post has multiple terms in the selected taxonomy.
  • $post_type (string) โ€” the post type slug.
  • $post_id (int) โ€” the post ID, enabling per-post customization.

Fallback behavior

  • If the preferred taxonomy doesnโ€™t exist or has no terms assigned, fall back to the first available taxonomy with terms assigned.
  • If the preferred term doesnโ€™t exist or isnโ€™t assigned to the post, fall back to the first term
  • If the post has only one term, that term is used regardless of setting

Example 1: Set a preferred taxonomy and term per post type

add_filter( 'block_core_breadcrumbs_post_type_settings', function( $settings, $post_type ) {
	if ( $post_type === 'post' ) {
		$settings['taxonomy'] = 'category';
		$settings['term'] = 'news';
	}
	if ( $post_type === 'product' ) {
		$settings['taxonomy'] = 'product_tag';
	}
	return $settings;
}, 10, 2 );

Example 2: Choose a specific term per post

add_filter( 'block_core_breadcrumbs_post_type_settings', function ( $settings, $post_type, $post_id ) {
	if ( $post_type !== 'post' ) {
		return $settings;
	}
	
	$terms = get_the_terms( $post_id, 'category' );

	if ( $terms ) {
		$settings['taxonomy'] = 'category';
		$settings['term']     = end( $terms )->slug;
	}

	return $settings;
}, 10, 3 );

See 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/ pull requests: 74169, 73283, 74170.

Props to @karolmanijak, @ntsekouras for the implementation.

Props to @karolmanijak for technical review.

Props to @mcsf for copy review.

#dev-notes, #7-0

#dev-notes-7-0

Customizable Navigation Overlays in WordPress 7.0

WordPress 7.0 introduces Customizable Navigation Overlays, giving site owners full control over their mobile navigation menus using 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.

Previously, when a visitor tapped a hamburger menu icon on a mobile device, WordPress displayed a fixed default overlay with no support for customization. The design, layout, and content were locked.

Customizable Navigation Overlays remove this restriction entirely โ€” any overlay can now be built from blocks and patterns in the Site Editor. This includes a dedicatedย Navigation Overlay Closeย block for placing and styling a close button anywhere within the overlay.

How overlays work

Navigation overlays are implemented as template parts using a newย navigation-overlayย template part area, managed principally through the Navigation blockโ€™s overlay controls in the Site Editor. Because they are template parts, they can also be found and edited via theย Patternsย section in the Site Editor 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.. Each overlay is assigned to a Navigation block โ€” while the same overlay can be referenced by more than one, a one-to-one relationship is the most common pattern.

What goes inside an overlay is entirely up to the author. As a standard block canvas, it can contain any block โ€” navigation, social icons, a search field, a site logo, calls to actionโ€ฆor any combination! A Navigation block is the typical inclusion but is not a requirement. Because overlays only function correctly when rendered by a Navigation block, overlay template parts are intentionally excluded from the general block inserter โ€” this prevents them from being inserted accidentally into other parts of a template.

The feature is opt-in: by default, the Navigation block continues to use the standard overlay behaviour from previous versions of WordPress. A custom overlay can be activated in three ways:

  • Creating a new overlayย โ€” via theย Overlaysย section in the Navigation blockโ€™s sidebar controls in the Site Editor
  • Selecting an existing overlayย โ€” from the same controls, choosing from any overlays already created or bundled with the active theme
  • Theme pre-assignmentย โ€” a theme can reference a bundled overlay directly in the Navigation block markup (covered in the developer section below)

For theme developers: bundling overlays with your theme

Themes can ship pre-built navigation overlays so they are available as soon as the theme is activated. The recommended approach is to provide both a default overlay template part and a set of overlay patterns.

Template parts vs patterns

Understanding the distinction helps decide how to structure an overlay offering:

  • Aย template partย is the overlay itself โ€” the component that gets rendered when a Navigation block uses an overlay. Shipping a template part means a ready-to-use overlay is available from the moment the theme is activated.
  • Patternsย are design options that appear in theย Designย tab when editing a navigation overlay in the Site Editor. Selecting a pattern replaces the current overlay content with the patternโ€™s block markup, letting users switch between distinct designs.

A patterns-only approach is also valid โ€” useful when a theme wants to offer design options without pre-applying an overlay automatically. In this case, users create a new overlay via the Navigation blockโ€™s controls and pick from the themeโ€™s patterns as a starting point.

Updating your Theme

1. Register the template part inย theme.json

Registering the template part inย theme.jsonย is required. Without it, the template part is assigned theย uncategorizedย area and will not be recognized by the Navigation block as an overlay.

Add an entry to theย templatePartsย array, settingย areaย toย navigation-overlay:

{
    "templateParts": [
        {
            "area": "navigation-overlay",
            "name": "my-custom-overlay",
            "title": "My Custom Overlay"
        }
    ]
}

2. Create the template part file

Create the corresponding HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. file in the themeโ€™sย parts/ย directory. The filename should match theย nameย value fromย theme.json.

It is strongly recommended to include the Navigation Overlay Close block within the overlay. If it is omitted, WordPress will automatically insert a fallback close button on the frontend for 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 usability reasons โ€” but that button may not match the overlayโ€™s design or be positioned as expected. Including it explicitly gives full control over its appearance and placement.

<!-- parts/my-custom-overlay.html -->
<!-- wp:group {"layout":{"type":"flex","orientation":"vertical"}} -->
<div class="wp-block-group">
    <!-- wp:navigation-overlay-close /-->
    <!-- wp:navigation {"layout":{"type":"flex","orientation":"vertical"}} /-->
</div>
<!-- /wp:group -->

3. Register overlay patterns

Overlay patterns are registered usingย register_block_pattern(). Settingย blockTypesย toย core/template-part/navigation-overlayย scopes the pattern so it only appears when editing a navigation overlay template part โ€” not in the general inserter.

register_block_pattern(
    'my-theme/navigation-overlay-default',
    array(
        'title'      => __( 'Default Overlay', 'my-theme' ),
        'categories' => array( 'navigation' ),
        'blockTypes' => array( 'core/template-part/navigation-overlay' ),
        'content'    => '<!-- wp:group {"layout":{"type":"flex","orientation":"vertical"}} -->
<div class="wp-block-group">
    <!-- wp:navigation-overlay-close /-->
    <!-- wp:navigation {"layout":{"type":"flex","orientation":"vertical"}} /-->
</div>
<!-- /wp:group -->',
    )
);

4. Pre-configuring the Navigation block (optional)

A theme can optionally pre-configure a Navigation block to reference a specific overlay by setting theย overlayย attribute in the block markup. The value should be the template part slug only โ€” without a theme prefix:

<!-- wp:navigation {"overlay":"my-custom-overlay"} /-->

Using the slug only โ€” without a theme prefix โ€” is important for future compatibility: WordPress plans to allow template parts to persist across theme switches, and a theme-prefixed identifier would break that. This follows the same convention asย headerย andย footerย template parts.

Theย overlayย attribute is entirely optional โ€” users can select or change the overlay at any time using the Navigation blockโ€™s sidebar controls.

Known limitations

Template parts and theme switching

Navigation overlay template parts are currently tied to the active theme. Custom overlays will not be preserved if the active theme is switched. This is a known limitation tracked inย gutenberg#72452.

Overlays are full-screen only

In this initial release, navigation overlays are always rendered full-screen. Non-full-screen overlay styles (such as a sidebar drawer) are not yet supported. This requires implementing overlays as a trueย <dialog>ย element โ€” including support for clicking outside to close โ€” which is planned for a future release.

Not a generic popup or dialog

Navigation Overlays are intentionally scoped to the Navigation block and are not designed as a general-purpose popup or dialog implementation. For broader use cases โ€” such as modal dialogs triggered by arbitrary content โ€” a dedicated Dialog block is in development and tracked inย gutenberg#61297.

Questions and feedback

Until now, the mobile navigation overlay has been one of the few remaining areas of a block theme that couldnโ€™t be designed in the Site Editor. Navigation Overlays change that. An overlay can contain anything blocks can express โ€” a simple menu with a styled close button, a full-screen layout with the site logo and a call to action, or a content-rich experience that turns the mobile menu into a destination in its own right.

There is a lot of creative space here, and seeing what the community builds with it will be exciting.

Questions are welcome in the comments below.

Further reading


Props @onemaggie for implementation contributions and technical review, @mikachan, @jeryj @scruffian for proofreading, and @mmcalister, whoseย Ollie Menu Designerย 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. helped validate community demand for this functionality.

#7-0, #dev-notes, #dev-notes-7-0, #navigation