Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add required logic for Block template themes #1267

Closed
wants to merge 57 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
fcb8068
Add block templates based theme fixtures from GB
ockham May 19, 2021
96146a8
Update names
ockham May 19, 2021
0a529e3
Add class-wp-rest-templates-controller.php
ockham May 20, 2021
808babb
Add templates controller test
ockham May 20, 2021
c7889f1
Add class-wp-block-template.php
ockham May 20, 2021
107e917
Register wp_template post type
ockham May 21, 2021
dac3189
Register wp_theme taxonomy
ockham May 21, 2021
26712c7
Add src/wp-admin/includes/templates-utils.php
ockham May 21, 2021
f991abe
Add src/wp-admin/theme-templates.php
ockham May 21, 2021
4ca78c2
Remove post type and taxonomy registration from theme-templates.php
ockham May 21, 2021
ba9f4ea
Add wp_template caps to src/wp-includes/post.php
ockham May 21, 2021
daeba90
Add src/wp-includes/block-templates.php
ockham May 21, 2021
fc62150
Add src/wp-includes/default-template-types.php
ockham May 21, 2021
ab6fa38
Add tests/phpunit/tests/block-templates.php
ockham May 21, 2021
c6a71b2
Move gutenberg_is_fse_theme and gutenberg_supports_block_templates to…
ockham May 21, 2021
832e464
Add custom block template support
ockham May 21, 2021
e9c64a4
Ugh, forgot to negate
ockham May 21, 2021
cc4393e
Uncomment theme.json specific criterion
ockham May 21, 2021
41db3dc
Remove now-obsolete test setup methods
ockham May 21, 2021
31c1ce6
Add src/wp-includes/block-template.php
ockham May 21, 2021
15d49d6
FSE: Remove now-obsolete get_template_hierarchy()
ockham May 21, 2021
0f3d157
Call block template loader directly, rather than adding filters
ockham May 21, 2021
d5d3277
Add src/template-canvas.php
ockham May 21, 2021
a543e57
Add tests/phpunit/tests/block-template.php
ockham May 21, 2021
19ed259
Fix block-template tests
ockham May 21, 2021
aa44958
Fix block-template implementation
ockham May 21, 2021
5b8f956
Load stuff
ockham May 21, 2021
9a4052d
Rename block-templates.php to block-template-loader.php to avoid conf…
ockham May 21, 2021
69e9c7a
Block Template Loader Test: Remove now-obsolete setup steps
ockham May 21, 2021
c283b49
Minor fix to block-template-loader.php test
ockham May 21, 2021
ff8a5e4
Rename test block template themes
ockham May 21, 2021
ba9c8d6
Load templates endpoint
ockham May 21, 2021
633e5c0
Some cleaning
youknowriad May 24, 2021
c9f5176
Add editor setting to enable template mode
youknowriad May 24, 2021
cf3cbd9
Add iframe assets
ellatrix May 24, 2021
ae960b0
Assign block templates to all post types
youknowriad May 24, 2021
fef992d
Remove template part related logic
youknowriad May 24, 2021
9c530a1
Rename theme_supports_block_templates
youknowriad May 24, 2021
0d0a58c
clean theme-templates.php
youknowriad May 24, 2021
3de35b0
clean block-template-utils
youknowriad May 24, 2021
e3ad830
clean block-template.php
youknowriad May 24, 2021
598c152
Remove default template types
youknowriad May 24, 2021
f2c95ab
Translations cleaning
youknowriad May 24, 2021
eec967e
Adding since
youknowriad May 24, 2021
0a5e4da
Remove testing theme and clean tests
youknowriad May 24, 2021
600db7c
Format changes
youknowriad May 24, 2021
2fc65d0
Fix unit tests
youknowriad May 24, 2021
0270bb2
more formatting issues
youknowriad May 24, 2021
8f6f435
Fix theme unit test
youknowriad May 24, 2021
595b6c8
Fix rest api test
youknowriad May 24, 2021
de87bd2
Move filters to default-filters.php
youknowriad May 24, 2021
575a506
no need for taxonomy in classic themes
youknowriad May 24, 2021
71d29fc
Fix capabilities
youknowriad May 25, 2021
e4ecc6b
Inline theme_supports_block_templates
ockham May 25, 2021
3471404
Make CPT registration unconditional
ockham May 25, 2021
cba7648
Make wp_theme taxonomy registration unconditional
ockham May 25, 2021
bf8d81e
Rename _strip_php_suffix to _strip_template_file_suffix
ockham May 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/wp-admin/edit-form-blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@
'supportsLayout' => WP_Theme_JSON_Resolver::theme_has_support(),
'__experimentalBlockPatterns' => WP_Block_Patterns_Registry::get_instance()->get_all_registered(),
'__experimentalBlockPatternCategories' => WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(),
'supportsTemplateMode' => current_theme_supports( 'block-templates' ),

// Whether or not to load the 'postcustom' meta box is stored as a user meta
// field so that we're not always loading its assets.
Expand Down
144 changes: 144 additions & 0 deletions src/wp-includes/block-template-utils.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php
/**
* Utilities used to fetch and create templates.
*
* @package WordPress
* @since 5.8.0
*/

