PluginProbe
Gutenberg / 12.1.0
Gutenberg v12.1.0
23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 7.4.0 All 402 releases
gutenberg / lib / compat / wordpress-5.9 / block-template-utils.php

block-template-utils.php in Gutenberg 12.1.0, at lib/compat/wordpress-5.9/block-template-utils.php

954 lines 30.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Temporary compatibility shims for features present in Gutenberg.
4 * This file should be removed when WordPress 5.9.0 becomes the lowest
5 * supported version by this plugin.
6 *
7 * @package gutenberg
8 */
9
10 // Define constants for supported wp_template_part_area taxonomy.
11 if ( ! defined( 'WP_TEMPLATE_PART_AREA_HEADER' ) ) {
12 define( 'WP_TEMPLATE_PART_AREA_HEADER', 'header' );
13 }
14 if ( ! defined( 'WP_TEMPLATE_PART_AREA_FOOTER' ) ) {
15 define( 'WP_TEMPLATE_PART_AREA_FOOTER', 'footer' );
16 }
17 if ( ! defined( 'WP_TEMPLATE_PART_AREA_SIDEBAR' ) ) {
18 define( 'WP_TEMPLATE_PART_AREA_SIDEBAR', 'sidebar' );
19 }
20 if ( ! defined( 'WP_TEMPLATE_PART_AREA_UNCATEGORIZED' ) ) {
21 define( 'WP_TEMPLATE_PART_AREA_UNCATEGORIZED', 'uncategorized' );
22 }
23
24
25 if ( ! function_exists( 'get_block_theme_folders' ) ) {
26 /**
27 * For backward compatibility reasons,
28 * block themes might be using block-templates or block-template-parts,
29 * this function ensures we fallback to these folders properly.
30 *
31 * @param string $theme_stylesheet The stylesheet. Default is to leverage the main theme root.
32 *
33 * @return array Folder names used by block themes.
34 */
35 function get_block_theme_folders( $theme_stylesheet = null ) {
36 $theme_name = null === $theme_stylesheet ? get_stylesheet() : $theme_stylesheet;
37 $root_dir = get_theme_root( $theme_name );
38 $theme_dir = "$root_dir/$theme_name";
39
40 if ( is_readable( $theme_dir . '/block-templates/index.html' ) ) {
41 return array(
42 'wp_template' => 'block-templates',
43 'wp_template_part' => 'block-template-parts',
44 );
45 }
46
47 return array(
48 'wp_template' => 'templates',
49 'wp_template_part' => 'parts',
50 );
51 }
52 }
53
54 if ( ! function_exists( 'get_allowed_block_template_part_areas' ) ) {
55 /**
56 * Returns a filtered list of allowed area values for template parts.
57 *
58 * @return array The supported template part area values.
59 */
60 function get_allowed_block_template_part_areas() {
61 $default_area_definitions = array(
62 array(
63 'area' => WP_TEMPLATE_PART_AREA_UNCATEGORIZED,
64 'label' => __( 'General', 'gutenberg' ),
65 'description' => __(
66 'General templates often perform a specific role like displaying post content, and are not tied to any particular area.',
67 'gutenberg'
68 ),
69 'icon' => 'layout',
70 'area_tag' => 'div',
71 ),
72 array(
73 'area' => WP_TEMPLATE_PART_AREA_HEADER,
74 'label' => __( 'Header', 'gutenberg' ),
75 'description' => __(
76 'The Header template defines a page area that typically contains a title, logo, and main navigation.',
77 'gutenberg'
78 ),
79 'icon' => 'header',
80 'area_tag' => 'header',
81 ),
82 array(
83 'area' => WP_TEMPLATE_PART_AREA_FOOTER,
84 'label' => __( 'Footer', 'gutenberg' ),
85 'description' => __(
86 'The Footer template defines a page area that typically contains site credits, social links, or any other combination of blocks.',
87 'gutenberg'
88 ),
89 'icon' => 'footer',
90 'area_tag' => 'footer',
91 ),
92 );
93
94 /**
95 * Filters the list of allowed template part area values.
96 *
97 * @param array $default_areas An array of supported area objects.
98 */
99 return apply_filters( 'default_wp_template_part_areas', $default_area_definitions );
100 }
101 }
102
103 if ( ! function_exists( 'get_default_block_template_types' ) ) {
104 /**
105 * Returns a filtered list of default template types, containing their
106 * localized titles and descriptions.
107 *
108 * @return array The default template types.
109 */
110 function get_default_block_template_types() {
111 $default_template_types = array(
112 'index' => array(
113 'title' => _x( 'Index', 'Template name', 'gutenberg' ),
114 'description' => __( 'Displays posts.', 'gutenberg' ),
115 ),
116 'home' => array(
117 'title' => _x( 'Home', 'Template name', 'gutenberg' ),
118 'description' => __( 'Displays as the site\'s home page, or as the Posts page when a static home page it set.', 'gutenberg' ),
119 ),
120 'front-page' => array(
121 'title' => _x( 'Front Page', 'Template name', 'gutenberg' ),
122 'description' => __( 'Displays as the site\'s home page.', 'gutenberg' ),
123 ),
124 'singular' => array(
125 'title' => _x( 'Singular', 'Template name', 'gutenberg' ),
126 'description' => __( 'Displays a single post or page.', 'gutenberg' ),
127 ),
128 'single' => array(
129 'title' => _x( 'Single Post', 'Template name', 'gutenberg' ),
130 'description' => __( 'Displays a single post.', 'gutenberg' ),
131 ),
132 'page' => array(
133 'title' => _x( 'Page', 'Template name', 'gutenberg' ),
134 'description' => __( 'Displays a single page.', 'gutenberg' ),
135 ),
136 'archive' => array(
137 'title' => _x( 'Archive', 'Template name', 'gutenberg' ),
138 'description' => __( 'Displays post categories, tags, and other archives.', 'gutenberg' ),
139 ),
140 'author' => array(
141 'title' => _x( 'Author', 'Template name', 'gutenberg' ),
142 'description' => __( 'Displays latest posts written by a single author.', 'gutenberg' ),
143 ),
144 'category' => array(
145 'title' => _x( 'Category', 'Template name', 'gutenberg' ),
146 'description' => __( 'Displays latest posts in single post category.', 'gutenberg' ),
147 ),
148 'taxonomy' => array(
149 'title' => _x( 'Taxonomy', 'Template name', 'gutenberg' ),
150 'description' => __( 'Displays latest posts from a single post taxonomy.', 'gutenberg' ),
151 ),
152 'date' => array(
153 'title' => _x( 'Date', 'Template name', 'gutenberg' ),
154 'description' => __( 'Displays posts from a specific date.', 'gutenberg' ),
155 ),
156 'tag' => array(
157 'title' => _x( 'Tag', 'Template name', 'gutenberg' ),
158 'description' => __( 'Displays latest posts with single post tag.', 'gutenberg' ),
159 ),
160 'attachment' => array(
161 'title' => __( 'Media', 'gutenberg' ),
162 'description' => __( 'Displays individual media items or attachments.', 'gutenberg' ),
163 ),
164 'search' => array(
165 'title' => _x( 'Search', 'Template name', 'gutenberg' ),
166 'description' => __( 'Template used to display search results.', 'gutenberg' ),
167 ),
168 'privacy-policy' => array(
169 'title' => __( 'Privacy Policy', 'gutenberg' ),
170 'description' => __( 'Displays the privacy policy page.', 'gutenberg' ),
171 ),
172 '404' => array(
173 'title' => _x( '404', 'Template name', 'gutenberg' ),
174 'description' => __( 'Displays when no content is found.', 'gutenberg' ),
175 ),
176 );
177
178 /**
179 * Filters the list of template types.
180 *
181 * @param array $default_template_types An array of template types, formatted as [ slug => [ title, description ] ].
182 *
183 * @since 5.x.x
184 */
185 return apply_filters( 'default_template_types', $default_template_types );
186 }
187 }
188
189 if ( ! function_exists( '_filter_block_template_part_area' ) ) {
190 /**
191 * Checks whether the input 'area' is a supported value.
192 * Returns the input if supported, otherwise returns the 'uncategorized' value.
193 *
194 * @param string $type Template part area name.
195 *
196 * @return string Input if supported, else the uncategorized value.
197 */
198 function _filter_block_template_part_area( $type ) {
199 $allowed_areas = array_map(
200 function ( $item ) {
201 return $item['area'];
202 },
203 get_allowed_block_template_part_areas()
204 );
205 if ( in_array( $type, $allowed_areas, true ) ) {
206 return $type;
207 }
208
209 /* translators: %1$s: Template area type, %2$s: the uncategorized template area value. */
210 $warning_message = sprintf( __( '"%1$s" is not a supported wp_template_part area value and has been added as "%2$s".', 'gutenberg' ), $type, WP_TEMPLATE_PART_AREA_UNCATEGORIZED );
211 trigger_error( $warning_message, E_USER_NOTICE );
212 return WP_TEMPLATE_PART_AREA_UNCATEGORIZED;
213 }
214 }
215
216 if ( ! function_exists( '_get_block_templates_paths' ) ) {
217 /**
218 * Finds all nested template part file paths in a theme's directory.
219 *
220 * @access private
221 *
222 * @param string $base_directory The theme's file path.
223 * @return array $path_list A list of paths to all template part files.
224 */
225 function _get_block_templates_paths( $base_directory ) {
226 $path_list = array();
227 if ( file_exists( $base_directory ) ) {
228 $nested_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $base_directory ) );
229 $nested_html_files = new RegexIterator( $nested_files, '/^.+\.html$/i', RecursiveRegexIterator::GET_MATCH );
230 foreach ( $nested_html_files as $path => $file ) {
231 $path_list[] = $path;
232 }
233 }
234 return $path_list;
235 }
236 }
237
238 if ( ! function_exists( '_get_block_template_file' ) ) {
239 /**
240 * Retrieves the template file from the theme for a given slug.
241 *
242 * @access private
243 * @internal
244 *
245 * @param string $template_type wp_template or wp_template_part.
246 * @param string $slug template slug.
247 *
248 * @return array|null Template.
249 */
250 function _get_block_template_file( $template_type, $slug ) {
251 if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) {
252 return null;
253 }
254
255 $themes = array(
256 get_stylesheet() => get_stylesheet_directory(),
257 get_template() => get_template_directory(),
258 );
259 foreach ( $themes as $theme_slug => $theme_dir ) {
260 $template_base_paths = get_block_theme_folders( $theme_slug );
261 $file_path = $theme_dir . '/' . $template_base_paths[ $template_type ] . '/' . $slug . '.html';
262 if ( file_exists( $file_path ) ) {
263 $new_template_item = array(
264 'slug' => $slug,
265 'path' => $file_path,
266 'theme' => $theme_slug,
267 'type' => $template_type,
268 );
269
270 if ( 'wp_template_part' === $template_type ) {
271 return _add_block_template_part_area_info( $new_template_item );
272 }
273
274 if ( 'wp_template' === $template_type ) {
275 return _add_block_template_info( $new_template_item );
276 }
277
278 return $new_template_item;
279 }
280 }
281
282 return null;
283 }
284 }
285
286 if ( ! function_exists( '_get_block_templates_files' ) ) {
287 /**
288 * Retrieves the template files from the theme.
289 *
290 * @access private
291 * @internal
292 *
293 * @param string $template_type wp_template or wp_template_part.
294 *
295 * @return array Template.
296 */
297 function _get_block_templates_files( $template_type ) {
298 if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) {
299 return null;
300 }
301
302 $themes = array(
303 get_stylesheet() => get_stylesheet_directory(),
304 get_template() => get_template_directory(),
305 );
306 $template_files = array();
307 foreach ( $themes as $theme_slug => $theme_dir ) {
308 $template_base_paths = get_block_theme_folders( $theme_slug );
309 $theme_template_files = _get_block_templates_paths( $theme_dir . '/' . $template_base_paths[ $template_type ] );
310 foreach ( $theme_template_files as $template_file ) {
311 $template_base_path = $template_base_paths[ $template_type ];
312 $template_slug = substr(
313 $template_file,
314 // Starting position of slug.
315 strpos( $template_file, $template_base_path . DIRECTORY_SEPARATOR ) + 1 + strlen( $template_base_path ),
316 // Subtract ending '.html'.
317 -5
318 );
319 $new_template_item = array(
320 'slug' => $template_slug,
321 'path' => $template_file,
322 'theme' => $theme_slug,
323 'type' => $template_type,
324 );
325
326 if ( 'wp_template_part' === $template_type ) {
327 $template_files[] = _add_block_template_part_area_info( $new_template_item );
328 }
329
330 if ( 'wp_template' === $template_type ) {
331 $template_files[] = _add_block_template_info( $new_template_item );
332 }
333 }
334 }
335
336 return $template_files;
337 }
338 }
339
340 if ( ! function_exists( '_add_block_template_info' ) ) {
341 /**
342 * Attempts to add custom template information to the template item.
343 *
344 * @param array $template_item Template to add information to (requires 'slug' field).
345 * @return array Template
346 */
347 function _add_block_template_info( $template_item ) {
348 if ( ! WP_Theme_JSON_Resolver_Gutenberg::theme_has_support() ) {
349 return $template_item;
350 }
351
352 $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_custom_templates();
353 if ( isset( $theme_data[ $template_item['slug'] ] ) ) {
354 $template_item['title'] = $theme_data[ $template_item['slug'] ]['title'];
355 $template_item['postTypes'] = $theme_data[ $template_item['slug'] ]['postTypes'];
356 }
357
358 return $template_item;
359 }
360 }
361
362 if ( ! function_exists( '_add_block_template_part_area_info' ) ) {
363 /**
364 * Attempts to add the template part's area information to the input template.
365 *
366 * @param array $template_info Template to add information to (requires 'type' and 'slug' fields).
367 *
368 * @return array Template.
369 */
370 function _add_block_template_part_area_info( $template_info ) {
371 if ( WP_Theme_JSON_Resolver_Gutenberg::theme_has_support() ) {
372 $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_template_parts();
373 }
374
375 if ( isset( $theme_data[ $template_info['slug'] ]['area'] ) ) {
376 $template_info['title'] = $theme_data[ $template_info['slug'] ]['title'];
377 $template_info['area'] = _filter_block_template_part_area( $theme_data[ $template_info['slug'] ]['area'] );
378 } else {
379 $template_info['area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED;
380 }
381
382 return $template_info;
383 }
384 }
385
386 if ( ! function_exists( '_flatten_blocks' ) ) {
387 /**
388 * Returns an array containing the references of
389 * the passed blocks and their inner blocks.
390 *
391 * @param array $blocks array of blocks.
392 *
393 * @return array block references to the passed blocks and their inner blocks.
394 */
395 function _flatten_blocks( &$blocks ) {
396 $all_blocks = array();
397 $queue = array();
398 foreach ( $blocks as &$block ) {
399 $queue[] = &$block;
400 }
401
402 while ( count( $queue ) > 0 ) {
403 $block = &$queue[0];
404 array_shift( $queue );
405 $all_blocks[] = &$block;
406
407 if ( ! empty( $block['innerBlocks'] ) ) {
408 foreach ( $block['innerBlocks'] as &$inner_block ) {
409 $queue[] = &$inner_block;
410 }
411 }
412 }
413
414 return $all_blocks;
415 }
416 }
417
418 if ( ! function_exists( '_inject_theme_attribute_in_block_template_content' ) ) {
419 /**
420 * Parses wp_template content and injects the current theme's
421 * stylesheet as a theme attribute into each wp_template_part
422 *
423 * @param string $template_content serialized wp_template content.
424 *
425 * @return string Updated wp_template content.
426 */
427 function _inject_theme_attribute_in_block_template_content( $template_content ) {
428 $has_updated_content = false;
429 $new_content = '';
430 $template_blocks = parse_blocks( $template_content );
431
432 $blocks = _flatten_blocks( $template_blocks );
433 foreach ( $blocks as &$block ) {
434 if (
435 'core/template-part' === $block['blockName'] &&
436 ! isset( $block['attrs']['theme'] )
437 ) {
438 $block['attrs']['theme'] = wp_get_theme()->get_stylesheet();
439 $has_updated_content = true;
440 }
441 }
442
443 if ( $has_updated_content ) {
444 foreach ( $template_blocks as &$block ) {
445 $new_content .= serialize_block( $block );
446 }
447
448 return $new_content;
449 }
450
451 return $template_content;
452 }
453 }
454
455 if ( ! function_exists( '_remove_theme_attribute_in_block_template_content' ) ) {
456 /**
457 * Parses wp_template content and removes the theme attribute from
458 * each wp_template_part
459 *
460 * @param string $template_content serialized wp_template content.
461 *
462 * @return string Updated wp_template content.
463 */
464 function _remove_theme_attribute_in_block_template_content( $template_content ) {
465 $has_updated_content = false;
466 $new_content = '';
467 $template_blocks = parse_blocks( $template_content );
468
469 $blocks = _flatten_blocks( $template_blocks );
470 foreach ( $blocks as $key => $block ) {
471 if ( 'core/template-part' === $block['blockName'] && isset( $block['attrs']['theme'] ) ) {
472 unset( $blocks[ $key ]['attrs']['theme'] );
473 $has_updated_content = true;
474 }
475 }
476
477 if ( $has_updated_content ) {
478 foreach ( $template_blocks as $block ) {
479 $new_content .= serialize_block( $block );
480 }
481
482 return $new_content;
483 }
484
485 return $template_content;
486 }
487 }
488
489 if ( ! function_exists( '_build_block_template_result_from_file' ) ) {
490 /**
491 * Build a unified template object based on a theme file.
492 *
493 * @param array $template_file Theme file.
494 * @param array $template_type wp_template or wp_template_part.
495 *
496 * @return WP_Block_Template Template.
497 */
498 function _build_block_template_result_from_file( $template_file, $template_type ) {
499 $default_template_types = get_default_block_template_types();
500 $template_content = file_get_contents( $template_file['path'] );
501 $theme = wp_get_theme()->get_stylesheet();
502
503 $template = new WP_Block_Template();
504 $template->id = $theme . '//' . $template_file['slug'];
505 $template->theme = $theme;
506 $template->content = _inject_theme_attribute_in_block_template_content( $template_content );
507 $template->slug = $template_file['slug'];
508 $template->source = 'theme';
509 $template->origin = null;
510 $template->type = $template_type;
511 $template->title = ! empty( $template_file['title'] ) ? $template_file['title'] : $template_file['slug'];
512 $template->status = 'publish';
513 $template->has_theme_file = true;
514 $template->is_custom = true;
515 $template->author = 0;
516
517 if ( 'wp_template' === $template_type && isset( $default_template_types[ $template_file['slug'] ] ) ) {
518 $template->description = $default_template_types[ $template_file['slug'] ]['description'];
519 $template->title = $default_template_types[ $template_file['slug'] ]['title'];
520 $template->is_custom = false;
521 }
522
523 if ( 'wp_template' === $template_type && isset( $template_file['postTypes'] ) ) {
524 $template->post_types = $template_file['postTypes'];
525 }
526
527 if ( 'wp_template_part' === $template_type && isset( $template_file['area'] ) ) {
528 $template->area = $template_file['area'];
529 }
530
531 return $template;
532 }
533 }
534
535 if ( ! function_exists( '_build_block_template_result_from_post' ) ) {
536 /**
537 * Build a unified template object based a post Object.
538 *
539 * @param WP_Post $post Template post.
540 *
541 * @return WP_Block_Template|WP_Error Template.
542 */
543 function _build_block_template_result_from_post( $post ) {
544 $default_template_types = get_default_block_template_types();
545 $terms = get_the_terms( $post, 'wp_theme' );
546
547 if ( is_wp_error( $terms ) ) {
548 return $terms;
549 }
550
551 if ( ! $terms ) {
552 return new WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.', 'gutenberg' ) );
553 }
554
555 $origin = get_post_meta( $post->ID, 'origin', true );
556
557 $theme = $terms[0]->name;
558 $has_theme_file = wp_get_theme()->get_stylesheet() === $theme &&
559 null !== _get_block_template_file( $post->post_type, $post->post_name );
560
561 $template = new WP_Block_Template();
562 $template->wp_id = $post->ID;
563 $template->id = $theme . '//' . $post->post_name;
564 $template->theme = $theme;
565 $template->content = $post->post_content;
566 $template->slug = $post->post_name;
567 $template->source = 'custom';
568 $template->origin = ! empty( $origin ) ? $origin : null;
569 $template->type = $post->post_type;
570 $template->description = $post->post_excerpt;
571 $template->title = $post->post_title;
572 $template->status = $post->post_status;
573 $template->has_theme_file = $has_theme_file;
574 $template->is_custom = true;
575 $template->author = $post->post_author;
576
577 if ( 'wp_template' === $post->post_type && isset( $default_template_types[ $template->slug ] ) ) {
578 $template->is_custom = false;
579 }
580
581 if ( 'wp_template_part' === $post->post_type ) {
582 $type_terms = get_the_terms( $post, 'wp_template_part_area' );
583 if ( ! is_wp_error( $type_terms ) && false !== $type_terms ) {
584 $template->area = $type_terms[0]->name;
585 }
586 }
587
588 return $template;
589 }
590 }
591
592
593 /**
594 * Retrieves a list of unified template objects based on a query.
595 *
596 * @param array $query {
597 * Optional. Arguments to retrieve templates.
598 *
599 * @type array $slug__in List of slugs to include.
600 * @type int $wp_id Post ID of customized template.
601 * @type string $area A 'wp_template_part_area' taxonomy value to filter by (for wp_template_part template type only).
602 * @type string $post_type Post type to get the templates for.
603 * }
604 * @param array $template_type wp_template or wp_template_part.
605 *
606 * @return array Templates.
607 */
608 function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_template' ) {
609 /**
610 * Filters the block templates array before the query takes place.
611 *
612 * Return a non-null value to bypass the WordPress queries.
613 *
614 * @since 10.8
615 *
616 * @param WP_Block_Template[]|null $block_templates Return an array of block templates to short-circuit the default query,
617 * or null to allow WP to run it's normal queries.
618 * @param array $query {
619 * Optional. Arguments to retrieve templates.
620 *
621 * @type array $slug__in List of slugs to include.
622 * @type int $wp_id Post ID of customized template.
623 * @type string $post_type Post type to get the templates for.
624 * }
625 * @param array $template_type wp_template or wp_template_part.
626 */
627 $templates = apply_filters( 'pre_get_block_templates', null, $query, $template_type );
628 if ( ! is_null( $templates ) ) {
629 return $templates;
630 }
631
632 $post_type = isset( $query['post_type'] ) ? $query['post_type'] : '';
633 $wp_query_args = array(
634 'post_status' => array( 'auto-draft', 'draft', 'publish' ),
635 'post_type' => $template_type,
636 'posts_per_page' => -1,
637 'no_found_rows' => true,
638 'tax_query' => array(
639 array(
640 'taxonomy' => 'wp_theme',
641 'field' => 'name',
642 'terms' => wp_get_theme()->get_stylesheet(),
643 ),
644 ),
645 );
646
647 if ( 'wp_template_part' === $template_type && isset( $query['area'] ) ) {
648 $wp_query_args['tax_query'][] = array(
649 'taxonomy' => 'wp_template_part_area',
650 'field' => 'name',
651 'terms' => $query['area'],
652 );
653 $wp_query_args['tax_query']['relation'] = 'AND';
654 }
655
656 if ( isset( $query['slug__in'] ) ) {
657 $wp_query_args['post_name__in'] = $query['slug__in'];
658 }
659
660 // This is only needed for the regular templates/template parts CPT listing and editor.
661 if ( isset( $query['wp_id'] ) ) {
662 $wp_query_args['p'] = $query['wp_id'];
663 } else {
664 $wp_query_args['post_status'] = 'publish';
665 }
666
667 $template_query = new WP_Query( $wp_query_args );
668 $query_result = array();
669 foreach ( $template_query->posts as $post ) {
670 $template = _build_block_template_result_from_post( $post );
671
672 if ( is_wp_error( $template ) ) {
673 continue;
674 }
675
676 if ( $post_type && ! $template->is_custom ) {
677 continue;
678 }
679
680 $query_result[] = $template;
681 }
682
683 if ( ! isset( $query['wp_id'] ) ) {
684 $template_files = _get_block_templates_files( $template_type );
685 foreach ( $template_files as $template_file ) {
686 $template = _build_block_template_result_from_file( $template_file, $template_type );
687
688 if ( $post_type && ! $template->is_custom ) {
689 continue;
690 }
691
692 if ( $post_type &&
693 isset( $template->post_types ) &&
694 ! in_array( $post_type, $template->post_types, true )
695 ) {
696 continue;
697 }
698
699 $is_not_custom = false === array_search(
700 wp_get_theme()->get_stylesheet() . '//' . $template_file['slug'],
701 array_column( $query_result, 'id' ),
702 true
703 );
704 $fits_slug_query =
705 ! isset( $query['slug__in'] ) || in_array( $template_file['slug'], $query['slug__in'], true );
706 $fits_area_query =
707 ! isset( $query['area'] ) || $template_file['area'] === $query['area'];
708 $should_include = $is_not_custom && $fits_slug_query && $fits_area_query;
709 if ( $should_include ) {
710 $query_result[] = $template;
711 }
712 }
713 }
714 /**
715 * Filters the array of queried block templates array after they've been fetched.
716 *
717 * @since 10.8
718 *
719 * @param WP_Block_Template[] $query_result Array of found block templates.
720 * @param array $query {
721 * Optional. Arguments to retrieve templates.
722 *
723 * @type array $slug__in List of slugs to include.
724 * @type int $wp_id Post ID of customized template.
725 * }
726 * @param array $template_type wp_template or wp_template_part.
727 */
728 return apply_filters( 'get_block_templates', $query_result, $query, $template_type );
729 }
730
731 /**
732 * Retrieves a single unified template object using its id.
733 *
734 * @param string $id Template unique identifier (example: theme_slug//template_slug).
735 * @param array $template_type wp_template or wp_template_part.
736 *
737 * @return WP_Block_Template|null Template.
738 */
739 function gutenberg_get_block_template( $id, $template_type = 'wp_template' ) {
740 /**
741 * Filters the block template object before the query takes place.
742 *
743 * Return a non-null value to bypass the WordPress queries.
744 *
745 * @since 10.8
746 *
747 * @param WP_Block_Template|null $block_template Return block template object to short-circuit the default query,
748 * or null to allow WP to run it's normal queries.
749 * @param string $id Template unique identifier (example: theme_slug//template_slug).
750 * @param array $template_type wp_template or wp_template_part.
751 */
752 $block_template = apply_filters( 'pre_get_block_template', null, $id, $template_type );
753 if ( ! is_null( $block_template ) ) {
754 return $block_template;
755 }
756
757 $parts = explode( '//', $id, 2 );
758 if ( count( $parts ) < 2 ) {
759 return null;
760 }
761 list( $theme, $slug ) = $parts;
762 $wp_query_args = array(
763 'post_name__in' => array( $slug ),
764 'post_type' => $template_type,
765 'post_status' => array( 'auto-draft', 'draft', 'publish', 'trash' ),
766 'posts_per_page' => 1,
767 'no_found_rows' => true,
768 'tax_query' => array(
769 array(
770 'taxonomy' => 'wp_theme',
771 'field' => 'name',
772 'terms' => $theme,
773 ),
774 ),
775 );
776 $template_query = new WP_Query( $wp_query_args );
777 $posts = $template_query->posts;
778
779 if ( count( $posts ) > 0 ) {
780 $template = _build_block_template_result_from_post( $posts[0] );
781
782 if ( ! is_wp_error( $template ) ) {
783 return $template;
784 }
785 }
786
787 $block_template = get_block_file_template( $id, $template_type );
788
789 /**
790 * Filters the queried block template object after it's been fetched.
791 *
792 * @since 10.8
793 *
794 * @param WP_Block_Template|null $block_template The found block template, or null if there isn't one.
795 * @param string $id Template unique identifier (example: theme_slug//template_slug).
796 * @param array $template_type wp_template or wp_template_part.
797 */
798 return apply_filters( 'get_block_template', $block_template, $id, $template_type );
799 }
800
801 if ( ! function_exists( 'get_block_file_template' ) ) {
802 /**
803 * Retrieves a single unified template object using its id.
804 * Retrieves the file template.
805 *
806 * @param string $id Template unique identifier (example: theme_slug//template_slug).
807 * @param array $template_type wp_template or wp_template_part.
808 *
809 * @return WP_Block_Template|null File template.
810 */
811 function get_block_file_template( $id, $template_type = 'wp_template' ) {
812 /**
813 * Filters the block templates array before the query takes place.
814 *
815 * Return a non-null value to bypass the WordPress queries.
816 *
817 * @since 10.8
818 *
819 * @param WP_Block_Template|null $block_template Return block template object to short-circuit the default query,
820 * or null to allow WP to run it's normal queries.
821 * @param string $id Template unique identifier (example: theme_slug//template_slug).
822 * @param array $template_type wp_template or wp_template_part.
823 */
824 $block_template = apply_filters( 'pre_get_block_file_template', null, $id, $template_type );
825 if ( ! is_null( $block_template ) ) {
826 return $block_template;
827 }
828
829 $parts = explode( '//', $id, 2 );
830 if ( count( $parts ) < 2 ) {
831 /** This filter is documented at the end of this function */
832 return apply_filters( 'get_block_file_template', null, $id, $template_type );
833 }
834 list( $theme, $slug ) = $parts;
835
836 if ( wp_get_theme()->get_stylesheet() !== $theme ) {
837 /** This filter is documented at the end of this function */
838 return apply_filters( 'get_block_file_template', null, $id, $template_type );
839 }
840
841 $template_file = _get_block_template_file( $template_type, $slug );
842 if ( null === $template_file ) {
843 /** This filter is documented at the end of this function */
844 return apply_filters( 'get_block_file_template', null, $id, $template_type );
845 }
846
847 $block_template = _build_block_template_result_from_file( $template_file, $template_type );
848
849 /**
850 * Filters the array of queried block templates array after they've been fetched.
851 *
852 * @since 10.8
853 *
854 * @param null|WP_Block_Template $block_template The found block template.
855 * @param string $id Template unique identifier (example: theme_slug//template_slug).
856 * @param array $template_type wp_template or wp_template_part.
857 */
858 return apply_filters( 'get_block_file_template', $block_template, $id, $template_type );
859 }
860 }
861
862 if ( ! function_exists( 'block_template_part' ) ) {
863 /**
864 * Print a template-part.
865 *
866 * @param string $part The template-part to print. Use "header" or "footer".
867 *
868 * @return void
869 */
870 function block_template_part( $part ) {
871 $template_part = gutenberg_get_block_template( get_stylesheet() . '//' . $part, 'wp_template_part' );
872 if ( ! $template_part || empty( $template_part->content ) ) {
873 return;
874 }
875 echo do_blocks( $template_part->content );
876 }
877 }
878
879 if ( ! function_exists( 'block_header_area' ) ) {
880 /**
881 * Print the header template-part.
882 *
883 * @return void
884 */
885 function block_header_area() {
886 block_template_part( 'header' );
887 }
888 }
889
890 if ( ! function_exists( 'block_footer_area' ) ) {
891 /**
892 * Print the footer template-part.
893 *
894 * @return void
895 */
896 function block_footer_area() {
897 block_template_part( 'footer' );
898 }
899 }
900
901 if ( ! function_exists( 'wp_generate_block_templates_export_file' ) ) {
902 /**
903 * Creates an export of the current templates and
904 * template parts from the site editor at the
905 * specified path in a ZIP file.
906 *
907 * @since 5.9.0
908 *
909 * @return WP_Error|string Path of the ZIP file or error on failure.
910 */
911 function wp_generate_block_templates_export_file() {
912 if ( ! class_exists( 'ZipArchive' ) ) {
913 return new WP_Error( __( 'Zip Export not supported.', 'gutenberg' ) );
914 }
915
916 $obscura = wp_generate_password( 12, false, false );
917 $filename = get_temp_dir() . 'edit-site-export-' . $obscura . '.zip';
918
919 $zip = new ZipArchive();
920 if ( true !== $zip->open( $filename, ZipArchive::CREATE ) ) {
921 return new WP_Error( __( 'Unable to open export file (archive) for writing.', 'gutenberg' ) );
922 }
923
924 $zip->addEmptyDir( 'theme' );
925 $zip->addEmptyDir( 'theme/templates' );
926 $zip->addEmptyDir( 'theme/parts' );
927
928 // Load templates into the zip file.
929 $templates = gutenberg_get_block_templates();
930 foreach ( $templates as $template ) {
931 $template->content = _remove_theme_attribute_in_block_template_content( $template->content );
932
933 $zip->addFromString(
934 'theme/templates/' . $template->slug . '.html',
935 $template->content
936 );
937 }
938
939 // Load template parts into the zip file.
940 $template_parts = gutenberg_get_block_templates( array(), 'wp_template_part' );
941 foreach ( $template_parts as $template_part ) {
942 $zip->addFromString(
943 'theme/parts/' . $template_part->slug . '.html',
944 $template_part->content
945 );
946 }
947
948 // Save changes to the zip file.
949 $zip->close();
950
951 return $filename;
952 }
953 }
954