[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> block-template-utils.php (source)

   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  }


Generated : Fri Aug 19 08:20:02 2022 Cross-referenced by PHPXref