/**
* Build a unified template object based a post Object.
*
* @access private
* @since 5.8.0
*
* @param WP_Post $post Template post.
*
* @return WP_Block_Template|WP_Error Template.
*/
function _build_template_result_from_post( $post ) {
$terms = get_the_terms( $post, 'wp_theme' );

if ( is_wp_error( $terms ) ) {
return $terms;
}

if ( ! $terms ) {
return new WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.' ) );
}

$theme = $terms[0]->name;

$template = new WP_Block_Template();
$template->wp_id = $post->ID;
$template->id = $theme . '//' . $post->post_name;
$template->theme = $theme;
$template->content = $post->post_content;
$template->slug = $post->post_name;
$template->source = 'custom';
$template->type = $post->post_type;
$template->description = $post->post_excerpt;
$template->title = $post->post_title;
$template->status = $post->post_status;
$template->has_theme_file = false;

return $template;
}

/**
* Retrieves a list of unified template objects based on a query.
*
* @since 5.8.0
*
* @param array $query {
* Optional. Arguments to retrieve templates.
*
* @type array $slug__in List of slugs to include.
* @type int $wp_id Post ID of customized template.
* }
* @param string $template_type wp_template.
*
* @return array Templates.
*/
function get_block_templates( $query = array(), $template_type = 'wp_template' ) {
$wp_query_args = array(
'post_status' => array( 'auto-draft', 'draft', 'publish' ),
'post_type' => $template_type,
'posts_per_page' => -1,
'no_found_rows' => true,
'tax_query' => array(
array(
'taxonomy' => 'wp_theme',
'field' => 'name',
'terms' => wp_get_theme()->get_stylesheet(),
),
),
);

if ( isset( $query['slug__in'] ) ) {
$wp_query_args['post_name__in'] = $query['slug__in'];
}

// This is only needed for the regular templates CPT listing and editor.
if ( isset( $query['wp_id'] ) ) {
$wp_query_args['p'] = $query['wp_id'];
} else {
$wp_query_args['post_status'] = 'publish';
}

$template_query = new WP_Query( $wp_query_args );
$query_result = array();
foreach ( $template_query->get_posts() as $post ) {
$template = _build_template_result_from_post( $post );

if ( ! is_wp_error( $template ) ) {
$query_result[] = $template;
}
}

return $query_result;
}

/**
* Retrieves a single unified template object using its id.
*
* @since 5.8.0
*
* @param string $id Template unique identifier (example: theme_slug//template_slug).
* @param string $template_type wp_template.
*
* @return WP_Block_Template|null Template.
*/
function get_block_template( $id, $template_type = 'wp_template' ) {
$parts = explode( '//', $id, 2 );
if ( count( $parts ) < 2 ) {
return null;
}
list( $theme, $slug ) = $parts;
$wp_query_args = array(
'post_name__in' => array( $slug ),
'post_type' => $template_type,
'post_status' => array( 'auto-draft', 'draft', 'publish', 'trash' ),
'posts_per_page' => 1,
'no_found_rows' => true,
'tax_query' => array(
array(
'taxonomy' => 'wp_theme',
'field' => 'name',
'terms' => $theme,
),
),
);
$template_query = new WP_Query( $wp_query_args );
$posts = $template_query->get_posts();

if ( count( $posts ) > 0 ) {
$template = _build_template_result_from_post( $posts[0] );

if ( ! is_wp_error( $template ) ) {
return $template;
}
}

return null;
}
228 changes: 228 additions & 0 deletions src/wp-includes/block-template.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
<?php
/**
* Block template loader functions.
*
* @package WordPress
*/

/**
* Find a block template with equal or higher specificity than a given PHP template file.
*
* Internally, this communicates the block content that needs to be used by the template canvas through a global variable.
*
* @since 5.8.0
*
* @param string $template Path to the template. See locate_template().
* @param string $type Sanitized filename without extension.
* @param array $templates A list of template candidates, in descending order of priority.
* @return string The path to the Full Site Editing template canvas file, or the fallback PHP template.
*/
function locate_block_template( $template, $type, array $templates ) {
global $_wp_current_template_content;

if ( $template ) {
// locate_template() has found a PHP template at the path specified by $template.
// That means that we have a fallback candidate if we cannot find a block template
// with higher specificity.
// Thus, before looking for matching block themes, we shorten our list of candidate
// templates accordingly.

// Locate the index of $template (without the theme directory path) in $templates.
$relative_template_path = str_replace(
array( get_stylesheet_directory() . '/', get_template_directory() . '/' ),
'',
$template
);
$index = array_search( $relative_template_path, $templates, true );

// If the template hiearchy algorithm has successfully located a PHP template file,
// we will only consider block templates with higher or equal specificity.
$templates = array_slice( $templates, 0, $index + 1 );
}

$block_template = resolve_block_template( $type, $templates );

if ( $block_template ) {
if ( empty( $block_template->content ) && is_user_logged_in() ) {
$_wp_current_template_content =
sprintf(
/* translators: %s: Template title */
__( 'Empty template: %s' ),
$block_template->title
);
} elseif ( ! empty( $block_template->content ) ) {
$_wp_current_template_content = $block_template->content;
}
if ( isset( $_GET['_wp-find-template'] ) ) {
wp_send_json_success( $block_template );
}
} else {
if ( $template ) {
return $template;
}

if ( 'index' === $type ) {
if ( isset( $_GET['_wp-find-template'] ) ) {
wp_send_json_error( array( 'message' => __( 'No matching template found.' ) ) );
}
} else {
return ''; // So that the template loader keeps looking for templates.
}
}

// Add hooks for template canvas.
// Add viewport meta tag.
add_action( 'wp_head', '_block_template_viewport_meta_tag', 0 );

// Render title tag with content, regardless of whether theme has title-tag support.
remove_action( 'wp_head', '_wp_render_title_tag', 1 ); // Remove conditional title tag rendering...
add_action( 'wp_head', '_block_template_render_title_tag', 1 ); // ...and make it unconditional.

// This file will be included instead of the theme's template file.
return ABSPATH . WPINC . '/template-canvas.php';
}

