Creating block templates for custom post types

Level: Intermediate, developer

Estimated reading time: 3 minutes

Several theme developers have reached out to me asking how to create block templates for custom post types. The main pain point is that people are expecting to be able to create this type of template via the new Site Editor interface. This is a reasonable expectation, unfortunately the feature is not complete yet and not included in WordPress 5.9.0.

Updated: January 2, 2022.

Different ways to create block templates without the Site Editor

There are basically three ways to create block templates for custom post types programmatically:

  • By adding a full site editing HTML template file for the post type, matching the template hierarchy. You can assign and edit this template in the template editor and site editor.
  • By adding a traditional PHP template file for the post type, matching the template hierarchy. You can assign this template to your new content, but not edit the template in the template editor.
  • By adding a block template when registering the post type, or by filtering the post type template argument. You can not edit this template in the template editor or site editor.

Creating file based block templates

The only difference between creating a block template for a default post type and a custom, is the naming of the file. If your custom post type is called “books”, you need to name the template singe-books.html.

Remember that you need to place HTML templates in the templates folder, and PHP templates in the themes root folder.

Use an HTML file if you want the site editor to list the template. Use a PHP template if you need to check if a plugin is active before adding a plugin block.

You can read more in the official documentation in the theme developer handbook:

Registering a block template

Plugins can register a block template when registering a custom post type. This feature has been available since WordPress 5.0. Before full site editing, this was the only way to create a block template.

The template argument in the PHP function register_post_type() accepts blocks and block settings in the form of a nested array:

function myplugin_register_book_post_type() {
    $args = array(
        'public' => true,
        'label'  => 'Books',
        'show_in_rest' => true,
        'template' => array(
            array( 'core/columns', array(), array(
                array( 'core/column', array(), array(
                    array( 'core/image', array() ),
                ) ),
                array( 'core/column', array(), array(
                    array( 'core/paragraph', array(
                        'placeholder' => 'Add a inner paragraph'
                    ) ),
                ) ),
            ) )
        ),
    );
    register_post_type( 'book', $args );
}
add_action( 'init', 'myplugin_register_book_post_type' );

Note: Themes in the WordPress.org theme directory are not allowed to register custom post types.

Filtering templates for existing custom types

You can add a block template to an existing custom post type by filtering the template argument:

function myplugin_register_template() {
    $post_type_object = get_post_type_object( 'book' );
    $post_type_object->template = array(
        array( 'core/image' ),
    );
}
add_action( 'init', 'myplugin_register_template' );

Troubleshooting tips

In my experience, adding these nested arrays correctly can be a bit difficult at first. The array structure is the same as for a parsed block. The block name is a string, while the attributes and the inner blocks are arrays.
-To find out which attributes a block supports, look through the block reference or the block.json file.

If you are seeing errors in your template, try creating the block in the editor, copy the markup, and run it through parse_blocks(). Print the result of parse_blocks() and compare the array with your template.

array ( 
    0 => array ( 
        'blockName' => 'core/paragraph', 
        'attrs' => array ( 
            'textColor' => 'vivid-red', 
            'backgroundColor' => 'luminous-vivid-amber',
        ), 
        'innerBlocks' => array (
            /* Child blocks if they exists (used in Column Block for example) */
        )
    ),
)

Further reading

Gutenberg GitHub issues:
Expand the types of templates that can be added in the Site Editor
Create Block Template from copied block content
Using Patterns in Templates

Preview of templates for WooCommerce: https://developer.woocommerce.com/2021/11/22/woocommerce-blocks-6-3-2-release-notes/