Skip to content

Commit

Permalink
FSE: Add template loader unit tests (#31498)
Browse files Browse the repository at this point in the history
The block template resolution algorithm is quite complex, as it has to cover quite a lot of different possible cases resulting from various combinations of
- WP's "old" template hierarchy (including custom page templates, and child themes)
- block templates.

Things become especially complex when there are e.g. "oldschool" PHP templates with higher specificity than the available block templates; or when a child theme has a PHP template with equal specificity as the parent theme's corresponding block template.

For more discussion on this, see #31399. Examples of previous iterations that sought to refine the algorithms' behavior include #29026, #30599, #31123, and #31336. This PR's goal is to eventually cover all of those cases.
  • Loading branch information
ockham authored May 12, 2021
1 parent 2a33806 commit 75e05c7
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 0 deletions.
197 changes: 197 additions & 0 deletions phpunit/class-template-loader-test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
<?php
/**
* Template_Loader_Test class
*
* @package WordPress
*/

/**
* Tests for the block template loading algorithm.
*/
class Template_Loader_Test extends WP_UnitTestCase {
private static $post;
private static $template_part_post;

public static function wpSetUpBeforeClass() {
register_theme_directory( __DIR__ . '/fixtures/themes/' );

// Without this filter, get_template_directory() would erroneously return the default theme path
// (wp-content/themes/) for `test-theme` (rather than ./fixtures/themes/). Maybe a WP bug?
add_filter( 'template_directory', array( __CLASS__, 'change_theme_directory' ), 10, 2 );
add_filter( 'stylesheet_directory', array( __CLASS__, 'change_theme_directory' ), 10, 2 );

switch_theme( 'test-theme' );
gutenberg_register_template_post_type();
gutenberg_register_template_part_post_type();
gutenberg_register_wp_theme_taxonomy();
gutenberg_register_wp_template_part_area_taxonomy();

// Set up custom template post.
$args = array(
'post_type' => 'wp_template',
'post_name' => 'wp-custom-template-my-block-template',
'post_title' => 'My Custom Block Template',
'post_content' => 'Content',
'post_excerpt' => 'Description of my block template',
'tax_input' => array(
'wp_theme' => array(
get_stylesheet(),
),
),
);
self::$post = self::factory()->post->create_and_get( $args );
wp_set_post_terms( self::$post->ID, get_stylesheet(), 'wp_theme' );
}

public static function wpTearDownAfterClass() {
wp_delete_post( self::$post->ID );
remove_filter( 'stylesheet_directory', array( __CLASS__, 'change_theme_directory' ) );
remove_filter( 'template_directory', array( __CLASS__, 'change_theme_directory' ) );
}

public function tearDown() {
global $_wp_current_template_content;
unset( $_wp_current_template_content );
}

function test_gutenberg_page_home_block_template_takes_precedence_over_less_specific_block_templates() {
global $_wp_current_template_content;
$type = 'page';
$templates = array(
'page-home.php',
'page-1.php',
'page.php',
);
$resolved_template_path = gutenberg_override_query_template( get_stylesheet_directory() . '/page-home.php', $type, $templates );
$this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path );
$this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page-home.html', $_wp_current_template_content );
}

function test_gutenberg_page_block_template_takes_precedence() {
global $_wp_current_template_content;
$type = 'page';
$templates = array(
'page-slug-doesnt-exist.php',
'page-1.php',
'page.php',
);
$resolved_template_path = gutenberg_override_query_template( get_stylesheet_directory() . '/page.php', $type, $templates );
$this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path );
$this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page.html', $_wp_current_template_content );
}

function test_gutenberg_block_template_takes_precedence_over_equally_specific_php_template() {
global $_wp_current_template_content;
$type = 'index';
$templates = array(
'index.php',
);
$resolved_template_path = gutenberg_override_query_template( get_stylesheet_directory() . '/index.php', $type, $templates );
$this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path );
$this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/index.html', $_wp_current_template_content );
}

/**
* In a hybrid theme, a PHP template of higher specificity will take precedence over a block template
* with lower specificity.
*
* Covers https://github.com/WordPress/gutenberg/pull/29026.
*/
function test_gutenberg_more_specific_php_template_takes_precedence_over_less_specific_block_template() {
$page_id_template = 'page-1.php';
$page_id_template_path = get_stylesheet_directory() . '/' . $page_id_template;
$type = 'page';
$templates = array(
'page-slug-doesnt-exist.php',
'page-1.php',
'page.php',
);
$resolved_template_path = gutenberg_override_query_template( $page_id_template_path, $type, $templates );
$this->assertEquals( $page_id_template_path, $resolved_template_path );
}

