4 * |
4 * |
5 * @package WordPress |
5 * @package WordPress |
6 */ |
6 */ |
7 |
7 |
8 /** |
8 /** |
9 * Adds necessary filters to use 'wp_template' posts instead of theme template files. |
9 * Adds necessary hooks to resolve '_wp-find-template' requests. |
10 * |
10 * |
11 * @access private |
11 * @access private |
12 * @since 5.9.0 |
12 * @since 5.9.0 |
13 */ |
13 */ |
14 function _add_template_loader_filters() { |
14 function _add_template_loader_filters() { |
15 if ( ! current_theme_supports( 'block-templates' ) ) { |
15 if ( isset( $_GET['_wp-find-template'] ) && current_theme_supports( 'block-templates' ) ) { |
16 return; |
16 add_action( 'pre_get_posts', '_resolve_template_for_new_post' ); |
17 } |
17 } |
18 |
18 } |
19 $template_types = array_keys( get_default_block_template_types() ); |
19 |
20 foreach ( $template_types as $template_type ) { |
20 /** |
21 // Skip 'embed' for now because it is not a regular template type. |
21 * Finds a block template with equal or higher specificity than a given PHP template file. |
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 * |
22 * |
37 * Internally, this communicates the block content that needs to be used by the template canvas through a global variable. |
23 * Internally, this communicates the block content that needs to be used by the template canvas through a global variable. |
38 * |
24 * |
39 * @since 5.8.0 |
25 * @since 5.8.0 |
|
26 * @since 6.3.0 Added `$_wp_current_template_id` global for editing of current template directly from the admin bar. |
40 * |
27 * |
41 * @global string $_wp_current_template_content |
28 * @global string $_wp_current_template_content |
|
29 * @global string $_wp_current_template_id |
42 * |
30 * |
43 * @param string $template Path to the template. See locate_template(). |
31 * @param string $template Path to the template. See locate_template(). |
44 * @param string $type Sanitized filename without extension. |
32 * @param string $type Sanitized filename without extension. |
45 * @param string[] $templates A list of template candidates, in descending order of priority. |
33 * @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. |
34 * @return string The path to the Site Editor template canvas file, or the fallback PHP template. |
47 */ |
35 */ |
48 function locate_block_template( $template, $type, array $templates ) { |
36 function locate_block_template( $template, $type, array $templates ) { |
49 global $_wp_current_template_content; |
37 global $_wp_current_template_content, $_wp_current_template_id; |
50 |
38 |
51 if ( ! current_theme_supports( 'block-templates' ) ) { |
39 if ( ! current_theme_supports( 'block-templates' ) ) { |
52 return $template; |
40 return $template; |
53 } |
41 } |
54 |
42 |
76 } |
64 } |
77 |
65 |
78 $block_template = resolve_block_template( $type, $templates, $template ); |
66 $block_template = resolve_block_template( $type, $templates, $template ); |
79 |
67 |
80 if ( $block_template ) { |
68 if ( $block_template ) { |
|
69 $_wp_current_template_id = $block_template->id; |
|
70 |
81 if ( empty( $block_template->content ) && is_user_logged_in() ) { |
71 if ( empty( $block_template->content ) && is_user_logged_in() ) { |
82 $_wp_current_template_content = |
72 $_wp_current_template_content = |
83 sprintf( |
73 sprintf( |
84 /* translators: %s: Template title */ |
74 /* translators: %s: Template title */ |
85 __( 'Empty template: %s' ), |
75 __( 'Empty template: %s' ), |
164 $theme_base_path = get_stylesheet_directory() . DIRECTORY_SEPARATOR; |
153 $theme_base_path = get_stylesheet_directory() . DIRECTORY_SEPARATOR; |
165 $parent_theme_base_path = get_template_directory() . DIRECTORY_SEPARATOR; |
154 $parent_theme_base_path = get_template_directory() . DIRECTORY_SEPARATOR; |
166 |
155 |
167 // Is the active theme a child theme, and is the PHP fallback template part of it? |
156 // Is the active theme a child theme, and is the PHP fallback template part of it? |
168 if ( |
157 if ( |
169 strpos( $fallback_template, $theme_base_path ) === 0 && |
158 str_starts_with( $fallback_template, $theme_base_path ) && |
170 strpos( $fallback_template, $parent_theme_base_path ) === false |
159 ! str_contains( $fallback_template, $parent_theme_base_path ) |
171 ) { |
160 ) { |
172 $fallback_template_slug = substr( |
161 $fallback_template_slug = substr( |
173 $fallback_template, |
162 $fallback_template, |
174 // Starting position of slug. |
163 // Starting position of slug. |
175 strpos( $fallback_template, $theme_base_path ) + strlen( $theme_base_path ), |
164 strpos( $fallback_template, $theme_base_path ) + strlen( $theme_base_path ), |
217 * Returns the markup for the current template. |
206 * Returns the markup for the current template. |
218 * |
207 * |
219 * @access private |
208 * @access private |
220 * @since 5.8.0 |
209 * @since 5.8.0 |
221 * |
210 * |
|
211 * @global string $_wp_current_template_id |
222 * @global string $_wp_current_template_content |
212 * @global string $_wp_current_template_content |
223 * @global WP_Embed $wp_embed |
213 * @global WP_Embed $wp_embed WordPress Embed object. |
|
214 * @global WP_Query $wp_query WordPress Query object. |
224 * |
215 * |
225 * @return string Block template markup. |
216 * @return string Block template markup. |
226 */ |
217 */ |
227 function get_the_block_template_html() { |
218 function get_the_block_template_html() { |
228 global $_wp_current_template_content; |
219 global $_wp_current_template_id, $_wp_current_template_content, $wp_embed, $wp_query; |
229 global $wp_embed; |
|
230 |
220 |
231 if ( ! $_wp_current_template_content ) { |
221 if ( ! $_wp_current_template_content ) { |
232 if ( is_user_logged_in() ) { |
222 if ( is_user_logged_in() ) { |
233 return '<h1>' . esc_html__( 'No matching template found' ) . '</h1>'; |
223 return '<h1>' . esc_html__( 'No matching template found' ) . '</h1>'; |
234 } |
224 } |
235 return; |
225 return; |
236 } |
226 } |
237 |
227 |
238 $content = $wp_embed->run_shortcode( $_wp_current_template_content ); |
228 $content = $wp_embed->run_shortcode( $_wp_current_template_content ); |
239 $content = $wp_embed->autoembed( $content ); |
229 $content = $wp_embed->autoembed( $content ); |
240 $content = do_blocks( $content ); |
230 $content = shortcode_unautop( $content ); |
|
231 $content = do_shortcode( $content ); |
|
232 |
|
233 /* |
|
234 * Most block themes omit the `core/query` and `core/post-template` blocks in their singular content templates. |
|
235 * While this technically still works since singular content templates are always for only one post, it results in |
|
236 * the main query loop never being entered which causes bugs in core and the plugin ecosystem. |
|
237 * |
|
238 * The workaround below ensures that the loop is started even for those singular templates. The while loop will by |
|
239 * definition only go through a single iteration, i.e. `do_blocks()` is only called once. Additional safeguard |
|
240 * checks are included to ensure the main query loop has not been tampered with and really only encompasses a |
|
241 * single post. |
|
242 * |
|
243 * Even if the block template contained a `core/query` and `core/post-template` block referencing the main query |
|
244 * loop, it would not cause errors since it would use a cloned instance and go through the same loop of a single |
|
245 * post, within the actual main query loop. |
|
246 * |
|
247 * This special logic should be skipped if the current template does not come from the current theme, in which case |
|
248 * it has been injected by a plugin by hijacking the block template loader mechanism. In that case, entirely custom |
|
249 * logic may be applied which is unpredictable and therefore safer to omit this special handling on. |
|
250 */ |
|
251 if ( |
|
252 $_wp_current_template_id && |
|
253 str_starts_with( $_wp_current_template_id, get_stylesheet() . '//' ) && |
|
254 is_singular() && |
|
255 1 === $wp_query->post_count && |
|
256 have_posts() |
|
257 ) { |
|
258 while ( have_posts() ) { |
|
259 the_post(); |
|
260 $content = do_blocks( $content ); |
|
261 } |
|
262 } else { |
|
263 $content = do_blocks( $content ); |
|
264 } |
|
265 |
241 $content = wptexturize( $content ); |
266 $content = wptexturize( $content ); |
242 $content = convert_smilies( $content ); |
267 $content = convert_smilies( $content ); |
243 $content = shortcode_unautop( $content ); |
268 $content = wp_filter_content_tags( $content, 'template' ); |
244 $content = wp_filter_content_tags( $content ); |
|
245 $content = do_shortcode( $content ); |
|
246 $content = str_replace( ']]>', ']]>', $content ); |
269 $content = str_replace( ']]>', ']]>', $content ); |
247 |
270 |
248 // Wrap block template in .wp-site-blocks to allow for specific descendant styles |
271 // Wrap block template in .wp-site-blocks to allow for specific descendant styles |
249 // (e.g. `.wp-site-blocks > *`). |
272 // (e.g. `.wp-site-blocks > *`). |
250 return '<div class="wp-site-blocks">' . $content . '</div>'; |
273 return '<div class="wp-site-blocks">' . $content . '</div>'; |
333 current_user_can( 'edit_post', $post->ID ) |
356 current_user_can( 'edit_post', $post->ID ) |
334 ) { |
357 ) { |
335 $wp_query->set( 'post_status', 'auto-draft' ); |
358 $wp_query->set( 'post_status', 'auto-draft' ); |
336 } |
359 } |
337 } |
360 } |
338 |
|
339 /** |
|
340 * Returns the correct template for the site's home page. |
|
341 * |
|
342 * @access private |
|
343 * @since 6.0.0 |
|
344 * |
|
345 * @return array|null A template object, or null if none could be found. |
|
346 */ |
|
347 function _resolve_home_block_template() { |
|
348 $show_on_front = get_option( 'show_on_front' ); |
|
349 $front_page_id = get_option( 'page_on_front' ); |
|
350 |
|
351 if ( 'page' === $show_on_front && $front_page_id ) { |
|
352 return array( |
|
353 'postType' => 'page', |
|
354 'postId' => $front_page_id, |
|
355 ); |
|
356 } |
|
357 |
|
358 $hierarchy = array( 'front-page', 'home', 'index' ); |
|
359 $template = resolve_block_template( 'home', $hierarchy, '' ); |
|
360 |
|
361 if ( ! $template ) { |
|
362 return null; |
|
363 } |
|
364 |
|
365 return array( |
|
366 'postType' => 'wp_template', |
|
367 'postId' => $template->id, |
|
368 ); |
|
369 } |
|