/**
* Return the correct 'wp_template' to render for the request template type.
*
* @access private
* @since 5.8.0
*
* Accepts an optional $template_hierarchy argument as a hint.
*
* @param string $template_type The current template type.
* @param string[] $template_hierarchy (optional) The current template hierarchy, ordered by priority.
* @return WP_Block_Template|null template A template object, or null if none could be found.
*/
function resolve_block_template( $template_type, $template_hierarchy ) {
if ( ! $template_type ) {
return null;
}

if ( empty( $template_hierarchy ) ) {
$template_hierarchy = array( $template_type );
}

$slugs = array_map(
'_strip_template_file_suffix',
$template_hierarchy
);

// Find all potential templates 'wp_template' post matching the hierarchy.
$query = array(
'theme' => wp_get_theme()->get_stylesheet(),
'slug__in' => $slugs,
);
$templates = get_block_templates( $query );

// Order these templates per slug priority.
// Build map of template slugs to their priority in the current hierarchy.
$slug_priorities = array_flip( $slugs );

usort(
$templates,
function ( $template_a, $template_b ) use ( $slug_priorities ) {
return $slug_priorities[ $template_a->slug ] - $slug_priorities[ $template_b->slug ];
}
);

return count( $templates ) ? $templates[0] : null;
}

/**
* Displays title tag with content, regardless of whether theme has title-tag support.
*
* @access private
* @since 5.8.0
*
* @see _wp_render_title_tag()
*/
function _block_template_render_title_tag() {
echo '<title>' . wp_get_document_title() . '</title>' . "\n";
}

/**
* Returns the markup for the current template.
*
* @access private
* @since 5.8.0
*
* @return string block tempate markup.
*/
function get_the_block_template_html() {
global $_wp_current_template_content;
global $wp_embed;

if ( ! $_wp_current_template_content ) {
if ( is_user_logged_in() ) {
return '<h1>' . esc_html__( 'No matching template found' ) . '</h1>';
}
return;
}

$content = $wp_embed->run_shortcode( $_wp_current_template_content );
$content = $wp_embed->autoembed( $content );
$content = do_blocks( $content );
$content = wptexturize( $content );
if ( function_exists( 'wp_filter_content_tags' ) ) {
$content = wp_filter_content_tags( $content );
} else {
$content = wp_make_content_images_responsive( $content );
}
$content = str_replace( ']]>', ']]&gt;', $content );

// Wrap block template in .wp-site-blocks to allow for specific descendant styles
// (e.g. `.wp-site-blocks > *`).
return '<div class="wp-site-blocks">' . $content . '</div>';
}

/**
* Renders a 'viewport' meta tag.
*
* @access private
* @since 5.8.0
*
* This is hooked into {@see 'wp_head'} to decouple its output from the default template canvas.
*/
function _block_template_viewport_meta_tag() {
echo '<meta name="viewport" content="width=device-width, initial-scale=1" />' . "\n";
}

/**
* Strips .php or .html suffix from template file names.
*
* @access private
* @since 5.8.0
*
* @param string $template_file Template file name.
* @return string Template file name without extension.
*/
function _strip_template_file_suffix( $template_file ) {
return preg_replace( '/\.(php|html)$/', '', $template_file );
}

/**
* Removes post details from block context when rendering a block template.
*
* @access private
* @since 5.8.0
*
* @param array $context Default context.
*
* @return array Filtered context.
*/
function _block_template_render_without_post_block_context( $context ) {
/*
* When loading a template directly and not through a page
* that resolves it, the top-level post ID and type context get set to that
* of the template. Templates are just the structure of a site, and
* they should not be available as post context because blocks like Post
* Content would recurse infinitely.
*/
if ( isset( $context['postType'] ) && 'wp_template' === $context['postType'] ) {
unset( $context['postId'] );
unset( $context['postType'] );
}

return $context;
}
Loading