WordPress 6.0 simplifies block pattern creation for theme authors
Block patterns have been part of the WordPress block editor since version 5.5, letting users drop pre-built layouts into posts and pages. But for theme authors, the workflow for creating and bundling those patterns has traditionally meant writing PHP registration code. WordPress 6.0 changes that by letting themes register patterns simply by dropping files into a /patterns folder, matching the existing conventions for /parts, /templates, and /styles.
The old way: registering patterns with PHP
Before 6.0, patterns had to be registered with the register_block_pattern() function, either from a plugin or from a theme’s functions.php. The function takes a name and an array of properties describing the pattern:
register_block_pattern(
'my-plugin/hello-world',
array(
'title' => __( 'Hello World', 'my-plugin' ),
'content' => "<!-- wp:paragraph -->\n<p>Hello World</p>\n<!-- /wp:paragraph -->",
)
);
That registration call must be hooked to init:
function my_plugin_register_my_patterns() {
register_block_pattern( ... );
}
add_action( 'init', 'my_plugin_register_my_patterns' );
Beyond the required title and content, the block editor handbook documents these optional pattern properties:
description: A visually hidden text label for the inserter, useful when the title alone is not descriptive enough.categories: An array of registered pattern categories for grouping.keywords: Aliases that aid search discovery.viewportWidth: An integer for scaled previews in the inserter.blockTypes: An array of block names the pattern is intended for.inserter: Set tofalseto hide the pattern while still allowing programmatic insertion.
An example plugin-style registration of a quote pattern, from the WordPress blog:
/*
Plugin Name: Quote Pattern Example Plugin
*/
register_block_pattern(
'my-plugin/my-quote-pattern',
array(
'title' => __( 'Quote with Avatar', 'my-plugin' ),
'categories' => array( 'text' ),
'description' => _x( 'A big quote with an avatar".', 'Block pattern description', 'my-plugin' ),
'content' => '<!-- wp:group --><div class="wp-block-group"><div class="wp-block-group__inner-container"><!-- wp:separator {"className":"is-style-default"} --><hr class="wp-block-separator is-style-default"/><!-- /wp:separator --><!-- wp:image {"align":"center","id":553,"width":150,"height":150,"sizeSlug":"large","linkDestination":"none","className":"is-style-rounded"} --><div class="wp-block-image is-style-rounded"><figure class="aligncenter size-large is-resized"><img src="https://blockpatterndesigns.mystagingwebsite.com/wp-content/uploads/2021/02/StockSnap_HQR8BJFZID-1.jpg" alt="" class="wp-image-553" width="150" height="150"/></figure></div><!-- /wp:image --><!-- wp:quote {"align":"center","className":"is-style-large"} --><blockquote class="wp-block-quote has-text-align-center is-style-large"><p>"Contributing makes me feel like I\'m being useful to the planet."</p><cite>— Anna Wong, <em>Volunteer</em></cite></blockquote><!-- /wp:quote --><!-- wp:separator {"className":"is-style-default"} --><hr class="wp-block-separator is-style-default"/><!-- /wp:separator --></div></div><!-- /wp:group -->',
)
);
Once registered, a pattern can be pulled into a template file with its slug:
<!-- wp:pattern {"slug":"prefix/pattern-slug"} /-->
Themes that ship only a few patterns can keep this in one manageable block-patterns.php file. Twenty Twenty-Two, however, bundles more than 60 patterns and the refactored its pattern code for maintainability. Its approach: a registration file that iterates over an array of pattern names and requires a matching file from a dedicated /inc/patterns folder.
/**
* Registers block patterns and categories.
*/
function twentytwentytwo_register_block_patterns() {
$block_pattern_categories = array(
'footer' => array( 'label' => __( 'Footers', 'twentytwentytwo' ) ),
'header' => array( 'label' => __( 'Headers', 'twentytwentytwo' ) ),
'pages' => array( 'label' => __( 'Pages', 'twentytwentytwo' ) ),
// ...
);
/**
* Filters the theme block pattern categories.
*/
$block_pattern_categories = apply_filters( 'twentytwentytwo_block_pattern_categories', $block_pattern_categories );
foreach ( $block_pattern_categories as $name => $properties ) {
if ( ! WP_Block_Pattern_Categories_Registry::get_instance()->is_registered( $name ) ) {
register_block_pattern_category( $name, $properties );
}
}
$block_patterns = array(
'footer-default',
'footer-dark',
'footer-with-background',
//...
'header-default',
'header-large-dark',
'header-small-dark',
'hidden-404',
'hidden-bird',
//...
);
/**
* Filters the theme block patterns.
*/
$block_patterns = apply_filters( 'twentytwentytwo_block_patterns', $block_patterns );
foreach ( $block_patterns as $block_pattern ) {
$pattern_file = get_theme_file_path( '/inc/patterns/' . $block_pattern . '.php' );
register_block_pattern(
'twentytwentytwo/' . $block_pattern,
require $pattern_file
);
}
}
add_action( 'init', 'twentytwentytwo_register_block_patterns', 9 );
Each pattern file in that folder returns an array with its metadata and markup:
/**
* Dark footer wtih title and citation
*/
return array(
'title' => __( 'Footer with background', 'twentytwentytwo' ),
'categories' => array( 'footer' ),
'blockTypes' => array( 'core/template-part/footer' ),
'content' => '<!-- wp:group {"align":"full","style":{"elements":{"link":{"color":{"text":"var:preset|color|background"}}},"spacing":{"padding":{"top":"var(--wp--custom--spacing--small, 1.25rem)","bottom":"var(--wp--custom--spacing--small, 1.25rem)"}}},"backgroundColor":"background-header","textColor":"background","layout":{"inherit":true}} -->
<div class="wp-block-group alignfull has-background-color has-background-header-background-color has-text-color has-background has-link-color" style="padding-top:var(--wp--custom--spacing--small, 1.25rem);padding-bottom:var(--wp--custom--spacing--small, 1.25rem)"><!-- wp:paragraph {"align":"center"} -->
<p class="has-text-align-center">' .
sprintf(
/* Translators: WordPress link. */
esc_html__( 'Proudly powered by %s', 'twentytwentytwo' ),
'<a href="' . esc_url( __( 'https://wordpress.org', 'twentytwentytwo' ) ) . '" rel="nofollow">WordPress</a> | a modified TT2 theme.'
) . '</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group -->',
);
The pattern can then be referenced in a template part such as footer.html by its slug:
<!-- wp:template-part {"slug":"footer"} /-->
WordPress 6.0: patterns without registration
WordPress 6.0 (or Gutenberg plugin 13.0+) replaces the PHP registration workflow with a simpler, file-based alternative. There are three pieces:
- A
/patternsfolder at the theme's root. - A plugin-style header in each pattern file, with metadata as PHP comments.
- The pattern content in block markup.
The typical header fields:
<?php
/**
* Title: A Pattern Title
* Slug: namespace/slug
* Description: A human-friendly description.
* Viewport Width: 1024
* Categories: comma, separated, values
* Keywords: comma, separated, values
* Block Types: comma, separated, values
* Inserter: yes|no
*/
?>
Only Title and Slug are required; the rest are optional. Refactoring an existing pattern from the PHP registration model means moving a pattern file like footer-with-background.php from an /inc/patterns folder to the new /patterns folder and replacing the return array() structure with the header comments:
<?php
/**
* Title: Footer with background
* Slug: tt2gopher/footer-with-background
* Categories: tt2gopher-footer
* Viewport Width: 1280
* Block Types: core/parts/footer
* Inserter: yes
*/
?>
<!-- some-block-content /-->
Below the header, the pattern content is written directly in block markup. Existing patterns bundled with register_block_pattern() typically keep their content inside single quotes in a PHP array – that markup can be lifted out as-is into the new file. For example, the content from a footer-with-background pattern becomes:
<!-- wp:group {"align":"full","style":{"elements":{"link":{"color":{"text":"var:preset|color|foreground"}}},"spacing":{"padding":{"top":"35px","bottom":"30px"}}},"backgroundColor":"background-header","textColor":"foreground","className":"has-foreground","layout":{"inherit":true}} -->
<div class="wp-block-group alignfull has-foreground has-foreground-color has-background-header-background-color has-text-color has-background has-link-color" style="padding-top:35px;padding-bottom:30px"><!-- wp:paragraph {"align":"center","fontSize":"small"} -->
<p class="has-text-align-center has-small-font-size">Powered by WordPress | TT2 Gopher, a modified TT2 theme</p>
<!-- /wp:paragraph --></div>
<!-- /wp:group -->
Referencing the refactored pattern from a template file is no different than before — the same slug reference works in footer.html. The older /inc/patterns folder and block-patterns.php are not required in a 6.0 theme; they are leftover conventions.
Several themes in the WordPress directory already load patterns this way, including Archeo (12 patterns), Pendant (13), and Skatepark (10).
Pattern categories and the page creation modal
While the /patterns folder removes the need for pattern registration code, custom pattern categories still require registration in functions.php. Adding a theme namespace to the category registration keeps the category labels distinct in the inserter:
/**
* Registers block categories, and type.
*/
function tt2gopher_register_block_pattern_categories() {
$block_pattern_categories = array(
'tt2gopher-header' => array( 'label' => __( 'TT2 Gopher - Headers', 'tt2gopher' ) ),
'tt2gopher-footer' => array( 'label' => __( 'TT2 Gopher - Footers', 'tt2gopher' ) ),
'tt2gopher-page' => array( 'label' => __( 'TT2 Gopher - Page', 'tt2gopher' ) ),
// ...
);
/**
* Filters the theme block pattern categories.
*/
$block_pattern_categories = apply_filters( 'tt2gopher_block_pattern_categories', $block_pattern_categories );
foreach ( $block_pattern_categories as $name => $properties ) {
if ( ! WP_Block_Pattern_Categories_Registry::get_instance()->is_registered( $name ) ) {
register_block_pattern_category( $name, $properties );
}
}
add_action( 'init', 'tt2gopher_register_block_pattern_categories', 9 );
WordPress 6.0 also introduced a page creation pattern modal for block themes. Theme authors can specify patterns – say, an about page, a contact page, or a team page – that are offered to users when creating a new page. The configuration lives in the theme’s theme.json file:
register_block_pattern(
'my-plugin/about-page',
array(
'title' => __( 'About page', 'my-plugin' ),
'blockTypes' => array( 'core/post-content' ),
'content' => '<!-- wp:paragraph {"backgroundColor":"black","textColor":"white"} -->
<p class="has-white-color has-black-background-color has-text-color has-background">Write you about page here, feel free to use any block</p>
<!-- /wp:paragraph -->',
)
);
This is currently limited to pages; the Posts post type does not get the modal. Removing all patterns with the post-content block type disables the modal entirely.
Low-code paths: the pattern directory and theme.json
Theme authors can also skip local pattern files altogether and pull patterns from the public WordPress pattern directory. One route is simple copy-paste: grab a pattern from the directory front-end, paste it into a new page, customize it, copy the resulting block markup from the code editor, and save it as a file in /patterns with an appropriate header:
<?php
/**
* Title: Footer pattern from patterns library
* Slug: tt2gopher/footer-pattern-test
* Categories: tt2gopher-footer
* Viewport Width: 1280
* Block Types: core/template-part/footer
* Inserter: yes
*/
?>
<!-- wp:group {"align":"full","style":{"spacing":{"padding":{"top":"100px","bottom":"70px","right":"30px","left":"30px"}}},"backgroundColor":"black","layout":{"contentSize":"1280px"}} -->
<div class="wp-block-group alignfull has-black-background-color has-background" style="padding-top:100px;padding-right:30px;padding-bottom:70px;padding-left:30px"><!-- wp:columns -->
<div class="wp-block-columns"><!-- wp:column -->
<div class="wp-block-column"><!-- wp:heading {"style":{"typography":{"fontStyle":"normal","fontWeight":"700","textTransform":"uppercase"}},"textColor":"cyan-bluish-gray"} -->
<h2 class="has-cyan-bluish-gray-color has-text-color" style="font-style:normal;font-weight:700;text-transform:uppercase">lorem</h2>
<!-- /wp:heading -->
<!-- wp:paragraph {"style":{"typography":{"fontSize":"16px"}},"textColor":"cyan-bluish-gray"} -->
<p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px">One of the main benefits of using Lorem Ipsum is that it can be easily generated, and it takes the pressure off designers to create meaningful text. Instead, they can focus on crafting the best website data.</p>
<!-- /wp:paragraph -->
<!-- wp:social-links {"iconColor":"vivid-cyan-blue","iconColorValue":"#0693e3","openInNewTab":true,"className":"is-style-logos-only","style":{"spacing":{"blockGap":{"top":"15px","left":"15px"}}}} -->
<ul class="wp-block-social-links has-icon-color is-style-logos-only"><!-- wp:social-link {"url":"#","service":"facebook"} /-->
<!-- wp:social-link {"url":"#","service":"twitter"} /-->
<!-- wp:social-link {"url":"#","service":"instagram"} /-->
<!-- wp:social-link {"url":"#","service":"linkedin"} /--></ul>
<!-- /wp:social-links --></div>
<!-- /wp:column -->
<!-- wp:column -->
<div class="wp-block-column"><!-- wp:heading {"level":4,"style":{"typography":{"textTransform":"capitalize","fontStyle":"normal","fontWeight":"700","fontSize":"30px"}},"textColor":"cyan-bluish-gray"} -->
<h4 class="has-cyan-bluish-gray-color has-text-color" style="font-size:30px;font-style:normal;font-weight:700;text-transform:capitalize">Contact Us</h4>
<!-- /wp:heading -->
<!-- wp:paragraph {"style":{"typography":{"fontSize":"16px","lineHeight":"1.2"}},"textColor":"cyan-bluish-gray"} -->
<p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px;line-height:1.2">123 BD Lorem, Ipsum<br><br>+123-456-7890</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph {"style":{"typography":{"fontSize":"16px","lineHeight":"1"}},"textColor":"cyan-bluish-gray"} -->
<p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px;line-height:1">[email protected]</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph {"style":{"typography":{"fontSize":"16px","lineHeight":"1"}},"textColor":"cyan-bluish-gray"} -->
<p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px;line-height:1">Opening Hours: 10:00 - 18:00</p>
<!-- /wp:paragraph --></div>
<!-- /wp:column -->
<!-- wp:column -->
<div class="wp-block-column"><!-- wp:heading {"level":4,"style":{"typography":{"fontSize":"30px","fontStyle":"normal","fontWeight":"700","textTransform":"capitalize"}},"textColor":"cyan-bluish-gray"} -->
<h4 class="has-cyan-bluish-gray-color has-text-color" style="font-size:30px;font-style:normal;font-weight:700;text-transform:capitalize">Newsletter</h4>
<!-- /wp:heading -->
<!-- wp:paragraph {"style":{"typography":{"fontSize":"16px"}},"textColor":"cyan-bluish-gray"} -->
<p class="has-cyan-bluish-gray-color has-text-color" style="font-size:16px">Lorem ipsum dolor sit amet, consectetur ut labore et dolore magna aliqua ipsum dolor sit</p>
<!-- /wp:paragraph -->
<!-- wp:search {"label":"","placeholder":"Enter Your Email...","buttonText":"Subscribe","buttonPosition":"button-inside","style":{"border":{"width":"1px"}},"borderColor":"tertiary","backgroundColor":"background-header","textColor":"background"} /--></div>
<!-- /wp:column --></div>
<!-- /wp:columns --></div>
<!-- /wp:group -->
For patterns you want to use but not modify, WordPress 6.0 allows direct registration from theme.json. The patterns field in theme.json takes an array of pattern slugs from the directory:
{
"version": 2,
"patterns": ["short-text", "patterns-slug"]
}
The slug is the one that appears in the URL of a pattern's single view on the directory. Registered patterns are then searchable and available in the inserter alongside theme-bundled ones.
Because patterns are just block markup, they can also be assembled outside WordPress entirely. Experimental page-builder tools such as GutenbergHub's online builder let users assemble a full page from directory patterns and paste that code back into a site.
Pattern files placed in a theme's /patterns folder register automatically in WordPress 6.0, eliminating the PHP boilerplate of earlier releases. Copied, customized, or declaratively registered via theme.json, these patterns form the basis of a low-code approach to building and styling sites — one that is only expected to grow as further "building with patterns" features land in future releases.



