mirrored from git://develop.git.wordpress.org/
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
+1,825
−0
Closed
Changes from 53 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 96146a8
Update names
ockham 0a529e3
Add class-wp-rest-templates-controller.php
ockham 808babb
Add templates controller test
ockham c7889f1
Add class-wp-block-template.php
ockham 107e917
Register wp_template post type
ockham dac3189
Register wp_theme taxonomy
ockham 26712c7
Add src/wp-admin/includes/templates-utils.php
ockham f991abe
Add src/wp-admin/theme-templates.php
ockham 4ca78c2
Remove post type and taxonomy registration from theme-templates.php
ockham ba9f4ea
Add wp_template caps to src/wp-includes/post.php
ockham daeba90
Add src/wp-includes/block-templates.php
ockham fc62150
Add src/wp-includes/default-template-types.php
ockham ab6fa38
Add tests/phpunit/tests/block-templates.php
ockham c6a71b2
Move gutenberg_is_fse_theme and gutenberg_supports_block_templates to…
ockham 832e464
Add custom block template support
ockham e9c64a4
Ugh, forgot to negate
ockham cc4393e
Uncomment theme.json specific criterion
ockham 41db3dc
Remove now-obsolete test setup methods
ockham 31c1ce6
Add src/wp-includes/block-template.php
ockham 15d49d6
FSE: Remove now-obsolete get_template_hierarchy()
ockham 0f3d157
Call block template loader directly, rather than adding filters
ockham d5d3277
Add src/template-canvas.php
ockham a543e57
Add tests/phpunit/tests/block-template.php
ockham 19ed259
Fix block-template tests
ockham aa44958
Fix block-template implementation
ockham 5b8f956
Load stuff
ockham 9a4052d
Rename block-templates.php to block-template-loader.php to avoid conf…
ockham 69e9c7a
Block Template Loader Test: Remove now-obsolete setup steps
ockham c283b49
Minor fix to block-template-loader.php test
ockham ff8a5e4
Rename test block template themes
ockham ba9c8d6
Load templates endpoint
ockham 633e5c0
Some cleaning
youknowriad c9f5176
Add editor setting to enable template mode
youknowriad cf3cbd9
Add iframe assets
ellatrix ae960b0
Assign block templates to all post types
youknowriad fef992d
Remove template part related logic
youknowriad 9c530a1
Rename theme_supports_block_templates
youknowriad 0d0a58c
clean theme-templates.php
youknowriad 3de35b0
clean block-template-utils
youknowriad e3ad830
clean block-template.php
youknowriad 598c152
Remove default template types
youknowriad f2c95ab
Translations cleaning
youknowriad eec967e
Adding since
youknowriad 0a5e4da
Remove testing theme and clean tests
youknowriad 600db7c
Format changes
youknowriad 2fc65d0
Fix unit tests
youknowriad 0270bb2
more formatting issues
youknowriad 8f6f435
Fix theme unit test
youknowriad 595b6c8
Fix rest api test
youknowriad de87bd2
Move filters to default-filters.php
youknowriad 575a506
no need for taxonomy in classic themes
youknowriad 71d29fc
Fix capabilities
youknowriad e4ecc6b
Inline theme_supports_block_templates
ockham 3471404
Make CPT registration unconditional
ockham cba7648
Make wp_theme taxonomy registration unconditional
ockham bf8d81e
Rename _strip_php_suffix to _strip_template_file_suffix
ockham File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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_php_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( ']]>', ']]>', $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 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_php_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; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The naming isn't accurate here, since the line below also removes
.html
suffixes. We should either change the name, or the implementation. Since I only see one callsite which seems.php
specific, it might be okay to only remove.php
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's internal anyway, your call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I think the
.html
case is needed for custom page block templates. Renaming to_strip_template_file_suffix
in bf8d81e.