WordPress 6.7 introduces many exciting features, but one subtle enhancement worth noting is the stabilization of content-only editing, now ready for use by extenders and block developers.
Although content-only editing was first introduced in WordPress 6.1, supporting this mode in custom blocks previously required an experimental property in block.json
. Combined with the absence of an editor interface for applying content-only mode, it has remained one of the more overlooked and underutilized features of the block editor. But that might be changing soon.
So, if this is the first you’ve heard about content-only editing, don’t worry—you are not alone.
In this article, I’ll explain what content-only editing is, why it’s important to support it in your blocks, and how to implement it using a practical example.
Table of Contents
What is content-only editing?
Content-only editing was added to WordPress two years ago as an additional locking mechanism designed to reduce the need to create custom blocks for layouts that could alternatively be built using block patterns.
The main advantage of using a custom block is that it gives you complete control over what users can edit, such as restricting them to only editing text, images, and other content elements. This simplifies the editing experience for users while maintaining a consistent layout and enforcing design standards.
Content-only editing provides similar functionality to all blocks natively.
You enable it by adding templateLock: contentOnly
to a container block, like Group, Column, and Cover. Once active, users can only edit specific elements of the nested content. Blocks without editable content are hidden from the List View and cannot be selected. Additionally, the Settings Sidebar for all blocks is disabled.
While often applied to blocks and patterns, you can also use content-only editing to lock entire page templates. For more information, refer to the Block Templates documentation.
To demonstrate how this works, consider the following block layout, which features a Group block containing a Heading, Paragraph, and Social Icons block. Block styles and settings have been applied, and this example uses the Twenty Twenty-Five theme coming in WordPress 6.7.
In WordPress’s default editing mode, users can change anything they want about this design. Here’s the block markup for reference.
<!-- wp:group {"style":{"spacing":{"padding":{"top":"var:preset|spacing|50","bottom":"var:preset|spacing|50","left":"var:preset|spacing|50","right":"var:preset|spacing|50"},"margin":{"top":"var:preset|spacing|70","bottom":"var:preset|spacing|70"}}},"backgroundColor":"accent-5","layout":{"type":"constrained"}} -->
<div class="wp-block-group has-accent-5-background-color has-background" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--70);padding-top:var(--wp--preset--spacing--50);padding-right:var(--wp--preset--spacing--50);padding-bottom:var(--wp--preset--spacing--50);padding-left:var(--wp--preset--spacing--50)">
<!-- wp:heading -->
<h2 class="wp-block-heading">Speaker Name</h2>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>Speaker Description—Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus luctus urna sed urna ultricies ac tempor dui sagittis.</p>
<!-- /wp:paragraph -->
<!-- wp:social-links {"iconColor":"accent-5","iconColorValue":"#FBFAF3","iconBackgroundColor":"contrast","iconBackgroundColorValue":"#111111","showLabels":true,"size":"has-normal-icon-size","style":{"spacing":{"margin":{"top":"var:preset|spacing|50"}}}} -->
<ul class="wp-block-social-links has-normal-icon-size has-visible-labels has-icon-color has-icon-background-color" style="margin-top:var(--wp--preset--spacing--50)">
<!-- wp:social-link {"url":"#","service":"wordpress"} /-->
<!-- wp:social-link {"url":"#","service":"chain"} /-->
<!-- wp:social-link {"url":"#","service":"mail"} /-->
</ul>
<!-- /wp:social-links -->
</div>
<!-- /wp:group -->
Now, let’s apply the "templateLock": "contentOnly"
attribute to the block markup of the Group block. You only need to modify the attribute object. The rest of the block markup should remain the same.
<!-- wp:group {"templateLock": "contentOnly","style":{"spacing":{"padding":{"top":"var:preset|spacing|50","bottom":"var:preset|spacing|50","left":"var:preset|spacing|50","right":"var:preset|spacing|50"}}},"backgroundColor":"accent-5","layout":{"type":"constrained"}} -->
To follow along, open a WordPress Playground instance running WordPress 6.7. Here’s a handy link.
- Navigate to a new page.
- Open the Code Editor, and copy and paste the original block markup above.
- Add the
"templateLock": "contentOnly"
attribute to the Group block. - Switch back to the Visual Editor.
With those steps completed, you should see something like this.
If you compare the block layout in content-only mode to the default editing experience, you will quickly notice a few things:
- The List View is simplified and only displays the container (Group) and any internal blocks with editable content.
- The Settings Sidebar no longer displays block settings or styles, only the block style variations that are available to the container Group block.
- There is a new Content panel in the Settings Sidebar displaying the editable content blocks within the container.
- The icons in the Social Icons block are no longer editable. (Note this for later in the article)
Why support this editing mode?
Content-only editing is a powerful tool for creating curated and simplified user experiences. To make this feature effective, blocks must be designed to support it. For instance, as noted earlier, the Social Icons block currently does not function in this mode.
While future WordPress updates will address full support across core blocks, most sites include at least one custom block. For block developers, ensuring compatibility with content-only editing is essential. Prior to WordPress 6.7, enabling this feature in custom blocks required an experimental property in block.json
called __experimentalRole
. Now that the role
property has been stabilized, adding support is generally straightforward.
You still might wonder why content-only editing is so important, especially since it has remained relatively niche until now. The answer lies in the new Write mode in Gutenberg and the increased emphasis on content-only editing outlined in the Design Editor Overview issue on GitHub.
These developments underline the future importance of content-only editing and its role in creating a simpler, more controlled editing experience within WordPress’s broader design tools. It’s time to get your blocks ready.
How to add content-only support to a block
Although I initially planned to create an example block plugin for this article, let’s instead examine the Social Link block in WordPress since it’s currently disabled in content-only mode as of WordPress 6.7. You can view the source code in the Gutenberg plugin.
The Social Link block is a child of the Social Icons (Social Links) block, which displays a row or column of icons that link to social profiles or websites. In many cases, you might want users to be able to modify link URLs in content-only mode. This is especially useful when a block layout is provided as a pattern that can be used in different contexts, such as the speaker profile block design shown earlier.
Here’s a quick demonstration of how these blocks work. Notice how toggling Show text displays a label for each icon.
For the remainder of this article, I will refer to the blocks by their technical names as used in the WordPress source code and block markup: wp:social-links
and wp:social-link
. Just remember that the Social Links block appears as the Social Icons block in the Editor, while the Social Link block is represented by the individual platform names such as WordPress, Facebook, LinkedIn, Link, Mail, etc.
So, let’s assume that the Social Link block is your custom block that needs content-only editing support. How do you go about implementing this?
Updating block.json
The first step is to update the block.json
file of the Social Link block by adding the "role": "content"
property to each attribute that should be editable when "templateLock": "contentOnly"
is set.
For this example, the url
and label
attributes should be available. The url
attribute holds the link for the social icon, while the label
attribute represents an optional text label for the icon when Show text is enabled in the parent Social Links block.
The updated attributes section of the block.json
file should look like this:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "core/social-link",
"title": "Social Icon",
"category": "widgets",
"parent": [ "core/social-links" ],
"description": "Display an icon linking to a social profile or site.",
"textdomain": "default",
"attributes": {
"url": {
"type": "string",
"role": "content"
},
"service": {
"type": "string"
},
"label": {
"type": "string",
"role": "content"
},
"rel": {
"type": "string"
}
},
...
If you are adding content-only editing to your own block and need to support older versions of WordPress, use __experimentalRole
instead of role
until you are ready to set the minimum WordPress version to 6.7. The only downside to this approach is a minor deprecation warning in the console.
With these changes, URL editing for social icons will be enabled automatically. This works because the url
attribute is managed using the <SocialLinkURLPopover>
component, which is part of the Editor canvas when the block is inserted. A block’s canvas elements become editable when at least one attribute is assigned the "role": "content"
property.
You can see this demonstrated below.
The label
attribute, on the other hand, is normally set using the Text field in the Settings Sidebar. The sidebar is disabled in content-only mode.
If you want a block attribute that is typically set in the sidebar to be editable in content-only mode, you need to create an alternative editing experience within the block.
A great way to approach this is by taking inspiration from existing WordPress blocks. For example, the Image block allows users to edit the image’s alt text using an Alternative text dropdown in the block toolbar (source code).
Let’s apply a similar approach to the Social Link block.
Adding a custom editing experience
To begin, add a button to the block toolbar of the Social Link block by including content within a <BlockControls>
component. For this, let’s follow the approach used in the Image block and implement a <Dropdown>
component.
The following code should be placed within the return
statement of the block’s Edit()
function.
return (
<>
<BlockControls group="other">
<Dropdown
popoverProps={ { position: 'bottom right' } }
renderToggle={ ( { isOpen, onToggle } ) => (
<ToolbarButton
onClick={ onToggle }
aria-haspopup="true"
aria-expanded={ isOpen }
>
{ __( 'Text' ) }
</ToolbarButton>
) }
renderContent={ () => (
<TextControl
className="wp-block-social-link__toolbar_content_text"
label={ __( 'Text' ) }
help={ __( 'Provide a text label or use the default.' ) }
value={ label }
onChange={ ( value ) => setAttributes( { label: value } ) }
placeholder={ socialLinkName }
/>
) }
/>
</BlockControls>
<InspectorControls>
...
The <Dropdown>
component includes two key properties: renderToggle
and renderContent
.
The renderToggle
property is responsible for displaying the component that triggers the dropdown. In this case, a <ToolbarButton>
is used since it’s designed to integrate seamlessly within block toolbars.
The renderContent
property specifies what is displayed when the dropdown opens. In this example, it contains a <TextControl>
component used to set the label
attribute. This <TextControl>
is similar to the text input found in the block’s Settings Sidebar.
There are a few other details to note:
- The
<BlockControls>
component includes thegroup="other"
property, which ensures the Text button is positioned correctly within the toolbar. - The position of the dropdown is managed through the
popoverProps
property. - The
<TextControl>
component is assigned a custom class for styling purposes.
Once the code for the toolbar dropdown is added, the block will look like this.
You may have noticed two issues right away. First, the width of the dropdown needs to be fixed using CSS. Second, the Text button should not always be visible in the toolbar.
When the block is not in content-only mode, users can already modify the label
attribute from the Settings Sidebar. Additionally, if Show text is not enabled on the parent Social Links block, the button should not be displayed, regardless of the editing mode.
Applying the finishing touches
Let’s start with the easiest one. The dropdown width can be set by targeting the custom class added to the <TextControl>
component. The following CSS should be added to the block’s editor.scss
file.
.wp-block-social-link__toolbar_content_text {
// Corresponds to the size of the text control input in the block inspector.
width: 250px;
}
Next, you need to conditionally display the toolbar button based on the current editing mode and whether Show text is enabled.
The Social Link block already receives the showLabels
value from the context provided by its parent, the Social Links block (source code). The editing mode can be determined using the useBlockEditingMode
function.
Start by importing useBlockEditingMode
from the @wordpress/block-editor
package and defining the following constant in the block’s Edit()
function:
const isContentOnlyMode = useBlockEditingMode() === 'contentOnly';
Now, wrap the <BlockControls>
component created earlier in a conditional statement that checks for both isContentOnlyMode
and showLabels
.
return (
<>
{ isContentOnlyMode && showLabels && (
<BlockControls group="other">
...
</BlockControls>
) }
<InspectorControls>
...
The Text button in the toolbar will now display properly. When the Social Link block is in contentOnly
mode, and Show text is enabled, users will be able to set both the icon link and the text label.
Here’s a demonstration of the finished product.
You can find the full code for this example in the pull request that introduces content-only editing support for the Social Link block in the Gutenberg plugin. This functionality is expected to be included with WordPress 6.8 in early 2025.
Overall, the changes needed for the Social Link block were relatively minor. However, the modifications your custom blocks need will depend on their complexity and the amount of editing control you want to give users.
Closing thoughts
If you build custom blocks, consider whether some could be replaced with block patterns locked with content-only editing. If not, ensure your blocks support this mode. Although content-only editing is still somewhat niche, WordPress is expected to expand its use, and site builders using your blocks will come to expect it.
This is similar to adding official block supports so that your block’s styles and settings can be managed through theme.json
and modified in Global Styles. Aligning your custom solutions with core functionality makes them more adaptable and robust.
As you explore content-only editing, feel free to share any questions or challenges you encounter during implementation in the comments.
Props to @greenshady, @fabiankaegy, and @get_dave for feedback and review on this post.
Leave a Reply