Creating templates for custom post types

Level: ,

Estimated reading time: 7 minutes

Several theme developers have reached out asking how to create full site editing templates for custom post types.

The good news is that unless something unexpected happens -there can always be last minute changes before a release, developers and users will be able to create templates for custom post types via the Site Editor in WordPress 6.1. ❤️
The feature is available today with the Gutenberg plugin enabled.

In this lesson I will briefly explain:

  • How to create templates for custom post types in the Site Editor
  • How to add file-based templates in your theme
  • How to add default blocks to the post type templates

Prerequisites: For the templates and the Site Editor options to be available, you must first register the custom post type. This Site Editor feature is only for creating the templates, not for creating custom post types from scratch.

Updated September 22, 2022.

How to create templates for custom post types using the Site Editor

To test this feature, please make sure that you have activated Gutenberg 14.1 or newer.

In the WordPress admin area, open the Site Editor by going to Appearance > Editor.
In the editor, open the navigation sidebar by clicking on the site logo or WordPress logo in the top left corner of the screen.
Open the template list and click on the “Add new” button in the top right corner:

List of templates on the Site Editor templates screen.

This opens up a scrollable modal window with a list of templates that you can create. Note that if a template already exists, it will not show in the list, then you need to edit (or delete) the existing template instead.

The example shows two custom post types: Book and Movie, and a custom taxonomy: Genre. From here you can create a template for the single item, the post type archive, and the taxonomy archive:

The "Add new" modal lists all the templates that you can create. It shows the template icon, name and description.

As an example, when you click on the “Single item: Book” option, you will be prompted to choose if you want to create a template for all books, or for a specific book:

The second step of adding a template displays a modal with two buttons. The button text is the post type name followed by the option description: "For all items", and "For a specific item".

If you select the option “For a specific item”, you will see a list of the book items that you have saved on your website, and you will be able to choose one:

When you create a template for a specific item, you are presented with a select list with the item title (post title), and also the link to that item.
You can select one item.

When you choose to create a single item, the editor copies the single post template and re-uses it. For post type and taxonomy archives, the editor creates a copy of the archive template.
Secondly, If the single or archive templates do not exist, WordPress falls back to using the next template in the template hierarchy, the index.

In the final step, the Site Editor opens the newly created template so that you can edit, add and remove the blocks.

File-based custom page templates

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

  • Use an HTML file if you want the site editor to list the template.
  • Use a PHP template file if you need to:
    • Use conditionals
    • Display meta box options
    • Check if a plugin is active before adding a plugin block to the template

Remember to place HTML templates in the templates folder and PHP templates in the themes root folder.

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

Adding default blocks to the block editor

Using register_post_type() to register a block template

Plugins can register a template when registering a custom post type. This feature has been available since WordPress 5.0.
This method adds blocks directly in the block editor when you create a new post type item.

Since these two template methods do different things, it is a bit unfortunate that they share the same name! Depending on what type of project you are working on, you would use both methods together.

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' );

Filtering the template argument for existing custom types

You can update the template argument of an existing custom post type by using a filter:

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. 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’s block.json file.

If you see errors in your template, try adding the block in the block 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) */

Adding default blocks with the default_content filter

Another way to display default blocks in the editor when you create a new post type item is to filter the content. You can read about the default_content filter in the WordPress code reference:

In this code example I am first checking if the post type is book, before adding the block markup to the $content variable.
I am adding the same content as in the previous example, a columns block with an image and a paragraph:

function prefix_filter_book_content( $content, $post ) {
	if ( $post->post_type === 'book' ) {
		$content ='<!-- 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:paragraph -->
		<!-- /wp:paragraph --></div>
		<!-- /wp:column --></div>
		<!-- /wp:columns -->';
	return $content;
add_filter( 'default_content', 'prefix_filter_book_content', 10, 2 );

– You can use other conditionals, for example checking for a specific author or post title.

Here I have created a new book item through the WordPress admin area, and the block editor has placed the selected blocks for me:

The block editor shows the book custom post type with the default columns block.

Further reading

Gutenberg GitHub issues related to full site editing templates for custom post types:
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:

New: An introduction to block templates by Nick Diego