[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Block template loader functions. 4 * 5 * @package WordPress 6 */ 7 8 /** 9 * Adds necessary filters to use 'wp_template' posts instead of theme template files. 10 * 11 * @access private 12 * @since 5.9.0 13 */ 14 function _add_template_loader_filters() { 15 if ( ! current_theme_supports( 'block-templates' ) ) { 16 return; 17 } 18 19 $template_types = array_keys( get_default_block_template_types() ); 20 foreach ( $template_types as $template_type ) { 21 // Skip 'embed' for now because it is not a regular template type. 22 if ( 'embed' === $template_type ) { 23 continue; 24 } 25 add_filter( str_replace( '-', '', $template_type ) . '_template', 'locate_block_template', 20, 3 ); 26 } 27 28 // Request to resolve a template. 29 if ( isset( $_GET['_wp-find-template'] ) ) { 30 add_filter( 'pre_get_posts', '_resolve_template_for_new_post' ); 31 } 32 } 33 34 /** 35 * Find a block template with equal or higher specificity than a given PHP template file. 36 * 37 * Internally, this communicates the block content that needs to be used by the template canvas through a global variable. 38 * 39 * @since 5.8.0 40 * 41 * @global string $_wp_current_template_content 42 * 43 * @param string $template Path to the template. See locate_template(). 44 * @param string $type Sanitized filename without extension. 45 * @param string[] $templates A list of template candidates, in descending order of priority. 46 * @return string The path to the Full Site Editing template canvas file, or the fallback PHP template. 47 */ 48 function locate_block_template( $template, $type, array $templates ) { 49 global $_wp_current_template_content; 50 51 if ( ! current_theme_supports( 'block-templates' ) ) { 52 return $template; 53 } 54 55 if ( $template ) { 56 /* 57 * locate_template() has found a PHP template at the path specified by $template. 58 * That means that we have a fallback candidate if we cannot find a block template 59 * with higher specificity. 60 * 61 * Thus, before looking for matching block themes, we shorten our list of candidate 62 * templates accordingly. 63 */ 64 65 // Locate the index of $template (without the theme directory path) in $templates. 66 $relative_template_path = str_replace( 67 array( get_stylesheet_directory() . '/', get_template_directory() . '/' ), 68 '', 69 $template 70 ); 71 $index = array_search( $relative_template_path, $templates, true ); 72 73 // If the template hierarchy algorithm has successfully located a PHP template file, 74 // we will only consider block templates with higher or equal specificity. 75 $templates = array_slice( $templates, 0, $index + 1 ); 76 } 77 78 $block_template = resolve_block_template( $type, $templates, $template ); 79 80 if ( $block_template ) { 81 if ( empty( $block_template->content ) && is_user_logged_in() ) { 82 $_wp_current_template_content = 83 sprintf( 84 /* translators: %s: Template title */ 85 __( 'Empty template: %s' ), 86 $block_template->title 87 ); 88 } elseif ( ! empty( $block_template->content ) ) { 89 $_wp_current_template_content = $block_template->content; 90 } 91 if ( isset( $_GET['_wp-find-template'] ) ) { 92 wp_send_json_success( $block_template ); 93 } 94 } else { 95 if ( $template ) { 96 return $template; 97 } 98 99 if ( 'index' === $type ) { 100 if ( isset( $_GET['_wp-find-template'] ) ) { 101 wp_send_json_error( array( 'message' => __( 'No matching template found.' ) ) ); 102 } 103 } else { 104 return ''; // So that the template loader keeps looking for templates. 105 } 106 } 107 108 // Add hooks for template canvas. 109 // Add viewport meta tag. 110 add_action( 'wp_head', '_block_template_viewport_meta_tag', 0 ); 111 112 // Render title tag with content, regardless of whether theme has title-tag support. 113 remove_action( 'wp_head', '_wp_render_title_tag', 1 ); // Remove conditional title tag rendering... 114 add_action( 'wp_head', '_block_template_render_title_tag', 1 ); // ...and make it unconditional. 115 116 // This file will be included instead of the theme's template file. 117 return ABSPATH . WPINC . '/template-canvas.php'; 118 } 119 120 /** 121 * Return the correct 'wp_template' to render for the request template type. 122 * 123 * @access private 124 * @since 5.8.0 125 * @since 5.9.0 Added the `$fallback_template` parameter. 126 * 127 * @param string $template_type The current template type. 128 * @param string[] $template_hierarchy The current template hierarchy, ordered by priority. 129 * @param string $fallback_template A PHP fallback template to use if no matching block template is found. 130 * @return WP_Block_Template|null template A template object, or null if none could be found. 131 */ 132 function resolve_block_template( $template_type, $template_hierarchy, $fallback_template ) { 133 if ( ! $template_type ) { 134 return null; 135 } 136 137 if ( empty( $template_hierarchy ) ) { 138 $template_hierarchy = array( $template_type ); 139 } 140 141 $slugs = array_map( 142 '_strip_template_file_suffix', 143 $template_hierarchy 144 ); 145 146 // Find all potential templates 'wp_template' post matching the hierarchy. 147 $query = array( 148 'theme' => wp_get_theme()->get_stylesheet(), 149 'slug__in' => $slugs, 150 ); 151 $templates = get_block_templates( $query ); 152 153 // Order these templates per slug priority. 154 // Build map of template slugs to their priority in the current hierarchy. 155 $slug_priorities = array_flip( $slugs ); 156 157 usort( 158 $templates, 159 static function ( $template_a, $template_b ) use ( $slug_priorities ) { 160 return $slug_priorities[ $template_a->slug ] - $slug_priorities[ $template_b->slug ]; 161 } 162 ); 163 164 $theme_base_path = get_stylesheet_directory() . DIRECTORY_SEPARATOR; 165 $parent_theme_base_path = get_template_directory() . DIRECTORY_SEPARATOR; 166 167 // Is the active theme a child theme, and is the PHP fallback template part of it? 168 if ( 169 strpos( $fallback_template, $theme_base_path ) === 0 && 170 strpos( $fallback_template, $parent_theme_base_path ) === false 171 ) { 172 $fallback_template_slug = substr( 173 $fallback_template, 174 // Starting position of slug. 175 strpos( $fallback_template, $theme_base_path ) + strlen( $theme_base_path ), 176 // Remove '.php' suffix. 177 -4 178 ); 179 180 // Is our candidate block template's slug identical to our PHP fallback template's? 181 if ( 182 count( $templates ) && 183 $fallback_template_slug === $templates[0]->slug && 184 'theme' === $templates[0]->source 185 ) { 186 // Unfortunately, we cannot trust $templates[0]->theme, since it will always 187 // be set to the active theme's slug by _build_block_template_result_from_file(), 188 // even if the block template is really coming from the active theme's parent. 189 // (The reason for this is that we want it to be associated with the active theme 190 // -- not its parent -- once we edit it and store it to the DB as a wp_template CPT.) 191 // Instead, we use _get_block_template_file() to locate the block template file. 192 $template_file = _get_block_template_file( 'wp_template', $fallback_template_slug ); 193 if ( $template_file && get_template() === $template_file['theme'] ) { 194 // The block template is part of the parent theme, so we 195 // have to give precedence to the child theme's PHP template. 196 array_shift( $templates ); 197 } 198 } 199 } 200 201 return count( $templates ) ? $templates[0] : null; 202 } 203 204 /** 205 * Displays title tag with content, regardless of whether theme has title-tag support. 206 * 207 * @access private 208 * @since 5.8.0 209 * 210 * @see _wp_render_title_tag() 211 */ 212 function _block_template_render_title_tag() { 213 echo '<title>' . wp_get_document_title() . '</title>' . "\n"; 214 } 215 216 /** 217 * Returns the markup for the current template. 218 * 219 * @access private 220 * @since 5.8.0 221 * 222 * @global string $_wp_current_template_content 223 * @global WP_Embed $wp_embed 224 * 225 * @return string Block template markup. 226 */ 227 function get_the_block_template_html() { 228 global $_wp_current_template_content; 229 global $wp_embed; 230 231 if ( ! $_wp_current_template_content ) { 232 if ( is_user_logged_in() ) { 233 return '<h1>' . esc_html__( 'No matching template found' ) . '</h1>'; 234 } 235 return; 236 } 237 238 $content = $wp_embed->run_shortcode( $_wp_current_template_content ); 239 $content = $wp_embed->autoembed( $content ); 240 $content = do_blocks( $content ); 241 $content = wptexturize( $content ); 242 $content = convert_smilies( $content ); 243 $content = shortcode_unautop( $content ); 244 $content = wp_filter_content_tags( $content ); 245 $content = do_shortcode( $content ); 246 $content = str_replace( ']]>', ']]>', $content ); 247 248 // Wrap block template in .wp-site-blocks to allow for specific descendant styles 249 // (e.g. `.wp-site-blocks > *`). 250 return '<div class="wp-site-blocks">' . $content . '</div>'; 251 } 252 253 /** 254 * Renders a 'viewport' meta tag. 255 * 256 * This is hooked into {@see 'wp_head'} to decouple its output from the default template canvas. 257 * 258 * @access private 259 * @since 5.8.0 260 */ 261 function _block_template_viewport_meta_tag() { 262 echo '<meta name="viewport" content="width=device-width, initial-scale=1" />' . "\n"; 263 } 264 265 /** 266 * Strips .php or .html suffix from template file names. 267 * 268 * @access private 269 * @since 5.8.0 270 * 271 * @param string $template_file Template file name. 272 * @return string Template file name without extension. 273 */ 274 function _strip_template_file_suffix( $template_file ) { 275 return preg_replace( '/\.(php|html)$/', '', $template_file ); 276 } 277 278 /** 279 * Removes post details from block context when rendering a block template. 280 * 281 * @access private 282 * @since 5.8.0 283 * 284 * @param array $context Default context. 285 * 286 * @return array Filtered context. 287 */ 288 function _block_template_render_without_post_block_context( $context ) { 289 /* 290 * When loading a template directly and not through a page that resolves it, 291 * the top-level post ID and type context get set to that of the template. 292 * Templates are just the structure of a site, and they should not be available 293 * as post context because blocks like Post Content would recurse infinitely. 294 */ 295 if ( isset( $context['postType'] ) && 'wp_template' === $context['postType'] ) { 296 unset( $context['postId'] ); 297 unset( $context['postType'] ); 298 } 299 300 return $context; 301 } 302 303 /** 304 * Sets the current WP_Query to return auto-draft posts. 305 * 306 * The auto-draft status indicates a new post, so allow the the WP_Query instance to 307 * return an auto-draft post for template resolution when editing a new post. 308 * 309 * @access private 310 * @since 5.9.0 311 * 312 * @param WP_Query $wp_query Current WP_Query instance, passed by reference. 313 */ 314 function _resolve_template_for_new_post( $wp_query ) { 315 remove_filter( 'pre_get_posts', '_resolve_template_for_new_post' ); 316 317 // Pages. 318 $page_id = isset( $wp_query->query['page_id'] ) ? $wp_query->query['page_id'] : null; 319 320 // Posts, including custom post types. 321 $p = isset( $wp_query->query['p'] ) ? $wp_query->query['p'] : null; 322 323 $post_id = $page_id ? $page_id : $p; 324 $post = get_post( $post_id ); 325 326 if ( 327 $post && 328 'auto-draft' === $post->post_status && 329 current_user_can( 'edit_post', $post->ID ) 330 ) { 331 $wp_query->set( 'post_status', 'auto-draft' ); 332 } 333 } 334 335 /** 336 * Returns the correct template for the site's home page. 337 * 338 * @access private 339 * @since 6.0.0 340 * 341 * @return array|null A template object, or null if none could be found. 342 */ 343 function _resolve_home_block_template() { 344 $show_on_front = get_option( 'show_on_front' ); 345 $front_page_id = get_option( 'page_on_front' ); 346 347 if ( 'page' === $show_on_front && $front_page_id ) { 348 return array( 349 'postType' => 'page', 350 'postId' => $front_page_id, 351 ); 352 } 353 354 $hierarchy = array( 'front-page', 'home', 'index' ); 355 $template = resolve_block_template( 'home', $hierarchy, '' ); 356 357 if ( ! $template ) { 358 return null; 359 } 360 361 return array( 362 'postType' => 'wp_template', 363 'postId' => $template->id, 364 ); 365 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sat Nov 23 01:00:02 2024 | Cross-referenced by PHPXref 0.7.1 |