Skip to content

Instantly share code, notes, and snippets.

@justintadlock
Last active May 29, 2024 16:02
Show Gist options
  • Save justintadlock/cfcdcdf47ea785e84c8575dddc68ea37 to your computer and use it in GitHub Desktop.
Save justintadlock/cfcdcdf47ea785e84c8575dddc68ea37 to your computer and use it in GitHub Desktop.
Virtual page templates with block support
<?php
// This filter specifically checks whether a theme has a `changelog` template.
// If not, it looks for a fallback template in the plugin.
add_filter( 'template_include', function( $template ) {
// I'm just testing a query string here for demonstration/testing
// purposes, but you'll want to add a check for your registered query
// var with WordPress. For now, you can test with `?changelog=anything`.
if ( ! isset( $_GET['changelog'] ) ) {
return $template;
}
// Custom hierarchy of templates.
$templates = [
'changelog.php',
'index.php'
];
// First, search for PHP templates, which block themes can also use.
$template = locate_template( $templates );
// Pass the result into the block template locator and let it figure
// out whether block templates are supported and this template exists.
$template = locate_block_template( $template, 'changelog', $templates );
// If the template is found, use it. Otherwise, fall back to the plugin
// template. It's worth noting that the wrapping block template markup
// and block processing wouldn't be available to the plugin template.
// The plugin would have to handle all of this on its end and probably
// add a few actions/filters that WP would normally add.
//
// I'd recommend digging through `wp-includes/template-canvas.php` and
// the `locate_block_template()` function for building this fallback.
return $template ?: '/path/to/plugin/fallback-template.php';
} );
// Filter the default template types, adding your own.
add_filter( 'default_template_types', function( $templates ) {
return array_merge( $templates, [
'changelog' => [
'title' => 'Changelog',
'description' => 'A custom changelog template.'
]
] );
} );
@justintadlock
Copy link
Author

Here's an example fallback template:

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
	<meta charset="<?php bloginfo( 'charset' ); ?>" />
	<?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>
<?php wp_body_open(); ?>

<?php
// Create some default block markup for parsing.
$content = <<< 'HTML'

<!-- wp:template-part {"slug":"header"} /-->

<!-- wp:group {"tagName":"main","style":{"spacing":{"padding":{"top":"var:preset|spacing|plus-5","bottom":"var:preset|spacing|plus-3"}}},"layout":{"type":"default"}} -->
<main class="wp-block-group" style="padding-top:var(--wp--preset--spacing--plus-5);padding-bottom:var(--wp--preset--spacing--plus-3)">

	<!-- wp:group {"tagName":"article","layout":{"type":"constrained"}} -->
	<article class="wp-block-group">

		<!-- wp:heading {"level":1} -->
		<h1 class="wp-block-heading">Fallback Changelog</h1>
		<!-- /wp:heading -->

	</article>
	<!-- /wp:group -->

</main>
<!-- /wp:group -->

<!-- wp:template-part {"slug":"footer"} /-->

HTML;

// Parse and output blocks.
echo do_blocks( $content ); ?>

<?php wp_footer(); ?>
</body>
</html>

@carolinan
Copy link

👋
Are the comments about needing to using *_block_template not relevant?
WordPress/gutenberg#42362

@justintadlock
Copy link
Author

justintadlock commented Mar 21, 2024

@carolinan - I'm not sure. This was a one-off that @ryanwelcher and I were exploring for a different project. As far as I know, he's been using a form of this successfully for a few months.

I definitely want to do a complete deep dive into this at some point to see if there are pieces that are missing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment