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