Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Check block templates and parts directories to the Gutenberg 12.1.0 convention #5455

Merged
merged 10 commits into from
Dec 28, 2021
97 changes: 91 additions & 6 deletions src/Utils/BlockTemplateUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,42 @@
* IMPORTANT: These methods have been duplicated from Gutenberg/lib/full-site-editing/block-templates.php as those functions are not for public usage.
*/
class BlockTemplateUtils {
/**
* Old directory name of the block templates directory.
*
* The convention has changed with Gutenberg 12.1.0, but we need to keep this
* for backwards compatibility.
*
* @deprecated
* @var string
*/
const DEPRECATED_TEMPLATES_DIR_NAME = 'block-templates';

/**
* Old directory name of the block template parts directory.
*
* The convention has changed with Gutenberg 12.1.0, but we need to keep this
* for backwards compatibility.
*
* @deprecated
* @var string
*/
const DEPRECATED_TEMPLATE_PARTS_DIR_NAME = 'block-templates-parts';

/**
* Directory name of the block templates directory.
*
* @var string
*/
const TEMPLATES_DIR_NAME = 'templates';

/**
* Directory name of the block template parts directory.
*
* @var string
*/
const TEMPLATE_PARTS_DIR_NAME = 'parts';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not put these values in an associative array?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We 100% can. I was just following the pre-existing convention. Also, in the spirit of trying to avoid as many side-effects as possible, not changing that convention makes the PR slightly safer.

But I can convert those values in an associative array, if you so prefer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might make sense to put these in an associative array, I don't think it'll be too risky given the convention hasn't been set in this file.


/**
* Returns an array containing the references of
* the passed blocks and their inner blocks.
Expand Down Expand Up @@ -244,15 +280,65 @@ public static function generate_template_slug_from_path( $path, $directory_name
);
}

/**
* Gets the first matching template part within themes directories
*
* Since [Gutenberg 12.1.0](https://github.com/WordPress/gutenberg/releases/tag/v12.1.0), the conventions for
* block templates and parts directory has changed from `block-templates` and `block-templates-parts`
* to `templates` and `parts` respectively.
*
* This function traverses all possible combinations of directory paths where a template or part
* could be located and returns the first one which is readable, prioritizing the new convention
* over the deprecated one, but maintaining that one for backwards compatibility.
*
* @param string $template_slug The slug of the template (i.e. without the file extension).
* @param string $template_type Either `wp_template` or `wp_template_part`.
*
* @return string|null The matched path or `null` if no match was found.
*/
public static function get_theme_template_path( $template_slug, $template_type = 'wp_template' ) {
$template_filename = $template_slug . '.html';
$possible_templates_dir = 'wp_template' === $template_type ? array(
self::TEMPLATES_DIR_NAME,
self::DEPRECATED_TEMPLATES_DIR_NAME,
) : array(
self::TEMPLATE_PARTS_DIR_NAME,
self::DEPRECATED_TEMPLATE_PARTS_DIR_NAME,
);

// Combine the possible root directory names with either the template directory
// or the stylesheet directory for child themes.
$possible_paths = array_reduce(
tjcafferkey marked this conversation as resolved.
Show resolved Hide resolved
$possible_templates_dir,
function( $carry, $item ) use ( $template_filename ) {
$filepath = DIRECTORY_SEPARATOR . $item . DIRECTORY_SEPARATOR . $template_filename;

$carry[] = get_template_directory() . $filepath;
$carry[] = get_stylesheet_directory() . $filepath;
Comment on lines +301 to +302
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for being late on this one, but if I'm not wrong this is searching templates in this order:

  1. Parent theme templates folder.
  2. Child theme templates folder.
  3. Parent theme block-templates folder.
  4. Child theme block-templates folder.

But I think the child theme should always have priority. Something like this:

  1. Child theme templates folder.
  2. Child theme block-templates folder.
  3. Parent theme templates folder.
  4. Parent theme block-templates folder.

What do you think @sunyatasattva?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Aljullu Indeed this is correct! I'll open a PR to amend this! Thanks for spotting that.


return $carry;
},
array()
);

// Return the first matching.
foreach ( $possible_paths as $path ) {
if ( is_readable( $path ) ) {
return $path;
}
}

return null;
}

/**
* Check if the theme has a template. So we know if to load our own in or not.
*
* @param string $template_name name of the template file without .html extension e.g. 'single-product'.
* @return boolean
*/
public static function theme_has_template( $template_name ) {
return is_readable( get_template_directory() . '/block-templates/' . $template_name . '.html' ) ||
is_readable( get_stylesheet_directory() . '/block-templates/' . $template_name . '.html' );
return ! ! self::get_theme_template_path( $template_name, 'wp_template' );
}

/**
Expand All @@ -262,8 +348,7 @@ public static function theme_has_template( $template_name ) {
* @return boolean
*/
public static function theme_has_template_part( $template_name ) {
return is_readable( get_template_directory() . '/block-template-parts/' . $template_name . '.html' ) ||
is_readable( get_stylesheet_directory() . '/block-template-parts/' . $template_name . '.html' );
return ! ! self::get_theme_template_path( $template_name, 'wp_template_part' );
}

/**
Expand Down Expand Up @@ -311,8 +396,8 @@ public static function template_is_eligible_for_product_archive_fallback( $templ
*
* It returns `true` if anything was changed, `false` otherwise.
*
* @param array $query_result Array of template objects.
* @param array $template A specific template object which could have a fallback.
* @param array $query_result Array of template objects.
* @param object $template A specific template object which could have a fallback.
*
* @return boolean
*/
Expand Down