How to use PHP templates in block themes

Level: ,

Estimated reading time: 6 minutes

In the introduction to creating block themes, I mentioned that if WordPress can not find a matching .html file, it tries to find a .php version of that file. For theme developers, this means that you can use PHP in situations where full site editing is not mature enough; For example to cover features that are not available yet.
In this lesson, I will give you an example of a PHP template for a block theme that uses the header and footer template parts and also displays the blocks from the page content.

Updated September 22, 2022, for Gutenberg version 14.1

Things to consider when adding PHP templates

There are three main things that come to mind when you want to use PHP in block themes instead of using HTML block templates:

  • PHP template files are not editable in the Site Editor or template editor.
  • You must include the necessary WordPress hooks, <HTML> and <body> markup (these are automatically included for the HTML template files).
  • You can use do_blocks() to render blocks.
  • By using existing template parts for header and footer, the user can manage the navigation in the header by editing the template part directly.

For this example, I will continue using the theme that we created in the previous lessons. You can download the sample theme with the basic templates and theme.json from GitHub.

First, install and activate the theme and open the theme files in your code editor.

  • If you are creating a page template, place your file in the themes root folder.
  • If you are replacing a template in the template hierarchy, you have to place it inside the themes templates folder. Otherwise, WordPress will not recognize that it as part of the template hierarchy, and it will not work.

I have chosen to create a custom template that can be assigned to a page.
First, create a new .php file in the root directory called example-page.php. At the top of the file, add the template name file header:

<?php
/*
Template Name: Example
*/
?>

If you plan to use more than one PHP template, create separate footer and header parts that you can reuse. For the sake of simplicity, I am going to add the hooks directly in the file.

This is a standard template that includes the wp_head, body_class, wp_body_open, and wp_footer hooks. For consistency, I have added the same wrapping div that is used in the HTML templates, with the CSS class wp-site-blocks. The meta tag I have used in the <head> is only an example:

<?php
/*
Template Name: Example
*/
?>
<!doctype html>
<html <?php language_attributes(); ?>>
<head>
	<meta charset="<?php bloginfo( 'charset' ); ?>">
	<?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<div class="wp-site-blocks">


</div>
<?php wp_footer(); ?>

</body>
</html>

How to render blocks in PHP templates

To render block markup as blocks and not as HTML comments, you need to wrap the code inside a PHP function called do_blocks();

The function uses one parameter, which is the string that contains the content that the function needs to parse. You can use do_blocks() to render any block or a combination of blocks.
You can render more than one block in the same call.
Note that you can not split blocks: The opening and closing tag must be in the same do_blocks() function call.

WordPress 5.9 also adds three new functions specifically for rendering the content of template parts:

  • block_template_part() which accepts one parameter, $part, the slug of the selected template part. This function is a wrapper for do_blocks(), and echoes the content of the template part.
  • A wrapper for block_template_part() called block_header_area(), which prints a template part called ‘header’.
  • A wrapper for block_template_part() called block_footer_area(), which prints a template part called ‘footer’.

The key differences that I recommend you to remember is that:

  • do_blocks() returns the block markup that you place inside the function, and you need to output the result yourself, for example with echo.
  • block_template_part() echoes the content of the template part. It fetches the content of the template part, runs it through do_blocks(), and then echoes it.

Example of adding the footer and header template parts:

<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<div class="wp-site-blocks">
<header class="wp-block-template-part site-header">
<?php block_header_area(); ?>
</header>

<footer class="wp-block-template-part site-footer">
<?php block_footer_area(); ?>
</footer>
</div>
<?php wp_footer(); ?>
</body>

Making sure that WordPress loads the block CSS

In version 6.0, WordPress changed the way it loads the block support CSS:

  • In classic PHP based themes, the CSS is loaded in the body
  • In block themes, the CSS is loaded in the head

Related pull requests in the Gutenberg GitHub repository: #39164 #38750

This means that if you use do_blocks() after wp_head(), WordPress does not load the block CSS.

Instead, you need to place the block markup in do_blocks() above wp_head(), and then echo it in the template body.

In the example below I have moved the main element with the search results query inside a new variable that I named block_content:

<head>
	<meta charset="<?php bloginfo( 'charset' ); ?>">
	<?php
	$block_content = do_blocks( '
		<!-- wp:group {"layout":{"type":"constrained"}} -->
		<div class="wp-block-group">
		<!-- wp:post-content /-->
		</div>
		<!-- /wp:group -->'
 	);
 	?>
	<?php wp_head(); ?>
</head>

And next I echo the rendered blocks in the body:

<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<div class="wp-site-blocks">

<header class="wp-block-template-part site-header">
<?php block_header_area(); ?>
</header>
<?php echo $block_content; ?>
<footer class="wp-block-template-part site-footer">
<?php block_footer_area(); ?>
</footer>
</div>
<?php wp_footer(); ?>
</body>

Using template parts inside do_blocks()

If you want to include a template part including the wrapper directly inside do_blocks() instead of using the block tempalte part function, you need to add the theme attribute to the markup. Use your theme slug as the value:

<!-- wp:template-part {"slug":"comments","theme":"fse"} /-->

Extending the template with PHP

Now you have an example template that displays the site header and footer and the block content of the assigned page.
You can combine this with any PHP functionality that you need, for example, displaying block content conditionally, display data from post meta fields, or support a plugin. You could display different blocks for logged in users, or for users with a specific user role.

Remember that when you add HTML elements that are not blocks to the page, you need to load additional CSS to style them.

Conclusion

Using a PHP template with and without rendering blocks works well in full site editing themes, as long as you don’t need the template to be editable in the Site Editor.

If you are creating a template using PHP only because there is a feature that you need that you can not build with WordPress core blocks, -consider creating a custom block so that you can use the same format for all your templates.