[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[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 * @return string Input if supported, else the uncategorized value. 201 */ 202 function _filter_block_template_part_area( $type ) { 203 $allowed_areas = array_map( 204 static function ( $item ) { 205 return $item['area']; 206 }, 207 get_allowed_block_template_part_areas() 208 ); 209 if ( in_array( $type, $allowed_areas, true ) ) { 210 return $type; 211 } 212 213 $warning_message = sprintf( 214 /* translators: %1$s: Template area type, %2$s: the uncategorized template area value. */ 215 __( '"%1$s" is not a supported wp_template_part area value and has been added as "%2$s".' ), 216 $type, 217 WP_TEMPLATE_PART_AREA_UNCATEGORIZED 218 ); 219 trigger_error( $warning_message, E_USER_NOTICE ); 220 return WP_TEMPLATE_PART_AREA_UNCATEGORIZED; 221 } 222 223 /** 224 * Finds all nested template part file paths in a theme's directory. 225 * 226 * @since 5.9.0 227 * @access private 228 * 229 * @param string $base_directory The theme's file path. 230 * @return array A list of paths to all template part files. 231 */ 232 function _get_block_templates_paths( $base_directory ) { 233 $path_list = array(); 234 if ( file_exists( $base_directory ) ) { 235 $nested_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $base_directory ) ); 236 $nested_html_files = new RegexIterator( $nested_files, '/^.+\.html$/i', RecursiveRegexIterator::GET_MATCH ); 237 foreach ( $nested_html_files as $path => $file ) { 238 $path_list[] = $path; 239 } 240 } 241 return $path_list; 242 } 243 244 /** 245 * Retrieves the template file from the theme for a given slug. 246 * 247 * @since 5.9.0 248 * @access private 249 * 250 * @param string $template_type 'wp_template' or 'wp_template_part'. 251 * @param string $slug Template slug. 252 * @return array|null Template. 253 */ 254 function _get_block_template_file( $template_type, $slug ) { 255 if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) { 256 return null; 257 } 258 259 $themes = array( 260 get_stylesheet() => get_stylesheet_directory(), 261 get_template() => get_template_directory(), 262 ); 263 foreach ( $themes as $theme_slug => $theme_dir ) { 264 $template_base_paths = get_block_theme_folders( $theme_slug ); 265 $file_path = $theme_dir . '/' . $template_base_paths[ $template_type ] . '/' . $slug . '.html'; 266 if ( file_exists( $file_path ) ) { 267 $new_template_item = array( 268 'slug' => $slug, 269 'path' => $file_path, 270 'theme' => $theme_slug, 271 'type' => $template_type, 272 ); 273 274 if ( 'wp_template_part' === $template_type ) { 275 return _add_block_template_part_area_info( $new_template_item ); 276 } 277 278 if ( 'wp_template' === $template_type ) { 279 return _add_block_template_info( $new_template_item ); 280 } 281 282 return $new_template_item; 283 } 284 } 285 286 return null; 287 } 288 289 /** 290 * Retrieves the template files from the theme. 291 * 292 * @since 5.9.0 293 * @access private 294 * 295 * @param string $template_type 'wp_template' or 'wp_template_part'. 296 * @return array Template. 297 */ 298 function _get_block_templates_files( $template_type ) { 299 if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) { 300 return null; 301 } 302 303 $themes = array( 304 get_stylesheet() => get_stylesheet_directory(), 305 get_template() => get_template_directory(), 306 ); 307 $template_files = array(); 308 foreach ( $themes as $theme_slug => $theme_dir ) { 309 $template_base_paths = get_block_theme_folders( $theme_slug ); 310 $theme_template_files = _get_block_templates_paths( $theme_dir . '/' . $template_base_paths[ $template_type ] ); 311 foreach ( $theme_template_files as $template_file ) { 312 $template_base_path = $template_base_paths[ $template_type ]; 313 $template_slug = substr( 314 $template_file, 315 // Starting position of slug. 316 strpos( $template_file, $template_base_path . DIRECTORY_SEPARATOR ) + 1 + strlen( $template_base_path ), 317 // Subtract ending '.html'. 318 -5 319 ); 320 $new_template_item = array( 321 'slug' => $template_slug, 322 'path' => $template_file, 323 'theme' => $theme_slug, 324 'type' => $template_type, 325 ); 326 327 if ( 'wp_template_part' === $template_type ) { 328 $template_files[] = _add_block_template_part_area_info( $new_template_item ); 329 } 330 331 if ( 'wp_template' === $template_type ) { 332 $template_files[] = _add_block_template_info( $new_template_item ); 333 } 334 } 335 } 336 337 return $template_files; 338 } 339 340 /** 341 * Attempts to add custom template information to the template item. 342 * 343 * @since 5.9.0 344 * @access private 345 * 346 * @param array $template_item Template to add information to (requires 'slug' field). 347 * @return array Template item. 348 */ 349 function _add_block_template_info( $template_item ) { 350 if ( ! WP_Theme_JSON_Resolver::theme_has_support() ) { 351 return $template_item; 352 } 353 354 $theme_data = WP_Theme_JSON_Resolver::get_theme_data()->get_custom_templates(); 355 if ( isset( $theme_data[ $template_item['slug'] ] ) ) { 356 $template_item['title'] = $theme_data[ $template_item['slug'] ]['title']; 357 $template_item['postTypes'] = $theme_data[ $template_item['slug'] ]['postTypes']; 358 } 359 360 return $template_item; 361 } 362 363 /** 364 * Attempts to add the template part's area information to the input template. 365 * 366 * @since 5.9.0 367 * @access private 368 * 369 * @param array $template_info Template to add information to (requires 'type' and 'slug' fields). 370 * @return array Template info. 371 */ 372 function _add_block_template_part_area_info( $template_info ) { 373 if ( WP_Theme_JSON_Resolver::theme_has_support() ) { 374 $theme_data = WP_Theme_JSON_Resolver::get_theme_data()->get_template_parts(); 375 } 376 377 if ( isset( $theme_data[ $template_info['slug'] ]['area'] ) ) { 378 $template_info['title'] = $theme_data[ $template_info['slug'] ]['title']; 379 $template_info['area'] = _filter_block_template_part_area( $theme_data[ $template_info['slug'] ]['area'] ); 380 } else { 381 $template_info['area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; 382 } 383 384 return $template_info; 385 } 386 387 /** 388 * Returns an array containing the references of 389 * the passed blocks and their inner blocks. 390 * 391 * @since 5.9.0 392 * @access private 393 * 394 * @param array $blocks array of blocks. 395 * @return array block references to the passed blocks and their inner blocks. 396 */ 397 function _flatten_blocks( &$blocks ) { 398 $all_blocks = array(); 399 $queue = array(); 400 foreach ( $blocks as &$block ) { 401 $queue[] = &$block; 402 } 403 404 while ( count( $queue ) > 0 ) { 405 $block = &$queue[0]; 406 array_shift( $queue ); 407 $all_blocks[] = &$block; 408 409 if ( ! empty( $block['innerBlocks'] ) ) { 410 foreach ( $block['innerBlocks'] as &$inner_block ) { 411 $queue[] = &$inner_block; 412 } 413 } 414 } 415 416 return $all_blocks; 417 } 418 419 /** 420 * Parses wp_template content and injects the active theme's 421 * stylesheet as a theme attribute into each wp_template_part 422 * 423 * @since 5.9.0 424 * @access private 425 * 426 * @param string $template_content serialized wp_template content. 427 * @return string Updated 'wp_template' content. 428 */ 429 function _inject_theme_attribute_in_block_template_content( $template_content ) { 430 $has_updated_content = false; 431 $new_content = ''; 432 $template_blocks = parse_blocks( $template_content ); 433 434 $blocks = _flatten_blocks( $template_blocks ); 435 foreach ( $blocks as &$block ) { 436 if ( 437 'core/template-part' === $block['blockName'] && 438 ! isset( $block['attrs']['theme'] ) 439 ) { 440 $block['attrs']['theme'] = wp_get_theme()->get_stylesheet(); 441 $has_updated_content = true; 442 } 443 } 444 445 if ( $has_updated_content ) { 446 foreach ( $template_blocks as &$block ) { 447 $new_content .= serialize_block( $block ); 448 } 449 450 return $new_content; 451 } 452 453 return $template_content; 454 } 455 456 /** 457 * Parses a block template and removes the theme attribute from each template part. 458 * 459 * @since 5.9.0 460 * @access private 461 * 462 * @param string $template_content Serialized block template content. 463 * @return string Updated block template content. 464 */ 465 function _remove_theme_attribute_in_block_template_content( $template_content ) { 466 $has_updated_content = false; 467 $new_content = ''; 468 $template_blocks = parse_blocks( $template_content ); 469 470 $blocks = _flatten_blocks( $template_blocks ); 471 foreach ( $blocks as $key => $block ) { 472 if ( 'core/template-part' === $block['blockName'] && isset( $block['attrs']['theme'] ) ) { 473 unset( $blocks[ $key ]['attrs']['theme'] ); 474 $has_updated_content = true; 475 } 476 } 477 478 if ( ! $has_updated_content ) { 479 return $template_content; 480 } 481 482 foreach ( $template_blocks as $block ) { 483 $new_content .= serialize_block( $block ); 484 } 485 486 return $new_content; 487 } 488 489 /** 490 * Builds a unified template object based on a theme file. 491 * 492 * @since 5.9.0 493 * @access private 494 * 495 * @param array $template_file Theme file. 496 * @param string $template_type 'wp_template' or 'wp_template_part'. 497 * @return WP_Block_Template Template. 498 */ 499 function _build_block_template_result_from_file( $template_file, $template_type ) { 500 $default_template_types = get_default_block_template_types(); 501 $template_content = file_get_contents( $template_file['path'] ); 502 $theme = wp_get_theme()->get_stylesheet(); 503 504 $template = new WP_Block_Template(); 505 $template->id = $theme . '//' . $template_file['slug']; 506 $template->theme = $theme; 507 $template->content = _inject_theme_attribute_in_block_template_content( $template_content ); 508 $template->slug = $template_file['slug']; 509 $template->source = 'theme'; 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 516 if ( 'wp_template' === $template_type && isset( $default_template_types[ $template_file['slug'] ] ) ) { 517 $template->description = $default_template_types[ $template_file['slug'] ]['description']; 518 $template->title = $default_template_types[ $template_file['slug'] ]['title']; 519 $template->is_custom = false; 520 } 521 522 if ( 'wp_template' === $template_type && isset( $template_file['postTypes'] ) ) { 523 $template->post_types = $template_file['postTypes']; 524 } 525 526 if ( 'wp_template_part' === $template_type && isset( $template_file['area'] ) ) { 527 $template->area = $template_file['area']; 528 } 529 530 return $template; 531 } 532 533 /** 534 * Builds a unified template object based a post Object. 535 * 536 * @since 5.9.0 537 * @access private 538 * 539 * @param WP_Post $post Template post. 540 * @return WP_Block_Template|WP_Error Template. 541 */ 542 function _build_block_template_result_from_post( $post ) { 543 $default_template_types = get_default_block_template_types(); 544 $terms = get_the_terms( $post, 'wp_theme' ); 545 546 if ( is_wp_error( $terms ) ) { 547 return $terms; 548 } 549 550 if ( ! $terms ) { 551 return new WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.' ) ); 552 } 553 554 $theme = $terms[0]->name; 555 $has_theme_file = wp_get_theme()->get_stylesheet() === $theme && 556 null !== _get_block_template_file( $post->post_type, $post->post_name ); 557 558 $origin = get_post_meta( $post->ID, 'origin', true ); 559 560 $template = new WP_Block_Template(); 561 $template->wp_id = $post->ID; 562 $template->id = $theme . '//' . $post->post_name; 563 $template->theme = $theme; 564 $template->content = $post->post_content; 565 $template->slug = $post->post_name; 566 $template->source = 'custom'; 567 $template->origin = ! empty( $origin ) ? $origin : null; 568 $template->type = $post->post_type; 569 $template->description = $post->post_excerpt; 570 $template->title = $post->post_title; 571 $template->status = $post->post_status; 572 $template->has_theme_file = $has_theme_file; 573 $template->is_custom = true; 574 $template->author = $post->post_author; 575 576 if ( 'wp_template' === $post->post_type && isset( $default_template_types[ $template->slug ] ) ) { 577 $template->is_custom = false; 578 } 579 580 if ( 'wp_template_part' === $post->post_type ) { 581 $type_terms = get_the_terms( $post, 'wp_template_part_area' ); 582 if ( ! is_wp_error( $type_terms ) && false !== $type_terms ) { 583 $template->area = $type_terms[0]->name; 584 } 585 } 586 587 return $template; 588 } 589 590 /** 591 * Retrieves a list of unified template objects based on a query. 592 * 593 * @since 5.8.0 594 * 595 * @param array $query { 596 * Optional. Arguments to retrieve templates. 597 * 598 * @type array $slug__in List of slugs to include. 599 * @type int $wp_id Post ID of customized template. 600 * @type string $area A 'wp_template_part_area' taxonomy value to filter by (for wp_template_part template type only). 601 * @type string $post_type Post type to get the templates for. 602 * } 603 * @param string $template_type 'wp_template' or 'wp_template_part'. 604 * @return array Templates. 605 */ 606 function get_block_templates( $query = array(), $template_type = 'wp_template' ) { 607 /** 608 * Filters the block templates array before the query takes place. 609 * 610 * Return a non-null value to bypass the WordPress queries. 611 * 612 * @since 5.9.0 613 * 614 * @param WP_Block_Template[]|null $block_templates Return an array of block templates to short-circuit the default query, 615 * or null to allow WP to run it's normal queries. 616 * @param array $query { 617 * Optional. Arguments to retrieve templates. 618 * 619 * @type array $slug__in List of slugs to include. 620 * @type int $wp_id Post ID of customized template. 621 * @type string $post_type Post type to get the templates for. 622 * } 623 * @param string $template_type wp_template or wp_template_part. 624 */ 625 $templates = apply_filters( 'pre_get_block_templates', null, $query, $template_type ); 626 if ( ! is_null( $templates ) ) { 627 return $templates; 628 } 629 630 $post_type = isset( $query['post_type'] ) ? $query['post_type'] : ''; 631 $wp_query_args = array( 632 'post_status' => array( 'auto-draft', 'draft', 'publish' ), 633 'post_type' => $template_type, 634 'posts_per_page' => -1, 635 'no_found_rows' => true, 636 'tax_query' => array( 637 array( 638 'taxonomy' => 'wp_theme', 639 'field' => 'name', 640 'terms' => wp_get_theme()->get_stylesheet(), 641 ), 642 ), 643 ); 644 645 if ( 'wp_template_part' === $template_type && isset( $query['area'] ) ) { 646 $wp_query_args['tax_query'][] = array( 647 'taxonomy' => 'wp_template_part_area', 648 'field' => 'name', 649 'terms' => $query['area'], 650 ); 651 $wp_query_args['tax_query']['relation'] = 'AND'; 652 } 653 654 if ( isset( $query['slug__in'] ) ) { 655 $wp_query_args['post_name__in'] = $query['slug__in']; 656 } 657 658 // This is only needed for the regular templates/template parts post type listing and editor. 659 if ( isset( $query['wp_id'] ) ) { 660 $wp_query_args['p'] = $query['wp_id']; 661 } else { 662 $wp_query_args['post_status'] = 'publish'; 663 } 664 665 $template_query = new WP_Query( $wp_query_args ); 666 $query_result = array(); 667 foreach ( $template_query->posts as $post ) { 668 $template = _build_block_template_result_from_post( $post ); 669 670 if ( is_wp_error( $template ) ) { 671 continue; 672 } 673 674 if ( $post_type && ! $template->is_custom ) { 675 continue; 676 } 677 678 $query_result[] = $template; 679 } 680 681 if ( ! isset( $query['wp_id'] ) ) { 682 $template_files = _get_block_templates_files( $template_type ); 683 foreach ( $template_files as $template_file ) { 684 $template = _build_block_template_result_from_file( $template_file, $template_type ); 685 686 if ( $post_type && ! $template->is_custom ) { 687 continue; 688 } 689 690 if ( $post_type && 691 isset( $template->post_types ) && 692 ! in_array( $post_type, $template->post_types, true ) 693 ) { 694 continue; 695 } 696 697 $is_not_custom = false === array_search( 698 wp_get_theme()->get_stylesheet() . '//' . $template_file['slug'], 699 array_column( $query_result, 'id' ), 700 true 701 ); 702 $fits_slug_query = 703 ! isset( $query['slug__in'] ) || in_array( $template_file['slug'], $query['slug__in'], true ); 704 $fits_area_query = 705 ! isset( $query['area'] ) || $template_file['area'] === $query['area']; 706 $should_include = $is_not_custom && $fits_slug_query && $fits_area_query; 707 if ( $should_include ) { 708 $query_result[] = $template; 709 } 710 } 711 } 712 713 /** 714 * Filters the array of queried block templates array after they've been fetched. 715 * 716 * @since 5.9.0 717 * 718 * @param WP_Block_Template[] $query_result Array of found block templates. 719 * @param array $query { 720 * Optional. Arguments to retrieve templates. 721 * 722 * @type array $slug__in List of slugs to include. 723 * @type int $wp_id Post ID of customized template. 724 * } 725 * @param string $template_type wp_template or wp_template_part. 726 */ 727 return apply_filters( 'get_block_templates', $query_result, $query, $template_type ); 728 } 729 730 /** 731 * Retrieves a single unified template object using its id. 732 * 733 * @since 5.8.0 734 * 735 * @param string $id Template unique identifier (example: theme_slug//template_slug). 736 * @param string $template_type Optional. Template type: `'wp_template'` or '`wp_template_part'`. 737 * Default `'wp_template'`. 738 * @return WP_Block_Template|null Template. 739 */ 740 function get_block_template( $id, $template_type = 'wp_template' ) { 741 /** 742 * Filters the block template object before the query takes place. 743 * 744 * Return a non-null value to bypass the WordPress queries. 745 * 746 * @since 5.9.0 747 * 748 * @param WP_Block_Template|null $block_template Return block template object to short-circuit the default query, 749 * or null to allow WP to run its normal queries. 750 * @param string $id Template unique identifier (example: theme_slug//template_slug). 751 * @param string $template_type Template type: `'wp_template'` or '`wp_template_part'`. 752 */ 753 $block_template = apply_filters( 'pre_get_block_template', null, $id, $template_type ); 754 if ( ! is_null( $block_template ) ) { 755 return $block_template; 756 } 757 758 $parts = explode( '//', $id, 2 ); 759 if ( count( $parts ) < 2 ) { 760 return null; 761 } 762 list( $theme, $slug ) = $parts; 763 $wp_query_args = array( 764 'post_name__in' => array( $slug ), 765 'post_type' => $template_type, 766 'post_status' => array( 'auto-draft', 'draft', 'publish', 'trash' ), 767 'posts_per_page' => 1, 768 'no_found_rows' => true, 769 'tax_query' => array( 770 array( 771 'taxonomy' => 'wp_theme', 772 'field' => 'name', 773 'terms' => $theme, 774 ), 775 ), 776 ); 777 $template_query = new WP_Query( $wp_query_args ); 778 $posts = $template_query->posts; 779 780 if ( count( $posts ) > 0 ) { 781 $template = _build_block_template_result_from_post( $posts[0] ); 782 783 if ( ! is_wp_error( $template ) ) { 784 return $template; 785 } 786 } 787 788 $block_template = get_block_file_template( $id, $template_type ); 789 790 /** 791 * Filters the queried block template object after it's been fetched. 792 * 793 * @since 5.9.0 794 * 795 * @param WP_Block_Template|null $block_template The found block template, or null if there isn't one. 796 * @param string $id Template unique identifier (example: theme_slug//template_slug). 797 * @param array $template_type Template type: `'wp_template'` or '`wp_template_part'`. 798 */ 799 return apply_filters( 'get_block_template', $block_template, $id, $template_type ); 800 } 801 802 /** 803 * Retrieves a single unified template object using its id. 804 * 805 * @since 5.9.0 806 * 807 * @param string $id Template unique identifier (example: theme_slug//template_slug). 808 * @param string $template_type Optional. Template type: `'wp_template'` or '`wp_template_part'`. 809 * Default `'wp_template'`. 810 * @return WP_Block_Template|null The found block template, or null if there isn't one. 811 */ 812 function get_block_file_template( $id, $template_type = 'wp_template' ) { 813 /** 814 * Filters the block templates array before the query takes place. 815 * 816 * Return a non-null value to bypass the WordPress queries. 817 * 818 * @since 5.9.0 819 * 820 * @param WP_Block_Template|null $block_template Return block template object to short-circuit the default query, 821 * or null to allow WP to run its normal queries. 822 * @param string $id Template unique identifier (example: theme_slug//template_slug). 823 * @param string $template_type Template type: `'wp_template'` or '`wp_template_part'`. 824 */ 825 $block_template = apply_filters( 'pre_get_block_file_template', null, $id, $template_type ); 826 if ( ! is_null( $block_template ) ) { 827 return $block_template; 828 } 829 830 $parts = explode( '//', $id, 2 ); 831 if ( count( $parts ) < 2 ) { 832 /** This filter is documented in wp-includes/block-template-utils.php */ 833 return apply_filters( 'get_block_file_template', null, $id, $template_type ); 834 } 835 list( $theme, $slug ) = $parts; 836 837 if ( wp_get_theme()->get_stylesheet() !== $theme ) { 838 /** This filter is documented in wp-includes/block-template-utils.php */ 839 return apply_filters( 'get_block_file_template', null, $id, $template_type ); 840 } 841 842 $template_file = _get_block_template_file( $template_type, $slug ); 843 if ( null === $template_file ) { 844 /** This filter is documented in wp-includes/block-template-utils.php */ 845 return apply_filters( 'get_block_file_template', null, $id, $template_type ); 846 } 847 848 $block_template = _build_block_template_result_from_file( $template_file, $template_type ); 849 850 /** 851 * Filters the array of queried block templates array after they've been fetched. 852 * 853 * @since 5.9.0 854 * 855 * @param WP_Block_Template|null $block_template The found block template, or null if there is none. 856 * @param string $id Template unique identifier (example: theme_slug//template_slug). 857 * @param string $template_type Template type: `'wp_template'` or '`wp_template_part'`. 858 */ 859 return apply_filters( 'get_block_file_template', $block_template, $id, $template_type ); 860 } 861 862 /** 863 * Prints a template-part. 864 * 865 * @since 5.9.0 866 * 867 * @param string $part The template-part to print. Use "header" or "footer". 868 */ 869 function block_template_part( $part ) { 870 $template_part = get_block_template( get_stylesheet() . '//' . $part, 'wp_template_part' ); 871 if ( ! $template_part || empty( $template_part->content ) ) { 872 return; 873 } 874 echo do_blocks( $template_part->content ); 875 } 876 877 /** 878 * Prints the header template-part. 879 * 880 * @since 5.9.0 881 */ 882 function block_header_area() { 883 block_template_part( 'header' ); 884 } 885 886 /** 887 * Prints the footer template-part. 888 * 889 * @since 5.9.0 890 */ 891 function block_footer_area() { 892 block_template_part( 'footer' ); 893 } 894 895 /** 896 * Determines whether a theme directory should be ignored during export. 897 * 898 * @since 6.0.0 899 * 900 * @param string $path The path of the file in the theme. 901 * @return Bool Whether this file is in an ignored directory. 902 */ 903 function wp_is_theme_directory_ignored( $path ) { 904 $directories_to_ignore = array( '.svn', '.git', '.hg', '.bzr', 'node_modules', 'vendor' ); 905 foreach ( $directories_to_ignore as $directory ) { 906 if ( strpos( $path, $directory ) === 0 ) { 907 return true; 908 } 909 } 910 911 return false; 912 } 913 914 /** 915 * Creates an export of the current templates and 916 * template parts from the site editor at the 917 * specified path in a ZIP file. 918 * 919 * @since 5.9.0 920 * @since 6.0.0 Adds the whole theme to the export archive. 921 * 922 * @return WP_Error|string Path of the ZIP file or error on failure. 923 */ 924 function wp_generate_block_templates_export_file() { 925 if ( ! class_exists( 'ZipArchive' ) ) { 926 return new WP_Error( 'missing_zip_package', __( 'Zip Export not supported.' ) ); 927 } 928 929 $obscura = wp_generate_password( 12, false, false ); 930 $theme_name = basename( get_stylesheet() ); 931 $filename = get_temp_dir() . $theme_name . $obscura . '.zip'; 932 933 $zip = new ZipArchive(); 934 if ( true !== $zip->open( $filename, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) { 935 return new WP_Error( 'unable_to_create_zip', __( 'Unable to open export file (archive) for writing.' ) ); 936 } 937 938 $zip->addEmptyDir( 'templates' ); 939 $zip->addEmptyDir( 'parts' ); 940 941 // Get path of the theme. 942 $theme_path = wp_normalize_path( get_stylesheet_directory() ); 943 944 // Create recursive directory iterator. 945 $theme_files = new RecursiveIteratorIterator( 946 new RecursiveDirectoryIterator( $theme_path ), 947 RecursiveIteratorIterator::LEAVES_ONLY 948 ); 949 950 // Make a copy of the current theme. 951 foreach ( $theme_files as $file ) { 952 // Skip directories as they are added automatically. 953 if ( ! $file->isDir() ) { 954 // Get real and relative path for current file. 955 $file_path = wp_normalize_path( $file ); 956 $relative_path = substr( $file_path, strlen( $theme_path ) + 1 ); 957 958 if ( ! wp_is_theme_directory_ignored( $relative_path ) ) { 959 $zip->addFile( $file_path, $relative_path ); 960 } 961 } 962 } 963 964 // Load templates into the zip file. 965 $templates = get_block_templates(); 966 foreach ( $templates as $template ) { 967 $template->content = _remove_theme_attribute_in_block_template_content( $template->content ); 968 969 $zip->addFromString( 970 'templates/' . $template->slug . '.html', 971 $template->content 972 ); 973 } 974 975 // Load template parts into the zip file. 976 $template_parts = get_block_templates( array(), 'wp_template_part' ); 977 foreach ( $template_parts as $template_part ) { 978 $zip->addFromString( 979 'parts/' . $template_part->slug . '.html', 980 $template_part->content 981 ); 982 } 983 984 // Load theme.json into the zip file. 985 $tree = WP_Theme_JSON_Resolver::get_theme_data( array(), array( 'with_supports' => false ) ); 986 // Merge with user data. 987 $tree->merge( WP_Theme_JSON_Resolver::get_user_data() ); 988 989 $theme_json_raw = $tree->get_data(); 990 // If a version is defined, add a schema. 991 if ( $theme_json_raw['version'] ) { 992 global $wp_version; 993 $theme_json_version = 'wp/' . substr( $wp_version, 0, 3 ); 994 $schema = array( '$schema' => 'https://schemas.wp.org/' . $theme_json_version . '/theme.json' ); 995 $theme_json_raw = array_merge( $schema, $theme_json_raw ); 996 } 997 998 // Convert to a string. 999 $theme_json_encoded = wp_json_encode( $theme_json_raw, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); 1000 1001 // Replace 4 spaces with a tab. 1002 $theme_json_tabbed = preg_replace( '~(?:^|\G)\h{4}~m', "\t", $theme_json_encoded ); 1003 1004 // Add the theme.json file to the zip. 1005 $zip->addFromString( 1006 'theme.json', 1007 $theme_json_tabbed 1008 ); 1009 1010 // Save changes to the zip file. 1011 $zip->close(); 1012 1013 return $filename; 1014 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Fri Aug 19 08:20:02 2022 | Cross-referenced by PHPXref |