{"id":33092,"date":"2026-02-16T19:55:34","date_gmt":"2026-02-16T19:55:34","guid":{"rendered":"https:\/\/brndle.com\/?p=33092"},"modified":"2026-02-16T19:55:34","modified_gmt":"2026-02-16T19:55:34","slug":"custom-block-patterns-wordpress","status":"publish","type":"post","link":"https:\/\/brndle.com\/custom-block-patterns-wordpress\/","title":{"rendered":"How to Create Custom Block Patterns in WordPress Block Themes"},"content":{"rendered":"<p>Block patterns are one of the most powerful features in the WordPress block theme ecosystem. They are pre-built layouts made of blocks that you can insert with a single click \u2014 hero sections, pricing tables, testimonial grids, call-to-action bars, team member layouts, and anything else you can build with blocks. Instead of assembling the same layout manually every time, you build it once as a pattern and reuse it across your entire site.<\/p>\n\n<p>WordPress ships with dozens of default patterns, but the real power comes from creating your own. Custom patterns let you define your brand&#8217;s specific layouts, enforce design consistency across your site, and give content editors pre-approved sections they can drop into any page without touching the design.<\/p>\n\n<p>This guide covers everything: registering patterns in PHP, organizing them into categories, understanding synced vs unsynced patterns, creating patterns from the editor, and building advanced PHP-based dynamic patterns. If you are new to block themes, start with our <a href=\"https:\/\/brndle.com\/how-to-master-theme-json-the-complete-block-theme-configuration-guide\/\">complete theme.json configuration guide<\/a> first.<\/p>\n\n<h2>What Block Patterns Are (and Are Not)<\/h2>\n\n<p>A block pattern is a collection of blocks arranged in a specific layout with predefined content, styles, and settings. When you insert a pattern into a page, WordPress copies all the blocks and their attributes into your content. From that point, you can edit the blocks individually \u2014 the pattern is just the starting point.<\/p>\n\n<p>Patterns are <strong>not<\/strong> reusable blocks (now called synced patterns). The difference matters:<\/p>\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Feature<\/th><th>Regular Pattern (Unsynced)<\/th><th>Synced Pattern<\/th><\/tr><\/thead><tbody><tr><td>What happens on insert<\/td><td>Blocks are copied. Each instance is independent.<\/td><td>A reference is inserted. All instances share the same content.<\/td><\/tr><tr><td>Editing one instance<\/td><td>Only affects that instance<\/td><td>Changes appear everywhere the pattern is used<\/td><\/tr><tr><td>Best for<\/td><td>Starting layouts, templates, design systems<\/td><td>Shared content like CTAs, announcements, footer blocks<\/td><\/tr><tr><td>Stored as<\/td><td>PHP registration or <code>wp_block<\/code> post type<\/td><td><code>wp_block<\/code> post type with <code>wp_pattern_sync_status<\/code> meta<\/td><\/tr><\/tbody><\/table><\/figure>\n\n<h2>Method 1: Register Patterns in PHP<\/h2>\n\n<p>The most reliable way to add custom patterns to your block theme is through PHP registration using the <code>register_block_pattern()<\/code> function. This approach keeps patterns in your theme&#8217;s codebase, makes them version-controllable, and ensures they are available immediately on theme activation.<\/p>\n\n<h3>Basic Pattern Registration<\/h3>\n\n<pre class=\"wp-block-code\"><code>add_action( 'init', function() {\n    register_block_pattern(\n        'mytheme\/hero-with-cta',\n        array(\n            'title'       => __( 'Hero Section with CTA', 'mytheme' ),\n            'description' => __( 'A full-width hero section with heading, paragraph, and two buttons.', 'mytheme' ),\n            'categories'  => array( 'featured', 'banner' ),\n            'keywords'    => array( 'hero', 'banner', 'cta', 'landing' ),\n            'content'     => '\n<div class=\"wp-block-cover alignfull\"><span class=\"wp-block-cover__background has-black-background-color has-background-dim-60 has-background-dim\"><\/span><div class=\"wp-block-cover__inner-container is-layout-flow wp-block-cover-is-layout-flow\">\n\n<h1 class=\"wp-block-heading has-text-align-center\" style=\"font-size:3.5rem\">Build Something Beautiful<\/h1>\n\n\n<p class=\"has-text-align-center\">Create stunning websites with the power of WordPress block themes.<\/p>\n\n\n<div class=\"wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-a89b3969 wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\">Get Started<\/a><\/div>\n\n\n<div class=\"wp-block-button is-style-outline is-style-outline--1\"><a class=\"wp-block-button__link wp-element-button\">Learn More<\/a><\/div>\n<\/div>\n\n<\/div><\/div>\n',\n        )\n    );\n});<\/code><\/pre>\n\n<h3>Pattern Properties Explained<\/h3>\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Property<\/th><th>Required<\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td><code>title<\/code><\/td><td>Yes<\/td><td>Display name in the pattern inserter<\/td><\/tr><tr><td><code>content<\/code><\/td><td>Yes<\/td><td>Block markup (copy from the editor&#8217;s Code Editor view)<\/td><\/tr><tr><td><code>description<\/code><\/td><td>No<\/td><td>Shown as a tooltip in the pattern inserter<\/td><\/tr><tr><td><code>categories<\/code><\/td><td>No<\/td><td>Array of category slugs for organization<\/td><\/tr><tr><td><code>keywords<\/code><\/td><td>No<\/td><td>Search terms to help users find the pattern<\/td><\/tr><tr><td><code>viewportWidth<\/code><\/td><td>No<\/td><td>Preview width in pixels (default: 800)<\/td><\/tr><tr><td><code>blockTypes<\/code><\/td><td>No<\/td><td>Suggest this pattern when specific blocks are inserted<\/td><\/tr><tr><td><code>inserter<\/code><\/td><td>No<\/td><td>Set to <code>false<\/code> to hide from the inserter (for programmatic use only)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n<h2>Method 2: File-Based Patterns (WordPress 6.0+)<\/h2>\n\n<p>Since WordPress 6.0, you can register patterns by simply creating PHP files in your theme&#8217;s <code>patterns\/<\/code> directory. WordPress automatically discovers and registers them \u2014 no <code>register_block_pattern()<\/code> call needed.<\/p>\n\n<h3>Create the Pattern File<\/h3>\n\n<p>Create a file at <code>patterns\/hero-cta.php<\/code> in your theme:<\/p>\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n\/**\n * Title: Hero Section with CTA\n * Slug: mytheme\/hero-cta\n * Categories: featured, banner\n * Keywords: hero, banner, cta, landing\n * Viewport Width: 1200\n *\/\n?&gt;\n&lt;!-- wp:cover {\"dimRatio\":60,\"overlayColor\":\"black\",\"isUserOverlayColor\":true,\"align\":\"full\"} --&gt;\n&lt;div class=\"wp-block-cover alignfull\"&gt;\n  &lt;span class=\"wp-block-cover__background has-black-background-color has-background-dim-60 has-background-dim\"&gt;&lt;\/span&gt;\n  &lt;div class=\"wp-block-cover__inner-container\"&gt;\n    &lt;!-- wp:heading {\"textAlign\":\"center\",\"level\":1} --&gt;\n    &lt;h1 class=\"wp-block-heading has-text-align-center\"&gt;Build Something Beautiful&lt;\/h1&gt;\n    &lt;!-- \/wp:heading --&gt;\n    &lt;!-- wp:paragraph {\"align\":\"center\"} --&gt;\n    &lt;p class=\"has-text-align-center\"&gt;Create stunning websites with WordPress block themes.&lt;\/p&gt;\n    &lt;!-- \/wp:paragraph --&gt;\n  &lt;\/div&gt;\n&lt;\/div&gt;\n&lt;!-- \/wp:cover --&gt;<\/code><\/pre>\n\n<p>The PHP comment block at the top is the pattern header. WordPress reads these comments to register the pattern automatically. The <code>Slug<\/code> must be unique and should follow the <code>themename\/pattern-name<\/code> convention.<\/p>\n\n<p>This method is cleaner than PHP registration for most use cases. Your pattern content lives in its own file, it is easy to read and edit, and you do not need any registration code.<\/p>\n\n<h2>Creating Pattern Categories<\/h2>\n\n<p>Custom categories help organize your patterns in the inserter. Register them using <code>register_block_pattern_category()<\/code>:<\/p>\n\n<pre class=\"wp-block-code\"><code>add_action( 'init', function() {\n    register_block_pattern_category(\n        'mytheme-heroes',\n        array(\n            'label' => __( 'Hero Sections', 'mytheme' ),\n        )\n    );\n\n    register_block_pattern_category(\n        'mytheme-testimonials',\n        array(\n            'label' => __( 'Testimonials', 'mytheme' ),\n        )\n    );\n\n    register_block_pattern_category(\n        'mytheme-pricing',\n        array(\n            'label' => __( 'Pricing Tables', 'mytheme' ),\n        )\n    );\n});<\/code><\/pre>\n\n<p>Then assign patterns to these categories using the <code>categories<\/code> property in either the PHP registration or the file header comment.<\/p>\n\n<h2>How to Get Block Markup for Patterns<\/h2>\n\n<p>The hardest part of creating patterns is getting the correct block markup. Here is the most reliable workflow:<\/p>\n\n<ol>\n<li><strong>Design the layout visually<\/strong> in the WordPress block editor. Add blocks, adjust settings, apply colors, set spacing \u2014 everything you want in the pattern<\/li>\n<li><strong>Switch to the Code Editor<\/strong> by clicking the three-dot menu in the top-right corner of the editor and selecting &#8220;Code editor&#8221;<\/li>\n<li><strong>Copy the entire block markup<\/strong> \u2014 this is what goes into the <code>content<\/code> property of your pattern<\/li>\n<li><strong>Paste it into your pattern file<\/strong> (either the PHP registration or the <code>patterns\/<\/code> file)<\/li>\n<li><strong>Replace specific content with placeholders<\/strong> \u2014 change &#8220;Our Company&#8221; to &#8220;Your Heading Here&#8221; so editors know what to customize<\/li>\n<\/ol>\n\n<p>This visual-first approach ensures your block markup is always valid. Writing block comments by hand is error-prone and unnecessary when the editor generates correct markup for you.<\/p>\n\n<h2>Synced Patterns: Shared Content Across Your Site<\/h2>\n\n<p>Synced patterns (formerly called reusable blocks) are different from regular patterns. When you edit a synced pattern, the changes appear everywhere that pattern is used. This is ideal for content that needs to stay consistent across your site:<\/p>\n\n<ul>\n<li><strong>Call-to-action banners<\/strong> that appear on multiple pages<\/li>\n<li><strong>Announcement bars<\/strong> for promotions or events<\/li>\n<li><strong>Standard disclaimers or legal notices<\/strong><\/li>\n<li><strong>Team bios or company info blocks<\/strong> used in footers and about pages<\/li>\n<\/ul>\n\n<h3>Creating Synced Patterns<\/h3>\n\n<p>In the editor, select one or more blocks, click the three-dot menu, and choose <strong>&#8220;Create pattern&#8221;<\/strong>. Toggle the <strong>&#8220;Synced&#8221;<\/strong> option to create a synced pattern. Give it a descriptive name and assign a category.<\/p>\n\n<p>Synced patterns are stored as <code>wp_block<\/code> posts in the database. You can manage them from <strong>Appearance > Editor > Patterns<\/strong> in the WordPress admin. From there you can edit, duplicate, or delete synced patterns.<\/p>\n\n<h2>Advanced: Dynamic Patterns with PHP<\/h2>\n\n<p>Because file-based patterns are PHP files, you can use PHP logic to create dynamic patterns. This is powerful for patterns that need to pull data from WordPress:<\/p>\n\n<pre class=\"wp-block-code\"><code>&lt;?php\n\/**\n * Title: Latest Posts Grid\n * Slug: mytheme\/latest-posts-grid\n * Categories: posts\n *\/\n\n$recent_posts = get_posts( array(\n    'numberposts' => 3,\n    'post_status' => 'publish',\n) );\n\nif ( empty( $recent_posts ) ) {\n    return;\n}\n?&gt;\n&lt;!-- wp:group {\"align\":\"wide\",\"layout\":{\"type\":\"constrained\"}} --&gt;\n&lt;div class=\"wp-block-group alignwide\"&gt;\n  &lt;!-- wp:heading --&gt;\n  &lt;h2 class=\"wp-block-heading\"&gt;Latest from Our Blog&lt;\/h2&gt;\n  &lt;!-- \/wp:heading --&gt;\n  &lt;!-- wp:columns --&gt;\n  &lt;div class=\"wp-block-columns\"&gt;\n    &lt;?php foreach ( $recent_posts as $post ) : ?&gt;\n    &lt;!-- wp:column --&gt;\n    &lt;div class=\"wp-block-column\"&gt;\n      &lt;!-- wp:heading {\"level\":3} --&gt;\n      &lt;h3 class=\"wp-block-heading\"&gt;&lt;?php echo esc_html( $post-&gt;post_title ); ?&gt;&lt;\/h3&gt;\n      &lt;!-- \/wp:heading --&gt;\n      &lt;!-- wp:paragraph --&gt;\n      &lt;p&gt;&lt;?php echo esc_html( wp_trim_words( $post-&gt;post_content, 20 ) ); ?&gt;&lt;\/p&gt;\n      &lt;!-- \/wp:paragraph --&gt;\n    &lt;\/div&gt;\n    &lt;!-- \/wp:column --&gt;\n    &lt;?php endforeach; ?&gt;\n  &lt;\/div&gt;\n  &lt;!-- \/wp:columns --&gt;\n&lt;\/div&gt;\n&lt;!-- \/wp:group --&gt;<\/code><\/pre>\n\n<p>Use dynamic patterns carefully. The PHP executes when the pattern is inserted, not on every page load. Once the blocks are in the content, they become static. For truly dynamic content, use the Query Loop block or custom dynamic blocks instead.<\/p>\n\n<h2>Using theme.json to Style Your Patterns<\/h2>\n\n<p>Your patterns inherit styles from <code>theme.json<\/code>. This means colors, typography, spacing, and layout settings defined in your theme&#8217;s global styles automatically apply to pattern blocks. To make your patterns look consistent with the rest of your theme:<\/p>\n\n<ul>\n<li>Use <strong>preset colors<\/strong> (like <code>has-primary-color<\/code>) instead of hardcoded hex values<\/li>\n<li>Use <strong>preset font sizes<\/strong> (like <code>has-large-font-size<\/code>) instead of pixel values<\/li>\n<li>Use <strong>spacing presets<\/strong> from your theme&#8217;s spacing scale instead of fixed padding and margin values<\/li>\n<\/ul>\n\n<p>This approach ensures that when someone changes the primary color in the Site Editor&#8217;s global styles, your patterns update automatically. Hardcoded values create patterns that look out of place when the theme styles change.<\/p>\n\n<h2>Pattern Best Practices<\/h2>\n\n<ul>\n<li><strong>Use descriptive names and keywords<\/strong> so editors can find patterns quickly in the inserter<\/li>\n<li><strong>Set appropriate <code>viewportWidth<\/code><\/strong> for each pattern so the preview in the inserter accurately represents the layout<\/li>\n<li><strong>Include placeholder content<\/strong> that makes it obvious what editors should replace (&#8220;Your Heading Here&#8221; instead of &#8220;Lorem Ipsum&#8221;)<\/li>\n<li><strong>Group related blocks<\/strong> inside a Group or Cover block so the entire pattern can be moved or deleted as one unit<\/li>\n<li><strong>Test patterns at multiple screen sizes<\/strong> \u2014 a pattern that looks great on desktop but breaks on mobile is not ready for production<\/li>\n<li><strong>Use the <code>patterns\/<\/code> directory<\/strong> for file-based patterns whenever possible \u2014 it is cleaner than <code>register_block_pattern()<\/code> calls in PHP<\/li>\n<li><strong>Prefer theme.json presets over hardcoded values<\/strong> for colors, fonts, and spacing so patterns adapt to style changes<\/li>\n<\/ul>\n\n<p>For deeper control over how patterns look, our guide on <a href=\"https:\/\/brndle.com\/global-styles-theme-json-block-theme-design\/\">configuring global styles in theme.json<\/a> covers the styles section, element-level styling, and CSS custom properties that your patterns inherit.\n\nBlock patterns are the bridge between a design system and the content editing experience. They give developers control over approved layouts while giving editors the freedom to customize content. Start with a few essential patterns \u2014 a hero section, a CTA bar, and a feature grid \u2014 and expand your library as your theme matures.<\/p>","protected":false},"excerpt":{"rendered":"<p>Learn how to create custom block patterns for WordPress block themes. Covers PHP registration, file-based patterns, synced vs unsynced patterns, pattern categories, and dynamic PHP patterns with theme.json integration.<\/p>\n","protected":false},"author":40,"featured_media":33094,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"rank_math_focus_keyword":"","rank_math_description":"","rank_math_title":"","rank_math_robots":"","rank_math_canonical_url":"","rank_math_breadcrumb_title":"","footnotes":""},"categories":[1],"tags":[4654,4649,4652],"class_list":["post-33092","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-block-theme-development","tag-block-themes","tag-theme-json"],"_links":{"self":[{"href":"https:\/\/brndle.com\/wp-json\/wp\/v2\/posts\/33092","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/brndle.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/brndle.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/brndle.com\/wp-json\/wp\/v2\/users\/40"}],"replies":[{"embeddable":true,"href":"https:\/\/brndle.com\/wp-json\/wp\/v2\/comments?post=33092"}],"version-history":[{"count":2,"href":"https:\/\/brndle.com\/wp-json\/wp\/v2\/posts\/33092\/revisions"}],"predecessor-version":[{"id":33095,"href":"https:\/\/brndle.com\/wp-json\/wp\/v2\/posts\/33092\/revisions\/33095"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/brndle.com\/wp-json\/wp\/v2\/media\/33094"}],"wp:attachment":[{"href":"https:\/\/brndle.com\/wp-json\/wp\/v2\/media?parent=33092"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/brndle.com\/wp-json\/wp\/v2\/categories?post=33092"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/brndle.com\/wp-json\/wp\/v2\/tags?post=33092"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}