Himanshu SharmaSoftware engineer
Let’s talk

WordPress · Lesson 21 of 45

Block patterns

Create block patterns for a WordPress theme with PHP files in the patterns folder, use them in templates, register categories and make them translatable.

13 minBlock themesUpdated 23 October 2026

By the end of this lessonPackage reusable layouts as patterns that editors can insert, and use patterns to keep templates short and consistent.

Patterns for themes

You met patterns as an editor in Writing with the block editor: ready-made groups of blocks that you insert and then change. Themes provide patterns too. They are the best way to offer editors well-designed sections (a hero banner, a call to action, a pricing table, a team grid) that match the theme.

Patterns also help you: templates can include patterns instead of repeating the same block markup, which keeps them short.

Development mode first

WordPress caches the list of a theme's pattern files, so that it does not scan the folder on every page view. While you are building a theme, that cache means a new pattern file may not appear until the cache expires. Tell WordPress you are developing a theme, in wp-config.php or with WP-CLI:

bash
wp config set WP_DEVELOPMENT_MODE theme
result
Success: Added the constant 'WP_DEVELOPMENT_MODE' to the 'wp-config.php' file with the value 'theme'.

In theme development mode, WordPress rescans pattern files (and skips some other theme caches) on every request. Remove the setting, or set it to an empty string, on the live site.

A pattern file

In a block theme, every PHP file in the patterns folder with a valid header is registered automatically. This hero section for the Bakery theme (continuing from Your first block theme) has a heading, a paragraph and a button:

php
<?php
/**
 * Title: Bakery hero
 * Slug: bakery/hero
 * Categories: bakery, featured
 * Keywords: banner, welcome
 * Description: A large welcome section with a call to action.
 */
?>
<!-- wp:group {"align":"wide","layout":{"type":"constrained"}} -->
<div class="wp-block-group alignwide">
	<!-- wp:heading {"level":1} -->
	<h1 class="wp-block-heading"><?php esc_html_e( 'Bread worth getting up for', 'bakery' ); ?></h1>
	<!-- /wp:heading -->
	<!-- wp:paragraph -->
	<p><?php esc_html_e( 'Sourdough, croissants and cakes, baked every morning in our own kitchen.', 'bakery' ); ?></p>
	<!-- /wp:paragraph -->
	<!-- wp:buttons -->
	<div class="wp-block-buttons">
		<!-- wp:button -->
		<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="/menu/"><?php esc_html_e( 'See today\'s menu', 'bakery' ); ?></a></div>
		<!-- /wp:button -->
	</div>
	<!-- /wp:buttons -->
</div>
<!-- /wp:group -->

The header comment works like a theme's style.css header:

  • Title (required): the name shown in the inserter.
  • Slug (required): a unique ID, conventionally theme-name/pattern-name.
  • Categories: where it appears in the inserter (comma separated).
  • Keywords, Description: help editors find it.
  • Optional Block Types, Post Types, Inserter: no (register it for templates only, hidden from editors), and Template Types.

