Since the introduction of “blocks” in WordPress, there have been calls for more control over how users manage and interact with this type of content. One common concern is that users might inadvertently delete or move blocks, destroying carefully crafted page layouts. Block locking goes a long way to alleviate this potential issue and curate the editing experience within WordPress.
In this article, we will explore the block locking API, how to implement locking in a real-world example, and discuss ways to extend this functionality by restricting who can lock and unlock blocks. Let’s get started!
Feel free to watch the video version of this article or continue reading.
Table of Contents
Background
Introduced in WordPress 5.9, the block locking API allows you to restrict the movement and removal of blocks in the Editor. Originally designed for use in templates, template parts, and patterns, you simply need to apply the lock
attribute to the markup of any block. This attribute has two options move
and remove
. When the options are set to true
, the block cannot be moved or removed respectively.
The complete markup on a Paragraph block would look something like this:
<!-- wp:paragraph {"lock":{"move":true,"remove":true}} -->
<p> ... </p>
<!-- /wp:paragraph -->
Code language: HTML, XML (xml)
This implementation was a big step forward, but there was no way to lock blocks from within the Editor unless you opened the Code Editor and modified the block markup directly. This restricted block locking to more advanced users such as developers and theme designers.
WordPress 6.0 enhanced this functionality by adding a simple user interface (UI) in the Editor. When opening the options menu on any block, you will now see the “Lock” option. Selecting this option will display a modal allowing you to configure lock settings for the current block. Once enabled, the lock
attribute is set and the block can no longer be moved or removed.
It’s important to note that by default, anyone with access to the Editor can both lock and unlock blocks. We will see how to restrict the locking UI to specific users later in this article.
More functionality is planned for WordPress 6.1, including the ability to lock all inner blocks at once, which is visible in the gif above. This feature is currently available for testing on Group, Column, and Cover blocks in the Gutenberg plugin.
Why Lock Blocks?
Editor Curation
There are many reasons to prevent the movement and removal of specific blocks, but the most common application is to restrict functionality for end users. In other words, curate the editing experience within WordPress.
When designing websites for clients or when a website has many editors, providing some guardrails to content creation and site management is often a prerequisite. An unrestricted Editor can complicate things, especially in maintaining brand guidelines, ensuring content consistency, and preventing inadvertent mistakes.
By allowing blocks to be locked, agencies and freelancers can now deliver predesigned patterns and templates to clients that, while editable, cannot be easily manipulated. Coupled with other curation techniques, block locking brings a degree of control back to the website builders and owners.
Personal Workflow
Not an agency or freelancer? Locking blocks can also help level up your personal workflow within WordPress.
Many applications such as Adobe Photoshop, Figma, and Sketch allow you to lock layers and assets. Locking prevents you from mistakenly moving or deleting content, especially when dealing with complex layouts.
The WordPress Editor can get equally complicated depending on the design with multiple layers of nested blocks. As you design a layout within the Editor, it’s often helpful to quickly lock blocks you’re happy with to avoid accidental edits. Give it a try!
Block Locking Example
While we have discussed the background of this functionality and why you might want to employ locking in your next project, let’s take a look at a real-world example.
In the following screenshot, we have the design for a testimonial block pattern. Notice that the layout is fairly complicated with multiple levels of nested blocks. We want users to be able to edit the testimonials but not break the design by moving or removing important blocks.
The pattern is primarily comprised of a Columns block with three columns. For each Column block, we have restricted removal, but not the movement. This allows the users to change the order of the testimonials but not delete them. The bock markup for this lock
attribute configuration looks like this:
<!-- wp:column {"lock":{"move":false,"remove":true}} -->
<div class="wp-block-column"> ... </div>
<!-- /wp:column -->
Code language: HTML, XML (xml)
Every other block inside of each Column block is fully locked. The complete block markup for this testimonials layout is presented below as a complete pattern. The locking attribute on each block has been highlighted.
patterns/testimonials.php
<?php
/**
* Title: Testimonials
* Slug: twentytwentytwo/testimonials
* Categories: columns
*/
?>
<!-- wp:group {"align":"wide","style":{"spacing":{"blockGap":"2rem"}},"layout":{"inherit":false}} -->
<div class="wp-block-group alignwide"><!-- wp:heading {"textAlign":"center","style":{"typography":{"fontStyle":"normal","fontWeight":"500"}},"fontSize":"x-large"} -->
<h2 class="has-text-align-center has-x-large-font-size" style="font-style:normal;font-weight:500"><?php echo esc_html( 'What Our Customers Are Saying', 'twentytwentytwo' ); ?></h2>
<!-- /wp:heading -->
<!-- wp:columns {"align":"wide","style":{"spacing":{"blockGap":"2rem","margin":{"top":"3rem"}}}} -->
<div class="wp-block-columns alignwide" style="margin-top:3rem"><!-- wp:column {<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-tiffany-color">"lock":{"move":false,"remove":true}</mark>,"style":{"spacing":{"padding":{"top":"2rem","right":"1.5rem","bottom":"2rem","left":"1rem"}}},"backgroundColor":"tertiary","className":"box-shadow\u002d\u002ddefault"} -->
<div class="wp-block-column box-shadow--default has-tertiary-background-color has-background" style="padding-top:2rem;padding-right:1.5rem;padding-bottom:2rem;padding-left:1rem"><!-- wp:quote {"lock":{"move":true,"remove":true},"className":"is-style-plain","fontSize":"small"} -->
<blockquote class="wp-block-quote is-style-plain has-small-font-size"><p><?php echo esc_html( 'Testimonial — Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus in tempus urna, at lacinia lectus. Cras aliquam neque et orci laoreet, eget lobortis sem tincidunt.', 'twentytwentytwo' ); ?></p></blockquote>
<!-- /wp:quote -->
<!-- wp:group {"lock":{"move":true,"remove":true},"style":{"spacing":{"blockGap":"1rem","padding":{"right":"1rem","left":"1rem"}}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"left"}} -->
<div class="wp-block-group" style="padding-right:1rem;padding-left:1rem"><!-- wp:image {<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-tiffany-color">"lock":{"move":true,"remove":true}</mark>,"width":60,"height":60,"style":{"border":{"radius":"100px"},"color":{"duotone":["#000097","#ff4747"]}},"className":"size-full is-resized is-style-default"} -->
<figure class="wp-block-image is-resized size-full is-style-default" style="border-radius:100px"><img src="<?php echo esc_url( get_template_directory_uri() ); ?>/assets/images/icon-bird.jpg" alt="" width="60" height="60"/></figure>
<!-- /wp:image -->
<!-- wp:group {"lock":{"move":true,"remove":true},"style":{"spacing":{"blockGap":"4px","margin":{"bottom":"1rem"}}}} -->
<div class="wp-block-group" style="margin-bottom:1rem"><!-- wp:paragraph {"placeholder":"First \u0026 Last Name",<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-tiffany-color">"lock":{"move":true,"remove":true}</mark>,"style":{"typography":{"fontStyle":"normal","fontWeight":"600","lineHeight":"1.5"}},"fontSize":"small"} -->
<p class="has-small-font-size" style="font-style:normal;font-weight:600;line-height:1.5"><?php echo esc_html( 'First & Last Name', 'twentytwentytwo' ); ?></p>
<!-- /wp:paragraph -->
<!-- wp:paragraph {"lock":{"move":true,"remove":true},"style":{"typography":{"textTransform":"uppercase","fontSize":"0.75rem"},"color":{"text":"#666666"}}} -->
<p class="has-text-color" style="color:#666666;font-size:0.75rem;text-transform:uppercase"><?php echo esc_html( 'Testimonial Source', 'twentytwentytwo' ); ?></p>
<!-- /wp:paragraph --></div>
<!-- /wp:group --></div>
<!-- /wp:group --></div>
<!-- /wp:column -->
<!-- wp:column {"lock":{"move":false,"remove":true},"style":{"spacing":{"padding":{"top":"2rem","right":"1.5rem","bottom":"2rem","left":"1rem"}}},"backgroundColor":"tertiary","className":"box-shadow\u002d\u002ddefault"} -->
<div class="wp-block-column box-shadow--default has-tertiary-background-color has-background" style="padding-top:2rem;padding-right:1.5rem;padding-bottom:2rem;padding-left:1rem"><!-- wp:quote {<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-tiffany-color">"lock":{"move":true,"remove":true}</mark>,"className":"is-style-plain","fontSize":"small"} -->
<blockquote class="wp-block-quote is-style-plain has-small-font-size"><p><?php echo esc_html( 'Testimonial — Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus in tempus urna, at lacinia lectus. Cras aliquam neque et orci laoreet, eget lobortis sem tincidunt.', 'twentytwentytwo' ); ?></p></blockquote>
<!-- /wp:quote -->
<!-- wp:group {"lock":{"move":true,"remove":true},"style":{"spacing":{"blockGap":"1rem","padding":{"right":"1rem","left":"1rem"}}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"left"}} -->
<div class="wp-block-group" style="padding-right:1rem;padding-left:1rem"><!-- wp:image {<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-tiffany-color">"lock":{"move":true,"remove":true}</mark>,"width":60,"height":60,"style":{"border":{"radius":"100px"},"color":{"duotone":["#a60072","#67ff66"]}},"className":"size-full is-resized is-style-default"} -->
<figure class="wp-block-image is-resized size-full is-style-default" style="border-radius:100px"><img src="<?php echo esc_url( get_template_directory_uri() ); ?>/assets/images/icon-bird.jpg" alt="" width="60" height="60"/></figure>
<!-- /wp:image -->
<!-- wp:group {"lock":{"move":true,"remove":true},"style":{"spacing":{"blockGap":"4px","margin":{"bottom":"1rem"}}}} -->
<div class="wp-block-group" style="margin-bottom:1rem"><!-- wp:paragraph {"placeholder":"First \u0026 Last Name",<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-tiffany-color">"lock":{"move":true,"remove":true}</mark>,"style":{"typography":{"fontStyle":"normal","fontWeight":"600","lineHeight":"1.5"}},"fontSize":"small"} -->
<p class="has-small-font-size" style="font-style:normal;font-weight:600;line-height:1.5"><?php echo esc_html( 'First & Last Name', 'twentytwentytwo' ); ?></p>
<!-- /wp:paragraph -->
<!-- wp:paragraph {"lock":{"move":true,"remove":true},"style":{"typography":{"textTransform":"uppercase","fontSize":"0.75rem"},"color":{"text":"#666666"}}} -->
<p class="has-text-color" style="color:#666666;font-size:0.75rem;text-transform:uppercase"><?php echo esc_html( 'Testimonial Source', 'twentytwentytwo' ); ?></p>
<!-- /wp:paragraph --></div>
<!-- /wp:group --></div>
<!-- /wp:group --></div>
<!-- /wp:column -->
<!-- wp:column {"lock":{"move":false,"remove":true},"style":{"spacing":{"padding":{"top":"2rem","right":"1.5rem","bottom":"2rem","left":"1rem"}}},"backgroundColor":"tertiary","className":"box-shadow\u002d\u002ddefault"} -->
<div class="wp-block-column box-shadow--default has-tertiary-background-color has-background" style="padding-top:2rem;padding-right:1.5rem;padding-bottom:2rem;padding-left:1rem"><!-- wp:quote {<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-tiffany-color">"lock":{"move":true,"remove":true}</mark>,"className":"is-style-plain","fontSize":"small"} -->
<blockquote class="wp-block-quote is-style-plain has-small-font-size"><p><?php echo esc_html( 'Testimonial — Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus in tempus urna, at lacinia lectus. Cras aliquam neque et orci laoreet, eget lobortis sem tincidunt.', 'twentytwentytwo' ); ?></p></blockquote>
<!-- /wp:quote -->
<!-- wp:group {"lock":{"move":true,"remove":true},"style":{"spacing":{"blockGap":"1rem","padding":{"right":"1rem","left":"1rem"}}},"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"left"}} -->
<div class="wp-block-group" style="padding-right:1rem;padding-left:1rem"><!-- wp:image {<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-tiffany-color">"lock":{"move":true,"remove":true}</mark>,"width":60,"height":60,"style":{"border":{"radius":"100px"},"color":{"duotone":["#c7005a","#fff278"]}},"className":"size-full is-resized is-style-default"} -->
<figure class="wp-block-image is-resized size-full is-style-default" style="border-radius:100px"><img src="<?php echo esc_url( get_template_directory_uri() ); ?>/assets/images/icon-bird.jpg" alt="" width="60" height="60"/></figure>
<!-- /wp:image -->
<!-- wp:group {"lock":{"move":true,"remove":true},"style":{"spacing":{"blockGap":"4px","margin":{"bottom":"1rem"}}}} -->
<div class="wp-block-group" style="margin-bottom:1rem"><!-- wp:paragraph {"placeholder":"First \u0026 Last Name",<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-tiffany-color">"lock":{"move":true,"remove":true}</mark>,"style":{"typography":{"fontStyle":"normal","fontWeight":"600","lineHeight":"1.5"}},"fontSize":"small"} -->
<p class="has-small-font-size" style="font-style:normal;font-weight:600;line-height:1.5"><?php echo esc_html( 'First & Last Name', 'twentytwentytwo' ); ?></p>
<!-- /wp:paragraph -->
<!-- wp:paragraph {"lock":{"move":true,"remove":true},"style":{"typography":{"textTransform":"uppercase","fontSize":"0.75rem"},"color":{"text":"#666666"}}} -->
<p class="has-text-color" style="color:#666666;font-size:0.75rem;text-transform:uppercase"><?php echo esc_html( 'Testimonial Source', 'twentytwentytwo' ); ?></p>
<!-- /wp:paragraph --></div>
<!-- /wp:group --></div>
<!-- /wp:group --></div>
<!-- /wp:column --></div>
<!-- /wp:columns --></div>
<!-- /wp:group -->
Code language: HTML, XML (xml)
To see this pattern in action, download the latest version of the Twenty Twenty-Two theme. The pattern should work in nearly any block theme, yet it uses Twenty Twenty-Two’s image assets to display the default testimonial image.
Note that while the theme registers all of its built-in patterns using the register_block_pattern()
function, there is now a more straightforward method. Create a new folder named patterns
in the root of the Twenty Twenty-Two directory and add the above code to a new file named testimonials.php
.
By placing the file in the patterns
folder, WordPress will handle the registration process automatically. This new way of registering patterns in themes was added in WordPress 6.0. More information is available in this Developer Note.
Restrict Locking and Unlocking
As noted above, any user who can edit blocks has the ability to both lock and unlock blocks. Given your WordPress implementation, this functionality might not be ideal.
Consider the situation where carefully crafted brand-specific block patterns have been created for a client. Locking goes a long way to ensure content consistency, but these users can still unlock blocks at will. What if you could restrict the locking UI to only Administrators or specific users?
The Editor setting canLockBlocks
was included in WordPress 6.0, allowing you to restrict the locking UI globally or conditionally. You can set this setting using the filter block_editor_settings_all
. By placing the following code example in the functions.php
file of any theme, only Administrators will have access to the locking UI.
functions.php
/**
* Restrict access to the locking UI to Administrators.
*
* @param array $settings Default editor settings.
* @param WP_Block_Editor_Context $context The current block editor context.
*/
function example_theme_restrict_locking_ui( $settings, $context ) {
$settings[ 'canLockBlocks' ] = current_user_can( 'activate_plugins' );
return $settings;
}
add_filter( 'block_editor_settings_all', 'example_theme_restrict_locking_ui', 10, 2 );
Code language: PHP (php)
In the Editor, block locking will remain visible to Administrators but will be disabled for all other users thereby preventing them from unlocking any locked blocks. Notice that even though the user cannot see the locking UI, they still cannot remove the Column block in the right screenshot.
This example checks the capabilities of the current user to determine if they are an Administrator. However, you can use any conditional. We are also disabling the locking UI for the “book” custom post type in this example.
functions.php
/**
* Restrict access to the locking UI to Administrators and
* disable entirely on the "book" custom post type.
*
* @param array $settings Default editor settings.
* @param WP_Block_Editor_Context $context The current block editor context.
*/
function example_theme_restrict_locking_ui( $settings, $context ) {
$is_administrator = current_user_can( 'activate_plugins' );
$is_book = $context->post && $context->post->post_type === 'book';
if ( $is_administrator || $is_book ) {
$settings[ 'canLockBlocks' ] = false;
}
return $settings;
}
add_filter( 'block_editor_settings_all', 'example_theme_restrict_locking_ui', 10, 2 );
Code language: PHP (php)
Bonus: Restrict Access to the Code Editor
We have shown that the lock
attribute determines whether a block can be moved or removed. While we can hide the locking UI from specific users, anyone with access to the Editor will also have access to the Code Editor. The Code Editor displays the underlying block markup allowing anyone to manually modify lock
attributes, which could be problematic.
Luckily it’s also possible to restrict access to the Code Editor using the Editor setting codeEditingEnabled
. We can easily modify our code example to accomplish this.
functions.php
/**
* Restrict access to the locking UI and the Code Editor
* to Administrators.
*
* @param array $settings Default editor settings.
* @param WP_Block_Editor_Context $context The current block editor context.
*/
function example_theme_restrict_locking_ui( $settings, $context ) {
$is_administrator = current_user_can( 'activate_plugins' );
if ( ! $is_administrator ) {
$settings[ 'canLockBlocks' ] = false;
$settings[ 'codeEditingEnabled' ] = false;
}
return $settings;
}
add_filter( 'block_editor_settings_all', 'example_theme_restrict_locking_ui', 10, 2 );
Code language: PHP (php)
Only Administrators can now access the block locking UI and the Code Editor. This example can be modified with different conditionals depending on your implementation, but hopefully, this illustrates just how powerful the block_editor_settings_all
can be.
Conclusion
Block locking is a great way to control how content is managed in WordPress. The applications are endless, whether you are locking content to prevent accidental removal and movement in your own workflow or looking to restrict Editor functionality for users and clients.
To learn more about additional ways to curate the editing experience in WordPress, check out our recent article on Block Templates or this fantastic Block Editor Handbook article on the topic. You can also watch the online workshop recording of Curating the Editor Experience, which is available on WordPress.tv.
External links referenced in this article and other related resources are listed below. Stay tuned for more articles on block theming, custom block development, and building with modern WordPress techniques.