When developing projects, I often use Custom Post Types (CPT). In a new project, the content of the entries were build completely with core blocks. In the past, I typically used custom meta fields and a fixed page template. But as creating such a complex content of a CPT is quite a lot of work and error-prone, I wanted to use a template for new entries.
Creating a block pattern
The easiest way to create a pattern for a post type is by creating the content first using the block editor and then exporting the HTML markup using the “Copy all content” option:
Now you can use this markup to register a block pattern with the default content of new entries:
function cpt_register_block_pattern() {
register_block_pattern(
'my-cpt/my-cpt-pattern',
array(
'title' => __( 'My CPT pattern', 'my-cpt' ),
'description' => _x( 'The custom template for my_cpt', 'Block pattern description', 'my-cpt' ),
'content' => '
<!-- wp:paragraph {"placeholder":"Custom Post Type ..."} -->
<p></p>
<!-- /wp:paragraph -->
<!-- wp:columns -->
<div class="wp-block-columns"><!-- wp:column -->
<div class="wp-block-column"><!-- wp:image -->
<figure class="wp-block-image"><img alt=""/></figure>
<!-- /wp:image --></div>
<!-- /wp:column -->
<!-- wp:column -->
<div class="wp-block-column"><!-- wp:heading {"placeholder":"Name ..."} -->
<h2></h2>
<!-- /wp:heading -->
<!-- wp:paragraph {"placeholder":"Phone ..."} -->
<p></p>
<!-- /wp:paragraph --></div>
<!-- /wp:column --></div>
<!-- /wp:columns -->',
)
);
}
add_action( 'init', 'cpt_register_block_pattern' );
Creating a template for new entries
When registering a new CPT, you can can also create default content by passing a template
argument with a multidimensional array defining the template:
function cpt_register_post_type() {
register_post_type(
'my_cpt',
array(
'label' => __( 'Custom Post Type', 'my-cpt' ),
'supports' => array( 'title', 'editor' ),
'public' => true,
'show_ui' => true,
// ... other settings
'has_archive' => true,
'show_in_rest' => true,
'template' => array(
array(
'core/paragraph',
array(
'placeholder' => __( 'Custom Post Type ...', 'my-cpt' ),
),
),
array(
'core/columns',
array(),
array(
array(
'core/column',
array(),
array(
array(
'core/image',
),
),
),
array(
'core/column',
array(),
array(
array(
'core/heading',
array(
'level' => 2,
'placeholder' => __( 'Name ...', 'my-cpt' ),
),
),
array(
'core/paragraph',
array(
'placeholder' => __( 'Phone ...', 'my-cpt' ),
),
),
),
),
),
),
),
)
);
}
add_action( 'init', 'cpt_register_post_type' );
As you can see in this little example, the array can get very complex, unreadable and hard to maintain. You would also have to convert the Block Pattern HTML to this PHP array format. So any change to the pattern would require you to do the work twice, trying not to make any mistake.
Combining Block Patterns and Custom Post Types templates
As the solution with the PHP array was not really something I wanted to use (the actual template was a lot more complex than the one shown in the example), I first tried the following:
// ...
'template' => array(
array(
'my-cpt/my-cpt-pattern',
),
),
// ...
I thought, that maybe the template
can also use Block Patterns in the array and not only blocks. But this didn’t work. When searching for a solution, I found multiple issues on GitHub. There I found the core/pattern
block, which makes the task very easy:
'template' => array(
array(
'core/pattern',
array(
'slug' => 'my-cpt/my-cpt-pattern',
),
),
),
Unfortunately, the core/pattern
block is not available in WordPress 5.8, but you can already use it with the Gutenberg plugin installed and activated. I really hope that it’s going to be available with WordPress 5.9 expected next month.
Conclusion
Both Block Patterns and templates for new Custom Post Type entries are really helpful. Combining them with the new core/pattern block can really increase usability a lot.
This is great and love the core/pattern solution, but unfortunately doesn’t seem to work with template_lock. Do you know if there is a way?
I don’t know if this is possible and I have not tried it out myself. Maybe when the feature get’s merged into WordPress 4.9 it would be posssible.
Still works like a charm 18 months later. “Copy all content” is now called “Copy all blocks”.
Thanks, Bernhard!
P.S.: I had to escape some characters like quotation marks from a SyntaxHighlighter Evolved block with hello world code in it, which would have otherwise broken the string in ‘content’ => ‘markup string’.