Because the file is PHP, text is wrapped in esc_html_e(), which translates it (using the theme's text domain, bakery) and escapes it for safe output. That is the main reason to write patterns as PHP files rather than plain HTML.

Pattern categories

featured is a built-in category; bakery is ours, so we register it in the theme's functions.php, a PHP file WordPress loads with the theme:

php
<?php
add_action( 'init', function () {
	register_block_pattern_category( 'bakery', [ 'label' => __( 'Bakery', 'bakery' ) ] );
} );

WordPress has now registered the pattern from the file:

php
<?php
$pattern = WP_Block_Patterns_Registry::get_instance()->get_registered( 'bakery/hero' );
echo "title: ", $pattern['title'], "\n";
echo "categories: ", implode( ', ', $pattern['categories'] ), "\n";
echo "keywords: ", implode( ', ', $pattern['keywords'] ), "\n";
echo "category registered: ", WP_Block_Pattern_Categories_Registry::get_instance()->is_registered( 'bakery' ) ? 'yes' : 'no', "\n";
result
title: Bakery hero
categories: bakery, featured
keywords: banner, welcome
category registered: yes

Editors find it in the block inserter under Patterns → Bakery. When they insert it, they get an independent copy of the blocks that they can edit freely.

Using a pattern in a template

A front-page template can now be a few lines long: header, hero pattern, latest posts, footer.

html
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->

<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
<main class="wp-block-group">
	<!-- wp:pattern {"slug":"bakery/hero"} /-->

	<!-- wp:heading --><h2 class="wp-block-heading">From the blog</h2><!-- /wp:heading -->
	<!-- wp:latest-posts {"postsToShow":3} /-->
</main>
<!-- /wp:group -->

<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
http
GET /
result
Bread worth getting up for
Sourdough, croissants and cakes, baked every morning in our own kitchen.
See today's menu
From the blog
Hello world!

The Pattern block (wp:pattern) was replaced by the hero's blocks, with the translated text. Latest Posts is a dynamic block that lists recent posts. Because front-page.html is more specific than index.html, WordPress now uses it for the home page.

Registering patterns in code

Plugins (and themes that prefer code) can register patterns with register_block_pattern() instead of files:

php
<?php
register_block_pattern( 'bakery/opening-hours', [
	'title'      => 'Opening hours',
	'categories' => [ 'bakery' ],
	'content'    => '<!-- wp:paragraph --><p>Monday to Saturday, 7am to 6pm.</p><!-- /wp:paragraph -->',
] );
echo do_blocks( '<!-- wp:pattern {"slug":"bakery/opening-hours"} /-->' ), "\n";
result
<p class="wp-block-paragraph">Monday to Saturday, 7am to 6pm.</p>

In real code, call it inside an init action as with the category above. The file approach is simpler for themes; the function suits plugins and patterns built from data.

Patterns from the directory

The official Pattern Directory offers many community patterns. Themes can list some to show by adding their slugs to "patterns" in theme.json. WordPress also loads some core patterns remotely; a theme can turn that off with remove_theme_support( 'core-block-patterns' ).

Patterns, template parts and synced patterns

These three are easy to confuse:

Pattern (theme or plugin) Template part Synced pattern
Defined in a PHP file or code parts/*.html the editor (database)
When inserted becomes an editable copy stays linked stays linked
Typical use starting layouts, sections header, footer content repeated across posts

Common mistakes

  • Missing Slug in the header, so the pattern is not registered.
  • Hard-coded English text instead of translatable strings.
  • Patterns with images from the theme folder using absolute URLs; build them with get_theme_file_uri() so they work on every site.
  • Very long templates that copy the same sections instead of using patterns.

Exercise

Create a pattern bakery/call-to-action in the patterns folder with a heading "Order a birthday cake" and a button linking to /contact/. Hide it from the inserter with Inserter: no and include it at the bottom of front-page.html.

Show one possible answer
php
<?php
/**
 * Title: Call to action
 * Slug: bakery/call-to-action
 * Inserter: no
 */
?>
<!-- wp:heading --><h2 class="wp-block-heading"><?php esc_html_e( 'Order a birthday cake', 'bakery' ); ?></h2><!-- /wp:heading -->
<!-- wp:buttons --><div class="wp-block-buttons"><!-- wp:button --><div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="/contact/"><?php esc_html_e( 'Get in touch', 'bakery' ); ?></a></div><!-- /wp:button --></div><!-- /wp:buttons -->

Then add <!-- wp:pattern {"slug":"bakery/call-to-action"} /--> before </main> in front-page.html. It appears on the home page but not in the editor's pattern list.

Key points

  • A pattern is a named, reusable group of blocks that editors insert from the Patterns tab.
  • Block themes register patterns automatically from PHP files in the patterns folder, using a header comment with Title and Slug.
  • Templates can include a pattern with <!-- wp:pattern {"slug":"theme/name"} /-->, which keeps them short.
  • Because pattern files are PHP, text in them can be translated and escaped with functions such as esc_html_e().

Check yourself

1. Where does a block theme put pattern files so WordPress registers them automatically?
2. Which header field is required for a pattern file?
3. How does a template include a pattern?
4. What is the difference between a theme pattern and a synced pattern made by a user?