Closed carolinan closed 2 years ago
Proposed areas to cover (unorganized):
patterns/
directory to register patternsget_theme_file_uri()
Block patterns are predefined block layouts. They offer a means to expedite and elevate the editorial experience by offering users a preset arrangement of blocks to start building right away.
Do you or your editors find themselves recreating patterns of blocks in the block editor? Then, converting those blocks into a pattern should save some time.
Let's jump in and learn how we can include them in a theme.
There are two methods for registering or including patterns in your theme and both approaches are compatible with classic and block themes:
patterns/
folder (recommended for block themes)register_block_pattern()
patterns/
directory to register patternsYou can add a new patterns/
directory within the root of your block theme and place PHP files within to register patterns. Each individual PHP file would contain a different pattern, e.g. patterns/my-fun-pattern.php
, patterns/another-pattern.php
The following is an example of a simple site footer pattern:
<?php
/**
* Title: Footer with text, social links.
* Slug: theme-slug/footer-default
* Categories: text, site-footer
* Block Types: core/template-part/footer
* Viewport Width: 1280
*/
?>
<!-- wp:group {"align":"full","layout":{"inherit":true}} -->
<div class="wp-block-group alignfull">
<!-- wp:group {"align":"wide","layout":{"type":"flex","allowOrientation":false,"justifyContent":"space-between"}} -->
<div class="wp-block-group alignwide">
<!-- wp:paragraph -->
<p>© <?php echo esc_html( gmdate( 'Y' ) ); ?> Your Company LLC · <a href="#"><?php echo esc_html__( 'Contact Us', 'theme-slug' ); ?></a></p>
<!-- /wp:paragraph -->
<!-- wp:social-links {"className":"is-style-logos-only"} -->
<ul class="wp-block-social-links has-icon-color is-style-logos-only">
<!-- wp:social-link {"url":"https://wordpress.org","service":"wordpress"} /-->
</ul>
<!-- /wp:social-links -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
This pattern would be saved in the patterns/
directory in your theme, e.g. patterns/footer-default.php
.
The title
and slug
properties in the pattern's header are required.
You can use the register_block_pattern()
function to register patterns with the init
hook.
function theme_slug_block_pattern() {
register_block_pattern( ... );
}
add_action( 'init', 'theme_slug_block_pattern' );
The register_block_pattern()
function requires two properties in order to properly register a custom pattern:
title
: A human-readable title for the pattern.content
: Block HTML Markup for the pattern.The following is a minimal example of a pattern with two buttons.
register_block_pattern(
'theme-slug/my-awesome-pattern',
array(
'title' => __( 'Two buttons', 'theme-slug' ),
'description' => _x( 'Two horizontal buttons, the left button is filled in, and the right button is outlined.', 'Block pattern description', 'theme-slug' ),
'categories' => array( 'theme-slug-custom-category' ),
'content' => "<!-- wp:buttons {"layout":{"type":"flex","justifyContent":"center"}} --><div class="wp-block-buttons"><!-- wp:button --><div class="wp-block-button"><a class="wp-block-button__link">' . __( 'Go shopping', 'theme-slug' ) . '</a></div><!-- /wp:button --></div><!-- /wp:buttons --></div></div>",
)
);
You can create patterns of blocks within the block editor and then copy from the code editor, and paste them into the 'content'
property. The 'content'
property contains the markup that your pattern will output when inserted in the block editor.
The 'categories'
property is optional and its value will assign your pattern to either a core or custom pattern category (See: Registering a custom pattern category below).
Some key things to keep in mind when you're creating block patterns in your theme, which we'll cover:
get_theme_file_uri()
Be sure to include the ability to translate strings when you're creating your block patterns. For example:
<!-- wp:heading -->
<h2>' . esc_html__( 'My great heading text', 'theme-slug' ) . '</h2>
<!-- /wp:heading -->
Notice the esc_html__( 'My great heading text', 'theme-slug' )
in the above code sample. This allows builders to translate your strings into other languages.
get_theme_file_uri()
If you're including inline assets in your patterns then you can use the get_theme_file_uri()
function to point to assets within your theme. Here is an example:
<!-- wp:cover {"url":"' .
esc_url( get_theme_file_uri( 'assets/images/snazzy-cover-image.png' ) ) . '",
"id":18,"contentPosition":"top center","align":"wide"}
-->
A typical workflow for creating block patterns starts in the block editor. You add, group, alter all your blocks and then copy and paste the results into either the 'content' = => 'your content'
if you're using register_block_pattern()
function, or just raw if you're placing in a new PHP file within your patterns/
directory. You may consider escaping the string before pasting with a tool like: https://onlinestringtools.com/escape-string
If you desire to add custom CSS classes to your pattern markup then you will have to use the className
attribute. For example:
<!-- wp:group {"className":"call-to-action"} -->
<div class="wp-block-group call-to-action">
<!-- wp:heading {"level":3} -->
<h3><?php esc_html_e( 'My heading', 'theme-slug' ); ?></h3>
<!-- /wp:heading --></div>
<!-- /wp:group -->
Note the use of "className":"call-to-action"
and within the related, following <div class="call-to-action">
. Both entries are necessary for this to work.
It is highly recommended that you conditionally load 3rd-party blocks within your patterns. Otherwise, the experience for rendering patterns can appear broken for end users. Here are two methods for conditionally loading blocks.
register_block_pattern()
Oftentimes, well written plugins offer a parent class
or function
for you to check against when relying on its functionality. You can use either the function_exists
or class_exists
check within the init
hook to check and register your pattern using register_block_pattern()
, as so:
add_action( 'init', function() {
if ( function_exists( 'some_plugin_func' ) ) {
register_block_pattern();
}
} );
patterns/
directorySince patterns that are found in the patterns/
directory are auto-registered then we need to reverse the operation by deregistering it based on if the plugin is active.
For example, if we had patterns/footer-default.php
in our theme:
<?php
/**
* Title: Footer with text, social links.
* Slug: theme-slug/footer-default
* Categories: text, site-footer
* Block Types: core/template-part/footer
* Viewport Width: 1280
*/
?>
<!-- block markup here -->
If this pattern relied on a 3rd-party block then we would unregister it with unregister_block_pattern()
, but we would have to hook it to our init
hook, like so:
add_action( 'init', function() {
if ( ! function_exists( 'some_plugin_func' ) ) {
unregister_block_pattern( 'theme-slug/footer-default' );
}
} );
Alternatively, if there were just a single 3rd-party block amongst many core blocks within a pattern that is loaded through the patterns/
directory. Then we could use PHP within the pattern to check:
<?php
/**
* Title: Footer with text, social links.
* Slug: theme-slug/footer-default
* Categories: text, site-footer
* Block Types: core/template-part/footer
* Viewport Width: 1280
*/
?>
<!-- some WP core blocks here -->
<?php if ( function_exists( 'some_plugin_func' ) ) : ?>
<!-- special 3rd-party block is here -->
<?php endif; ?>
<!-- some more WP core blocks here -->
Keep in mind that the pattern will look differently without the block when the 3rd-party block is unavailable and the overall layout may appear broken depending on your styling.
Organizing your block patterns into appropriate categories within the block inserter will help your users quickly find what they need.
You can register a custom category using the register_block_pattern_category()
function. Here is an example:
if ( function_exists( 'register_block_pattern_category' ) ) {
register_block_pattern_category(
'theme-slug-query',
array( 'label' => __( 'Query', 'theme-slug' ) )
);
}
This example registers a custom "Query" pattern category, which you can then reference and assign when you're registering your patterns:
register_block_pattern(
'theme-slug/my-custom-query-pattern',
array(
'categories' => array( 'theme-slug-query' ),
...
)
);
If you do not assign a category for your block pattern then it will just be automatically assigned to Uncategorized
in the block inserter.
You can use the unregister_block_pattern_category()
helper function to remove previously registered block categories. Typically, you'll want to call it within the init
hook, like so:
function theme_slug_unregister_pattern_categories() {
unregister_block_pattern_category( 'theme-slug-query' );
}
add_action( 'init', 'theme_slug_unregister_pattern_categories' );
The unregister_block_pattern_category()
function accepts one argument: title
, which is the name of the block pattern category to be unregistered.
By default, WordPress registers several block patterns and categories. However, theme developers can unregister some or all of these using the following methods:
remove_theme_support( 'core-block-patterns' );
- removes all core patterns and should be hooked to either the init
or the after_theme_setup()
hooks. Or,unregister_block_pattern()
- to unregister individual patterns.
Example: unregister_block_pattern( 'core/two-buttons' ); // Removes core two-buttons pattern
Furthermore, you can disable the calling and displaying of patterns from the WordPress Block Pattern Directory within you theme by utilizing the should_load_remote_block_patterns
filter.
add_filter( 'should_load_remote_block_patterns', '__return_false' );
@carolinan @kafleg @TeBenachi - this new doc is ready for review. This is my first contribution. Thanks!
@zzap I've moved label to Content Review
. Is this correct process?
For overall group, I added in the certain links to Learn videos, which I'm not sure is a standard, but I thought it would be helpful to allow different learning modalities. It could like be a maintenance burden. I'm curious on any guidance around this.
Yes, that's great @colorful-tones. As for Learn videos, I'd hold on with that. We do plan to link documentation to Learn resources but they are in the process of merging lessons and videos so the URLs might change very soon. This is why we are waiting with any sort of inner linking. But great thinking, nevertheless. It is what we plan eventually.
As for Learn videos, I'd hold on with that. We do plan to link documentation to Learn resources but they are in the process of merging lessons and videos so the URLs might change very soon. This is why we are waiting with any sort of inner linking. But great thinking, nevertheless. It is what we plan eventually.
@zzap thanks for clarifying. I've removed the links to video resources for now. 👍
@colorful-tones thank you so much. Great write-up! Looks great to me! It’s so clear and concise.
Just a couple of small minor points I noticed, if I may.
There are two methods currently for registering or including patterns in your theme and both approaches are compatible with classic and block themes:
currently may not be necessary for easier maintenance.
You can create patterns of blocks within the block editor and then copy from the code editor, and paste them into the 'content' property. The 'content' property contains the markup that your pattern will output when inserted in the block editor.
Adding “from the code editor” might help some developers clarify a little further.
I think the pattern topic can go under the Advanced Theme Topics or create a new top-level category.
Thanks
@TeBenachi thanks for the feedback. I've integrated both of your suggestions.
I think the pattern topic can go under the Advanced Theme Topics or create a new top-level category.
I do not have the ability to add this new doc here. May I have access please? Or, are Themes Team reps only allowed to access and add?
I'd consider moving the PHP registration as the secondary method for adding patterns, as using /patterns/
is simpler and less involved technically speaking. I would also add a bit of what use cases should lead to one method v. the other.
@colorful-tones the themes team do not have user management permission for the docs in order to give you permission.
I can see the list of users names that has access, but I do not see yours. I am also not sure which the correct user role would be.
I'd consider moving the PHP registration as the secondary method for adding patterns, as using
/patterns/
is simpler and less involved technically speaking.
Great point and I agree. I'll fix that up when I'm at my desk.
I would also add a bit of what use cases should lead to one method v. the other.
@richtabor I would have to lean on your experience and knowledge here. I'm not clear on the indicators of choosing one over the other and the value of adding that additional context?
@colorful-tones the themes team do not have user management permission for the docs in order to give you permission.
@carolinan thanks for checking and clarifying. I'll reach out to the Docs team to see if they're able to give me access. 👍
I'm not clear on the indicators of choosing one over the other and the value of adding that additional context?
I'd say that themes should use the /patterns
method, with the caveat that those patterns will not be available to sites running < WordPress 6.0. But if you're building a block theme, you should use the /patterns
method 100% of the time.
Plugins that register patterns (though there aren't many) would need to use the PHP method.
@richtabor I swapped the sequence for patterns/
and PHP registration
sections. I also updated and added a small addition here:
- patterns/ folder (recommended for block themes)
- PHP registration - uses the register_block_pattern()
Do you think that is adequate guidance?
I've submitted the post for review: "Block Patterns" under the "Advanced Theme Topics" (parent) on the Developer site.
Once approved, it would appear here: https://developer.wordpress.org/themes/advanced-topics/block-patterns/
Heads up @carolinan @kafleg @TeBenachi - I'm assuming it is you folks that will review and publish it?
Thanks everyone for your guidance! 🥳
Adding a note here to add in a new section to this doc that addresses how to conditionally load 3rd party blocks in patterns. As flagged by @carolinan in Slack.
@carolinan @justintadlock - I added a new section: "Using 3rd-party blocks". Please review and let me know if there is any feedback. Thanks!
@colorful-tones not sure if this is desired to be included but wanted to note some of the fun stuff from the curating the editor doc. Perhaps just linking off to this one is more than enough for now but it would be great to talk about locking, prioritizing patterns, etc.
@colorful-tones not sure if this is desired to be included but wanted to note some of the fun stuff from the curating the editor doc. Perhaps just linking off to this one is more than enough for now but it would be great to talk about locking, prioritizing patterns, etc.
@annezazu I think that is suitable for this doc and would be happy to add. I mostly want to get this published for now and could even add something while publishing the final doc, but just getting something published is better than nothing. 😄
I'll leave this open for another day or two for feedback, but then will likely publish and iterate from there.
I hear you there :D Sounds great.
@zzap I've just clicked the 'Submit for Review' on this draft. Curious, what team might be reviewing? Should I ping somebody?
Please no more pings 😄 once is enough unless you don't hear anything for several weeks.
@colorful-tones Are you still editing? The post is still locked.
@carolinan no, I am no longer editing.
I have some suggestions.
In the first paragraph it says: "They offer a means to expedite and elevate the editorial experience by offering users a preset arrangement of blocks to start building right away."
As a non native English speaker, the use of expedite and elevate and editorial experience is just confusing to me. My actual reaction was "Elevate? you mean like elevating an element in the design by adding a box shadow?" Can this be simplified and shortened?
The first code example was missing a translation function for part of the text. I have added it.
Below the first code example it says: "The title and slug properties in the pattern's header are required." Can we explain what these are? Part of that information is included for the PHP function, but not for the patterns folder.
And for the PHP function, it says that title and content are required, but it does not mention the slug.
In the translation code example, the text is escaped but not echoed.
How we can best explain the difference between the methods here?
In the PHP file in the patterns folder, the text needs to be echoed, but if we are using the PHP function to register the pattern, the text can't be echoed because we are returning the whole content
...
This difference got me more than once when I switched to using the patterns folder ;)
Linking assets code example Nit picking: Can we explain that this is not a full code example for the cover block? Because if someone tries to copy paste that code it will not work. In the cover block, the image source is used twice. Would it be easier to use an complete image block?
At the bottom, we should include a changelog. The first item will only show when the page was published. I have added this.
OK a few more things that came to mind after I posted the comment above:
On this list item patterns/ folder (recommended for block themes)
can we add that it only works from 6.0?
@carolinan thanks for all this awesome feedback! I'm going to look to incorporate it directly in the Make draft post. I'll drop a note here once it is all updated. 👍
In the first paragraph it says: "They offer a means to expedite and elevate the editorial experience by offering users a preset arrangement of blocks to start building right away."
As a non native English speaker, the use of expedite and elevate and editorial experience is just confusing to me. My actual reaction was "Elevate? you mean like elevating an element in the design by adding a box shadow?" Can this be simplified and shortened?
I've changed to read: "They offer a means to refine the editorial experience by offering users a preset arrangement of blocks to start building right away." Does this seem clearer?
The first code example was missing a translation function for part of the text. I have added it.
Thank you! 👍
Below the first code example it says: "The title and slug properties in the pattern's header are required." Can we explain what these are? Part of that information is included for the PHP function, but not for the patterns folder.
And for the PHP function, it says that title and content are required, but it does not mention the slug.
I believe I've addressed this. Please peek and let me know.
In the translation code example, the text is escaped but not echoed. How we can best explain the difference between the methods here? In the PHP file in the patterns folder, the text needs to be echoed, but if we are using the PHP function to register the pattern, the text can't be echoed because we are returning the whole content... This difference got me more than once when I switched to using the patterns folder ;)
I've added clarification around this as well. Let me know.
Linking assets code example Nit picking: Can we explain that this is not a full code example for the cover block? Because if someone tries to copy paste that code it will not work. In the cover block, the image source is used twice. Would it be easier to use an complete image block?
I've converted the example from a Cover block to an Image block. Let me know.
At the bottom, we should include a changelog. The first item will only show when the page was published. I have added this.
You rock! Thank you! ❤️
OK a few more things that came to mind after I posted the comment above:
- Should it not include instructions for how to display the pattern in a template in a full site editing theme, using the pattern block?
- Can we link to Converting customizer settings to block patterns?
I've addressed these as well.
On this list item patterns/ folder (recommended for block themes) can we add that it only works from 6.0?
I've added this with a link to the Make post announcing the addition of this feature.
@carolinan ☝️
Again, thanks for the review and feedback. Please let me know if you have anything further. I hope you enjoy your weekend and get some relaxing cross-stitching in. 🕺
The page is published and added to the menu. Thank you!
What is the new page you are requesting?
A dedicated page about how to register and use block patterns. A page that will refer back to the block editor handbook page at https://developer.wordpress.org/block-editor/reference-guides/block-api/block-patterns/
How will this new page help you?
Right now, it seems that information about block patterns in themes is spread out over several pages: https://developer.wordpress.org/themes/?s=block+patterns
Block patterns can be added in classic themes and block themes, but they can register them in different ways. Both the PHP function and the method with placing patterns inside the patterns folder should be covered.
For help with writing the content, you can refer to the dev notes: https://make.wordpress.org/core/2022/05/03/page-creation-patterns-in-wordpress-6-0/ https://make.wordpress.org/core/2022/05/02/new-features-for-working-with-patterns-and-themes-in-wordpress-6-0/