/**
* If a theme is a child of a block-based parent theme but has php templates for some of its pages,
* a php template of the child will take precedence over the parent's block template if they have
* otherwise equal specificity.
*
* Covers https://github.com/WordPress/gutenberg/pull/31123.
*/
function test_gutenberg_child_theme_php_template_takes_precedence_over_equally_specific_parent_theme_block_template() {
switch_theme( 'test-theme-child' );

$page_slug_template = 'page-home.php';
$page_slug_template_path = get_stylesheet_directory() . '/' . $page_slug_template;
$type = 'page';
$templates = array(
'page-home.php',
'page-1.php',
'page.php',
);
$resolved_template_path = gutenberg_override_query_template( $page_slug_template_path, $type, $templates );
$this->assertEquals( $page_slug_template_path, $resolved_template_path );

switch_theme( 'test-theme' );
}

function test_gutenberg_child_theme_block_template_takes_precedence_over_equally_specific_parent_theme_php_template() {
global $_wp_current_template_content;

switch_theme( 'test-theme-child' );

$page_template = 'page-1.php';
$parent_theme_page_template_path = get_template_directory() . '/' . $page_template;
$type = 'page';
$templates = array(
'page-slug-doesnt-exist.php',
'page-1.php',
'page.php',
);
$resolved_template_path = gutenberg_override_query_template( $parent_theme_page_template_path, $type, $templates );
$this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path );
$this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page-1.html', $_wp_current_template_content );

switch_theme( 'test-theme' );
}

/**
* Regression: https://github.com/WordPress/gutenberg/issues/31399.
*/
function test_gutenberg_custom_page_php_template_takes_precedence_over_all_other_templates() {
$custom_page_template = 'templates/full-width.php';
$custom_page_template_path = get_stylesheet_directory() . '/' . $custom_page_template;
$type = 'page';
$templates = array(
$custom_page_template,
'page-slug.php',
'page-1.php',
'page.php',
);
$resolved_template_path = gutenberg_override_query_template( $custom_page_template_path, $type, $templates );
$this->assertEquals( $custom_page_template_path, $resolved_template_path );
}

/**
* Covers: https://github.com/WordPress/gutenberg/pull/30438.
*/
function test_gutenberg_custom_page_block_template_takes_precedence_over_all_other_templates() {
global $_wp_current_template_content;

$custom_page_block_template = 'wp-custom-template-my-block-template';
$page_template_path = get_stylesheet_directory() . '/' . 'page.php';
$type = 'page';
$templates = array(
$custom_page_block_template,
'page-slug.php',
'page-1.php',
'page.php',
);
$resolved_template_path = gutenberg_override_query_template( $page_template_path, $type, $templates );
$this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path );
$this->assertEquals( self::$post->post_content, $_wp_current_template_content );
}

static function change_theme_directory( $theme_dir, $theme ) {
return __DIR__ . '/fixtures/themes/' . $theme;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- wp:paragraph -->
<p>Page (ID 1) Template</p>
<!-- /wp:paragraph -->
3 changes: 3 additions & 0 deletions phpunit/fixtures/themes/test-theme-child/page-home.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

echo 'PHP template for page with slug "home"';
4 changes: 4 additions & 0 deletions phpunit/fixtures/themes/test-theme-child/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*
Theme Name: Test Theme Child
Template: test-theme
*/
3 changes: 3 additions & 0 deletions phpunit/fixtures/themes/test-theme/block-templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- wp:paragraph -->
<p>Index Template</p>
<!-- /wp:paragraph -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- wp:paragraph -->
<p>Page (Home) Template</p>
<!-- /wp:paragraph -->
3 changes: 3 additions & 0 deletions phpunit/fixtures/themes/test-theme/block-templates/page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- wp:paragraph -->
<p>Page Template</p>
<!-- /wp:paragraph -->
3 changes: 3 additions & 0 deletions phpunit/fixtures/themes/test-theme/page-1.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

echo 'PHP template for page with ID 1';
3 changes: 3 additions & 0 deletions phpunit/fixtures/themes/test-theme/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/*
Theme Name: Test Theme
*/

0 comments on commit 75e05c7

Please sign in to comment.