wp/wp-includes/block-template.php
changeset 18 be944660c56a
child 19 3d72ae0968f4
equal deleted inserted replaced
17:34716fd837a4 18:be944660c56a
       
     1 <?php
       
     2 /**
       
     3  * Block template loader functions.
       
     4  *
       
     5  * @package WordPress
       
     6  */
       
     7 
       
     8 /**
       
     9  * Find a block template with equal or higher specificity than a given PHP template file.
       
    10  *
       
    11  * Internally, this communicates the block content that needs to be used by the template canvas through a global variable.
       
    12  *
       
    13  * @since 5.8.0
       
    14  *
       
    15  * @global string $_wp_current_template_content
       
    16  *
       
    17  * @param string $template  Path to the template. See locate_template().
       
    18  * @param string $type      Sanitized filename without extension.
       
    19  * @param array  $templates A list of template candidates, in descending order of priority.
       
    20  * @return string The path to the Full Site Editing template canvas file, or the fallback PHP template.
       
    21  */
       
    22 function locate_block_template( $template, $type, array $templates ) {
       
    23 	global $_wp_current_template_content;
       
    24 
       
    25 	if ( $template ) {
       
    26 		/*
       
    27 		 * locate_template() has found a PHP template at the path specified by $template.
       
    28 		 * That means that we have a fallback candidate if we cannot find a block template
       
    29 		 * with higher specificity.
       
    30 		 *
       
    31 		 * Thus, before looking for matching block themes, we shorten our list of candidate
       
    32 		 * templates accordingly.
       
    33 		 */
       
    34 
       
    35 		// Locate the index of $template (without the theme directory path) in $templates.
       
    36 		$relative_template_path = str_replace(
       
    37 			array( get_stylesheet_directory() . '/', get_template_directory() . '/' ),
       
    38 			'',
       
    39 			$template
       
    40 		);
       
    41 		$index                  = array_search( $relative_template_path, $templates, true );
       
    42 
       
    43 		// If the template hiearchy algorithm has successfully located a PHP template file,
       
    44 		// we will only consider block templates with higher or equal specificity.
       
    45 		$templates = array_slice( $templates, 0, $index + 1 );
       
    46 	}
       
    47 
       
    48 	$block_template = resolve_block_template( $type, $templates );
       
    49 
       
    50 	if ( $block_template ) {
       
    51 		if ( empty( $block_template->content ) && is_user_logged_in() ) {
       
    52 			$_wp_current_template_content =
       
    53 			sprintf(
       
    54 				/* translators: %s: Template title */
       
    55 				__( 'Empty template: %s' ),
       
    56 				$block_template->title
       
    57 			);
       
    58 		} elseif ( ! empty( $block_template->content ) ) {
       
    59 			$_wp_current_template_content = $block_template->content;
       
    60 		}
       
    61 		if ( isset( $_GET['_wp-find-template'] ) ) {
       
    62 			wp_send_json_success( $block_template );
       
    63 		}
       
    64 	} else {
       
    65 		if ( $template ) {
       
    66 			return $template;
       
    67 		}
       
    68 
       
    69 		if ( 'index' === $type ) {
       
    70 			if ( isset( $_GET['_wp-find-template'] ) ) {
       
    71 				wp_send_json_error( array( 'message' => __( 'No matching template found.' ) ) );
       
    72 			}
       
    73 		} else {
       
    74 			return ''; // So that the template loader keeps looking for templates.
       
    75 		}
       
    76 	}
       
    77 
       
    78 	// Add hooks for template canvas.
       
    79 	// Add viewport meta tag.
       
    80 	add_action( 'wp_head', '_block_template_viewport_meta_tag', 0 );
       
    81 
       
    82 	// Render title tag with content, regardless of whether theme has title-tag support.
       
    83 	remove_action( 'wp_head', '_wp_render_title_tag', 1 );    // Remove conditional title tag rendering...
       
    84 	add_action( 'wp_head', '_block_template_render_title_tag', 1 ); // ...and make it unconditional.
       
    85 
       
    86 	// This file will be included instead of the theme's template file.
       
    87 	return ABSPATH . WPINC . '/template-canvas.php';
       
    88 }
       
    89 
       
    90 /**
       
    91  * Return the correct 'wp_template' to render for the request template type.
       
    92  *
       
    93  * @access private
       
    94  * @since 5.8.0
       
    95  *
       
    96  * @param string   $template_type      The current template type.
       
    97  * @param string[] $template_hierarchy The current template hierarchy, ordered by priority.
       
    98  * @return WP_Block_Template|null template A template object, or null if none could be found.
       
    99  */
       
   100 function resolve_block_template( $template_type, $template_hierarchy ) {
       
   101 	if ( ! $template_type ) {
       
   102 		return null;
       
   103 	}
       
   104 
       
   105 	if ( empty( $template_hierarchy ) ) {
       
   106 		$template_hierarchy = array( $template_type );
       
   107 	}
       
   108 
       
   109 	$slugs = array_map(
       
   110 		'_strip_template_file_suffix',
       
   111 		$template_hierarchy
       
   112 	);
       
   113 
       
   114 	// Find all potential templates 'wp_template' post matching the hierarchy.
       
   115 	$query     = array(
       
   116 		'theme'    => wp_get_theme()->get_stylesheet(),
       
   117 		'slug__in' => $slugs,
       
   118 	);
       
   119 	$templates = get_block_templates( $query );
       
   120 
       
   121 	// Order these templates per slug priority.
       
   122 	// Build map of template slugs to their priority in the current hierarchy.
       
   123 	$slug_priorities = array_flip( $slugs );
       
   124 
       
   125 	usort(
       
   126 		$templates,
       
   127 		function ( $template_a, $template_b ) use ( $slug_priorities ) {
       
   128 			return $slug_priorities[ $template_a->slug ] - $slug_priorities[ $template_b->slug ];
       
   129 		}
       
   130 	);
       
   131 
       
   132 	return count( $templates ) ? $templates[0] : null;
       
   133 }
       
   134 
       
   135 /**
       
   136  * Displays title tag with content, regardless of whether theme has title-tag support.
       
   137  *
       
   138  * @access private
       
   139  * @since 5.8.0
       
   140  *
       
   141  * @see _wp_render_title_tag()
       
   142  */
       
   143 function _block_template_render_title_tag() {
       
   144 	echo '<title>' . wp_get_document_title() . '</title>' . "\n";
       
   145 }
       
   146 
       
   147 /**
       
   148  * Returns the markup for the current template.
       
   149  *
       
   150  * @access private
       
   151  * @since 5.8.0
       
   152  *
       
   153  * @global string   $_wp_current_template_content
       
   154  * @global WP_Embed $wp_embed
       
   155  *
       
   156  * @return string Block template markup.
       
   157  */
       
   158 function get_the_block_template_html() {
       
   159 	global $_wp_current_template_content;
       
   160 	global $wp_embed;
       
   161 
       
   162 	if ( ! $_wp_current_template_content ) {
       
   163 		if ( is_user_logged_in() ) {
       
   164 			return '<h1>' . esc_html__( 'No matching template found' ) . '</h1>';
       
   165 		}
       
   166 		return;
       
   167 	}
       
   168 
       
   169 	$content = $wp_embed->run_shortcode( $_wp_current_template_content );
       
   170 	$content = $wp_embed->autoembed( $content );
       
   171 	$content = do_blocks( $content );
       
   172 	$content = wptexturize( $content );
       
   173 	$content = wp_filter_content_tags( $content );
       
   174 	$content = str_replace( ']]>', ']]&gt;', $content );
       
   175 
       
   176 	// Wrap block template in .wp-site-blocks to allow for specific descendant styles
       
   177 	// (e.g. `.wp-site-blocks > *`).
       
   178 	return '<div class="wp-site-blocks">' . $content . '</div>';
       
   179 }
       
   180 
       
   181 /**
       
   182  * Renders a 'viewport' meta tag.
       
   183  *
       
   184  * This is hooked into {@see 'wp_head'} to decouple its output from the default template canvas.
       
   185  *
       
   186  * @access private
       
   187  * @since 5.8.0
       
   188  */
       
   189 function _block_template_viewport_meta_tag() {
       
   190 	echo '<meta name="viewport" content="width=device-width, initial-scale=1" />' . "\n";
       
   191 }
       
   192 
       
   193 /**
       
   194  * Strips .php or .html suffix from template file names.
       
   195  *
       
   196  * @access private
       
   197  * @since 5.8.0
       
   198  *
       
   199  * @param string $template_file Template file name.
       
   200  * @return string Template file name without extension.
       
   201  */
       
   202 function _strip_template_file_suffix( $template_file ) {
       
   203 	return preg_replace( '/\.(php|html)$/', '', $template_file );
       
   204 }
       
   205 
       
   206 /**
       
   207  * Removes post details from block context when rendering a block template.
       
   208  *
       
   209  * @access private
       
   210  * @since 5.8.0
       
   211  *
       
   212  * @param array $context Default context.
       
   213  *
       
   214  * @return array Filtered context.
       
   215  */
       
   216 function _block_template_render_without_post_block_context( $context ) {
       
   217 	/*
       
   218 	 * When loading a template directly and not through a page that resolves it,
       
   219 	 * the top-level post ID and type context get set to that of the template.
       
   220 	 * Templates are just the structure of a site, and they should not be available
       
   221 	 * as post context because blocks like Post Content would recurse infinitely.
       
   222 	 */
       
   223 	if ( isset( $context['postType'] ) && 'wp_template' === $context['postType'] ) {
       
   224 		unset( $context['postId'] );
       
   225 		unset( $context['postType'] );
       
   226 	}
       
   227 
       
   228 	return $context;
       
   229 }