Make WordPress Core


Ignore:
Timestamp:
11/08/2021 11:09:53 PM (3 years ago)
Author:
noisysocks
Message:

Editor: Add block theme infrastructure

Adds the required infrastructure to render block-based themes. This is sourced
from the Gutenberg plugin.

Fixes #54335.
Props bernhard-reiter, youknowriad, ntsekouras, hellofromtonya.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/block-template-utils.php

    r51300 r52062  
    11<?php
    22/**
    3  * Utilities used to fetch and create templates.
     3 * Utilities used to fetch and create templates and template parts.
    44 *
    55 * @package WordPress
     
    77 */
    88
     9// Define constants for supported wp_template_part_area taxonomy.
     10if ( ! defined( 'WP_TEMPLATE_PART_AREA_HEADER' ) ) {
     11    define( 'WP_TEMPLATE_PART_AREA_HEADER', 'header' );
     12}
     13if ( ! defined( 'WP_TEMPLATE_PART_AREA_FOOTER' ) ) {
     14    define( 'WP_TEMPLATE_PART_AREA_FOOTER', 'footer' );
     15}
     16if ( ! defined( 'WP_TEMPLATE_PART_AREA_SIDEBAR' ) ) {
     17    define( 'WP_TEMPLATE_PART_AREA_SIDEBAR', 'sidebar' );
     18}
     19if ( ! defined( 'WP_TEMPLATE_PART_AREA_UNCATEGORIZED' ) ) {
     20    define( 'WP_TEMPLATE_PART_AREA_UNCATEGORIZED', 'uncategorized' );
     21}
     22
     23/**
     24 * Returns a filtered list of allowed area values for template parts.
     25 *
     26 * @since 5.9.0
     27 *
     28 * @return array The supported template part area values.
     29 */
     30function get_allowed_block_template_part_areas() {
     31    $default_area_definitions = array(
     32        array(
     33            'area'        => WP_TEMPLATE_PART_AREA_UNCATEGORIZED,
     34            'label'       => __( 'General' ),
     35            'description' => __(
     36                'General templates often perform a specific role like displaying post content, and are not tied to any particular area.'
     37            ),
     38            'icon'        => 'layout',
     39            'area_tag'    => 'div',
     40        ),
     41        array(
     42            'area'        => WP_TEMPLATE_PART_AREA_HEADER,
     43            'label'       => __( 'Header' ),
     44            'description' => __(
     45                'The Header template defines a page area that typically contains a title, logo, and main navigation.'
     46            ),
     47            'icon'        => 'header',
     48            'area_tag'    => 'header',
     49        ),
     50        array(
     51            'area'        => WP_TEMPLATE_PART_AREA_FOOTER,
     52            'label'       => __( 'Footer' ),
     53            'description' => __(
     54                'The Footer template defines a page area that typically contains site credits, social links, or any other combination of blocks.'
     55            ),
     56            'icon'        => 'footer',
     57            'area_tag'    => 'footer',
     58        ),
     59    );
     60
     61    /**
     62     * Filters the list of allowed template part area values.
     63     *
     64     * @since 5.9.0
     65     *
     66     * @param array $default_areas An array of supported area objects.
     67     */
     68    return apply_filters( 'default_wp_template_part_areas', $default_area_definitions );
     69}
     70
     71
     72/**
     73 * Returns a filtered list of default template types, containing their
     74 * localized titles and descriptions.
     75 *
     76 * @since 5.9.0
     77 *
     78 * @return array The default template types.
     79 */
     80function get_default_block_template_types() {
     81    $default_template_types = array(
     82        'index'          => array(
     83            'title'       => _x( 'Index', 'Template name' ),
     84            'description' => __( 'The default template used when no other template is available. This is a required template in WordPress.' ),
     85        ),
     86        'home'           => array(
     87            'title'       => _x( 'Home', 'Template name' ),
     88            'description' => __( 'Template used for the main page that displays blog posts. This is the front page by default in WordPress. If a static front page is set, this is the template used for the page that contains the latest blog posts.' ),
     89        ),
     90        'front-page'     => array(
     91            'title'       => _x( 'Front Page', 'Template name' ),
     92            'description' => __( 'Template used to render the front page of the site, whether it displays blog posts or a static page. The front page template takes precedence over the "Home" template.' ),
     93        ),
     94        'singular'       => array(
     95            'title'       => _x( 'Singular', 'Template name' ),
     96            'description' => __( 'Template used for displaying single views of the content. This template is a fallback for the Single, Post, and Page templates, which take precedence when they exist.' ),
     97        ),
     98        'single'         => array(
     99            'title'       => _x( 'Single Post', 'Template name' ),
     100            'description' => __( 'Template used to display a single blog post.' ),
     101        ),
     102        'page'           => array(
     103            'title'       => _x( 'Page', 'Template name' ),
     104            'description' => __( 'Template used to display individual pages.' ),
     105        ),
     106        'archive'        => array(
     107            'title'       => _x( 'Archive', 'Template name' ),
     108            'description' => __( 'The archive template displays multiple entries at once. It is used as a fallback for the Category, Author, and Date templates, which take precedence when they are available.' ),
     109        ),
     110        'author'         => array(
     111            'title'       => _x( 'Author', 'Template name' ),
     112            'description' => __( 'Archive template used to display a list of posts from a single author.' ),
     113        ),
     114        'category'       => array(
     115            'title'       => _x( 'Category', 'Template name' ),
     116            'description' => __( 'Archive template used to display a list of posts from the same category.' ),
     117        ),
     118        'taxonomy'       => array(
     119            'title'       => _x( 'Taxonomy', 'Template name' ),
     120            'description' => __( 'Archive template used to display a list of posts from the same taxonomy.' ),
     121        ),
     122        'date'           => array(
     123            'title'       => _x( 'Date', 'Template name' ),
     124            'description' => __( 'Archive template used to display a list of posts from a specific date.' ),
     125        ),
     126        'tag'            => array(
     127            'title'       => _x( 'Tag', 'Template name' ),
     128            'description' => __( 'Archive template used to display a list of posts with a given tag.' ),
     129        ),
     130        'attachment'     => array(
     131            'title'       => __( 'Media' ),
     132            'description' => __( 'Template used to display individual media items or attachments.' ),
     133        ),
     134        'search'         => array(
     135            'title'       => _x( 'Search', 'Template name' ),
     136            'description' => __( 'Template used to display search results.' ),
     137        ),
     138        'privacy-policy' => array(
     139            'title'       => __( 'Privacy Policy' ),
     140            'description' => '',
     141        ),
     142        '404'            => array(
     143            'title'       => _x( '404', 'Template name' ),
     144            'description' => __( 'Template shown when no content is found.' ),
     145        ),
     146    );
     147
     148    /**
     149     * Filters the list of template types.
     150     *
     151     * @since 5.9.0
     152     *
     153     * @param array $default_template_types An array of template types, formatted as [ slug => [ title, description ] ].
     154     */
     155    return apply_filters( 'default_template_types', $default_template_types );
     156}
     157
     158/**
     159 * Checks whether the input 'area' is a supported value.
     160 * Returns the input if supported, otherwise returns the 'uncategorized' value.
     161 *
     162 * @access private
     163 * @since 5.9.0
     164 *
     165 * @param string $type Template part area name.
     166 *
     167 * @return string Input if supported, else the uncategorized value.
     168 */
     169function _filter_block_template_part_area( $type ) {
     170    $allowed_areas = array_map(
     171        static function ( $item ) {
     172            return $item['area'];
     173        },
     174        get_allowed_block_template_part_areas()
     175    );
     176    if ( in_array( $type, $allowed_areas, true ) ) {
     177        return $type;
     178    }
     179
     180    $warning_message = sprintf(
     181        /* translators: %1$s: Template area type, %2$s: the uncategorized template area value. */
     182        __( '"%1$s" is not a supported wp_template_part area value and has been added as "%2$s".' ),
     183        $type,
     184        WP_TEMPLATE_PART_AREA_UNCATEGORIZED
     185    );
     186    trigger_error( $warning_message, E_USER_NOTICE );
     187    return WP_TEMPLATE_PART_AREA_UNCATEGORIZED;
     188}
     189
     190/**
     191 * Finds all nested template part file paths in a theme's directory.
     192 *
     193 * @access private
     194 * @since 5.9.0
     195 *
     196 * @param string $base_directory The theme's file path.
     197 * @return array $path_list A list of paths to all template part files.
     198 */
     199function _get_block_templates_paths( $base_directory ) {
     200    $path_list = array();
     201    if ( file_exists( $base_directory ) ) {
     202        $nested_files      = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $base_directory ) );
     203        $nested_html_files = new RegexIterator( $nested_files, '/^.+\.html$/i', RecursiveRegexIterator::GET_MATCH );
     204        foreach ( $nested_html_files as $path => $file ) {
     205            $path_list[] = $path;
     206        }
     207    }
     208    return $path_list;
     209}
     210
     211/**
     212 * Retrieves the template file from the theme for a given slug.
     213 *
     214 * @access private
     215 * @since 5.9.0
     216 *
     217 * @param string $template_type wp_template or wp_template_part.
     218 * @param string $slug template slug.
     219 *
     220 * @return array|null Template.
     221 */
     222function _get_block_template_file( $template_type, $slug ) {
     223    if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) {
     224        return null;
     225    }
     226
     227    $template_base_paths = array(
     228        'wp_template'      => 'block-templates',
     229        'wp_template_part' => 'block-template-parts',
     230    );
     231    $themes              = array(
     232        get_stylesheet() => get_stylesheet_directory(),
     233        get_template()   => get_template_directory(),
     234    );
     235    foreach ( $themes as $theme_slug => $theme_dir ) {
     236        $file_path = $theme_dir . '/' . $template_base_paths[ $template_type ] . '/' . $slug . '.html';
     237        if ( file_exists( $file_path ) ) {
     238            $new_template_item = array(
     239                'slug'  => $slug,
     240                'path'  => $file_path,
     241                'theme' => $theme_slug,
     242                'type'  => $template_type,
     243            );
     244
     245            if ( 'wp_template_part' === $template_type ) {
     246                return _add_block_template_part_area_info( $new_template_item );
     247            }
     248
     249            if ( 'wp_template' === $template_type ) {
     250                return _add_block_template_info( $new_template_item );
     251            }
     252
     253            return $new_template_item;
     254        }
     255    }
     256
     257    return null;
     258}
     259
     260/**
     261 * Retrieves the template files from  the theme.
     262 *
     263 * @access private
     264 * @since 5.9.0
     265 *
     266 * @param string $template_type wp_template or wp_template_part.
     267 *
     268 * @return array Template.
     269 */
     270function _get_block_templates_files( $template_type ) {
     271    if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) {
     272        return null;
     273    }
     274
     275    $template_base_paths = array(
     276        'wp_template'      => 'block-templates',
     277        'wp_template_part' => 'block-template-parts',
     278    );
     279    $themes              = array(
     280        get_stylesheet() => get_stylesheet_directory(),
     281        get_template()   => get_template_directory(),
     282    );
     283
     284    $template_files = array();
     285    foreach ( $themes as $theme_slug => $theme_dir ) {
     286        $theme_template_files = _get_block_templates_paths( $theme_dir . '/' . $template_base_paths[ $template_type ] );
     287        foreach ( $theme_template_files as $template_file ) {
     288            $template_base_path = $template_base_paths[ $template_type ];
     289            $template_slug      = substr(
     290                $template_file,
     291                // Starting position of slug.
     292                strpos( $template_file, $template_base_path . DIRECTORY_SEPARATOR ) + 1 + strlen( $template_base_path ),
     293                // Subtract ending '.html'.
     294                -5
     295            );
     296            $new_template_item = array(
     297                'slug'  => $template_slug,
     298                'path'  => $template_file,
     299                'theme' => $theme_slug,
     300                'type'  => $template_type,
     301            );
     302
     303            if ( 'wp_template_part' === $template_type ) {
     304                $template_files[] = _add_block_template_part_area_info( $new_template_item );
     305            }
     306
     307            if ( 'wp_template' === $template_type ) {
     308                $template_files[] = _add_block_template_info( $new_template_item );
     309            }
     310        }
     311    }
     312
     313    return $template_files;
     314}
     315
     316/**
     317 * Attempts to add custom template information to the template item.
     318 *
     319 * @access private
     320 * @since 5.9.0
     321 *
     322 * @param array $template_item Template to add information to (requires 'slug' field).
     323 * @return array Template
     324 */
     325function _add_block_template_info( $template_item ) {
     326    if ( ! WP_Theme_JSON_Resolver::theme_has_support() ) {
     327        return $template_item;
     328    }
     329
     330    $theme_data = WP_Theme_JSON_Resolver::get_theme_data()->get_custom_templates();
     331    if ( isset( $theme_data[ $template_item['slug'] ] ) ) {
     332        $template_item['title']     = $theme_data[ $template_item['slug'] ]['title'];
     333        $template_item['postTypes'] = $theme_data[ $template_item['slug'] ]['postTypes'];
     334    }
     335
     336    return $template_item;
     337}
     338
     339/**
     340 * Attempts to add the template part's area information to the input template.
     341 *
     342 * @access private
     343 * @since 5.9.0
     344 *
     345 * @param array $template_info Template to add information to (requires 'type' and 'slug' fields).
     346 *
     347 * @return array Template.
     348 */
     349function _add_block_template_part_area_info( $template_info ) {
     350    if ( WP_Theme_JSON_Resolver::theme_has_support() ) {
     351        $theme_data = WP_Theme_JSON_Resolver::get_theme_data()->get_template_parts();
     352    }
     353
     354    if ( isset( $theme_data[ $template_info['slug'] ]['area'] ) ) {
     355        $template_info['title'] = $theme_data[ $template_info['slug'] ]['title'];
     356        $template_info['area']  = _filter_block_template_part_area( $theme_data[ $template_info['slug'] ]['area'] );
     357    } else {
     358        $template_info['area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED;
     359    }
     360
     361    return $template_info;
     362}
     363
     364/**
     365 * Returns an array containing the references of
     366 * the passed blocks and their inner blocks.
     367 *
     368 * @access private
     369 * @since 5.9.0
     370 *
     371 * @param array $blocks array of blocks.
     372 *
     373 * @return array block references to the passed blocks and their inner blocks.
     374 */
     375function _flatten_blocks( &$blocks ) {
     376    $all_blocks = array();
     377    $queue      = array();
     378    foreach ( $blocks as &$block ) {
     379        $queue[] = &$block;
     380    }
     381
     382    while ( count( $queue ) > 0 ) {
     383        $block = &$queue[0];
     384        array_shift( $queue );
     385        $all_blocks[] = &$block;
     386
     387        if ( ! empty( $block['innerBlocks'] ) ) {
     388            foreach ( $block['innerBlocks'] as &$inner_block ) {
     389                $queue[] = &$inner_block;
     390            }
     391        }
     392    }
     393
     394    return $all_blocks;
     395}
     396
     397/**
     398 * Parses wp_template content and injects the current theme's
     399 * stylesheet as a theme attribute into each wp_template_part
     400 *
     401 * @access private
     402 * @since 5.9.0
     403 *
     404 * @param string $template_content serialized wp_template content.
     405 *
     406 * @return string Updated wp_template content.
     407 */
     408function _inject_theme_attribute_in_block_template_content( $template_content ) {
     409    $has_updated_content = false;
     410    $new_content         = '';
     411    $template_blocks     = parse_blocks( $template_content );
     412
     413    $blocks = _flatten_blocks( $template_blocks );
     414    foreach ( $blocks as &$block ) {
     415        if (
     416            'core/template-part' === $block['blockName'] &&
     417            ! isset( $block['attrs']['theme'] )
     418        ) {
     419            $block['attrs']['theme'] = wp_get_theme()->get_stylesheet();
     420            $has_updated_content     = true;
     421        }
     422    }
     423
     424    if ( $has_updated_content ) {
     425        foreach ( $template_blocks as &$block ) {
     426            $new_content .= serialize_block( $block );
     427        }
     428
     429        return $new_content;
     430    }
     431
     432    return $template_content;
     433}
     434
     435/**
     436 * Build a unified template object based on a theme file.
     437 *
     438 * @access private
     439 * @since 5.9.0
     440 *
     441 * @param array $template_file Theme file.
     442 * @param array $template_type wp_template or wp_template_part.
     443 *
     444 * @return WP_Block_Template Template.
     445 */
     446function _build_block_template_result_from_file( $template_file, $template_type ) {
     447    $default_template_types = get_default_block_template_types();
     448    $template_content       = file_get_contents( $template_file['path'] );
     449    $theme                  = wp_get_theme()->get_stylesheet();
     450
     451    $template                 = new WP_Block_Template();
     452    $template->id             = $theme . '//' . $template_file['slug'];
     453    $template->theme          = $theme;
     454    $template->content        = _inject_theme_attribute_in_block_template_content( $template_content );
     455    $template->slug           = $template_file['slug'];
     456    $template->source         = 'theme';
     457    $template->type           = $template_type;
     458    $template->title          = ! empty( $template_file['title'] ) ? $template_file['title'] : $template_file['slug'];
     459    $template->status         = 'publish';
     460    $template->has_theme_file = true;
     461    $template->is_custom      = true;
     462
     463    if ( 'wp_template' === $template_type && isset( $default_template_types[ $template_file['slug'] ] ) ) {
     464        $template->description = $default_template_types[ $template_file['slug'] ]['description'];
     465        $template->title       = $default_template_types[ $template_file['slug'] ]['title'];
     466        $template->is_custom   = false;
     467    }
     468
     469    if ( 'wp_template' === $template_type && isset( $template_file['postTypes'] ) ) {
     470        $template->post_types = $template_file['postTypes'];
     471    }
     472
     473    if ( 'wp_template_part' === $template_type && isset( $template_file['area'] ) ) {
     474        $template->area = $template_file['area'];
     475    }
     476
     477    return $template;
     478}
     479
    9480/**
    10481 * Build a unified template object based a post Object.
    11482 *
    12483 * @access private
    13  * @since 5.8.0
     484 * @since 5.9.0
    14485 *
    15486 * @param WP_Post $post Template post.
     
    17488 * @return WP_Block_Template|WP_Error Template.
    18489 */
    19 function _build_template_result_from_post( $post ) {
    20     $terms = get_the_terms( $post, 'wp_theme' );
     490function _build_block_template_result_from_post( $post ) {
     491    $default_template_types = get_default_block_template_types();
     492    $terms                  = get_the_terms( $post, 'wp_theme' );
    21493
    22494    if ( is_wp_error( $terms ) ) {
     
    28500    }
    29501
    30     $theme = $terms[0]->name;
     502    $theme          = $terms[0]->name;
     503    $has_theme_file = wp_get_theme()->get_stylesheet() === $theme &&
     504        null !== _get_block_template_file( $post->post_type, $post->post_name );
    31505
    32506    $template                 = new WP_Block_Template();
     
    41515    $template->title          = $post->post_title;
    42516    $template->status         = $post->post_status;
    43     $template->has_theme_file = false;
     517    $template->has_theme_file = $has_theme_file;
     518    $template->is_custom      = true;
     519
     520    if ( 'wp_template' === $post->post_type && isset( $default_template_types[ $template->slug ] ) ) {
     521        $template->is_custom = false;
     522    }
     523
     524    if ( 'wp_template_part' === $post->post_type ) {
     525        $type_terms = get_the_terms( $post, 'wp_template_part_area' );
     526        if ( ! is_wp_error( $type_terms ) && false !== $type_terms ) {
     527            $template->area = $type_terms[0]->name;
     528        }
     529    }
    44530
    45531    return $template;
     
    54540 *     Optional. Arguments to retrieve templates.
    55541 *
    56  *     @type array  $slug__in List of slugs to include.
    57  *     @type int    $wp_id Post ID of customized template.
     542 *     @type array  $slug__in  List of slugs to include.
     543 *     @type int    $wp_id     Post ID of customized template.
     544 *     @type string $area      A 'wp_template_part_area' taxonomy value to filter by (for wp_template_part template type only).
     545 *     @type string $post_type Post type to get the templates for.
    58546 * }
    59  * @param string $template_type Optional. The template type (post type). Default 'wp_template'.
    60  * @return WP_Block_Template[] Block template objects.
     547 * @param array $template_type wp_template or wp_template_part.
     548 *
     549 * @return array Templates.
    61550 */
    62551function get_block_templates( $query = array(), $template_type = 'wp_template' ) {
     552    /**
     553     * Filters the block templates array before the query takes place.
     554     *
     555     * Return a non-null value to bypass the WordPress queries.
     556     *
     557     * @since 5.9
     558     *
     559     * @param WP_Block_Template[]|null $block_templates Return an array of block templates to short-circuit the default query,
     560     *                                                  or null to allow WP to run it's normal queries.
     561     * @param array $query {
     562     *     Optional. Arguments to retrieve templates.
     563     *
     564     *     @type array  $slug__in List of slugs to include.
     565     *     @type int    $wp_id Post ID of customized template.
     566     *     @type string $post_type Post type to get the templates for.
     567     * }
     568     * @param array $template_type wp_template or wp_template_part.
     569     */
     570    $templates = apply_filters( 'pre_get_block_templates', null, $query, $template_type );
     571    if ( ! is_null( $templates ) ) {
     572        return $templates;
     573    }
     574
     575    $post_type     = isset( $query['post_type'] ) ? $query['post_type'] : '';
    63576    $wp_query_args = array(
    64577        'post_status'    => array( 'auto-draft', 'draft', 'publish' ),
     
    75588    );
    76589
     590    if ( 'wp_template_part' === $template_type && isset( $query['area'] ) ) {
     591        $wp_query_args['tax_query'][]           = array(
     592            'taxonomy' => 'wp_template_part_area',
     593            'field'    => 'name',
     594            'terms'    => $query['area'],
     595        );
     596        $wp_query_args['tax_query']['relation'] = 'AND';
     597    }
     598
    77599    if ( isset( $query['slug__in'] ) ) {
    78600        $wp_query_args['post_name__in'] = $query['slug__in'];
    79601    }
    80602
    81     // This is only needed for the regular templates CPT listing and editor.
     603    // This is only needed for the regular templates/template parts CPT listing and editor.
    82604    if ( isset( $query['wp_id'] ) ) {
    83605        $wp_query_args['p'] = $query['wp_id'];
     
    89611    $query_result   = array();
    90612    foreach ( $template_query->posts as $post ) {
    91         $template = _build_template_result_from_post( $post );
    92 
    93         if ( ! is_wp_error( $template ) ) {
    94             $query_result[] = $template;
    95         }
    96     }
    97 
    98     return $query_result;
     613        $template = _build_block_template_result_from_post( $post );
     614
     615        if ( is_wp_error( $template ) ) {
     616            continue;
     617        }
     618
     619        if ( $post_type && ! $template->is_custom ) {
     620            continue;
     621        }
     622
     623        $query_result[] = $template;
     624    }
     625
     626    if ( ! isset( $query['wp_id'] ) ) {
     627        $template_files = _get_block_templates_files( $template_type );
     628        foreach ( $template_files as $template_file ) {
     629            $template = _build_block_template_result_from_file( $template_file, $template_type );
     630
     631            if ( $post_type && ! $template->is_custom ) {
     632                continue;
     633            }
     634
     635            if ( $post_type &&
     636                isset( $template->post_types ) &&
     637                ! in_array( $post_type, $template->post_types, true )
     638            ) {
     639                continue;
     640            }
     641
     642            $is_not_custom   = false === array_search(
     643                wp_get_theme()->get_stylesheet() . '//' . $template_file['slug'],
     644                array_column( $query_result, 'id' ),
     645                true
     646            );
     647            $fits_slug_query =
     648                ! isset( $query['slug__in'] ) || in_array( $template_file['slug'], $query['slug__in'], true );
     649            $fits_area_query =
     650                ! isset( $query['area'] ) || $template_file['area'] === $query['area'];
     651            $should_include  = $is_not_custom && $fits_slug_query && $fits_area_query;
     652            if ( $should_include ) {
     653                $query_result[] = $template;
     654            }
     655        }
     656    }
     657
     658    /**
     659     * Filters the array of queried block templates array after they've been fetched.
     660     *
     661     * @since 5.9
     662     *
     663     * @param WP_Block_Template[] $query_result Array of found block templates.
     664     * @param array $query {
     665     *     Optional. Arguments to retrieve templates.
     666     *
     667     *     @type array  $slug__in List of slugs to include.
     668     *     @type int    $wp_id Post ID of customized template.
     669     * }
     670     * @param array $template_type wp_template or wp_template_part.
     671     */
     672    return apply_filters( 'get_block_templates', $query_result, $query, $template_type );
    99673}
    100674
     
    105679 *
    106680 * @param string $id            Template unique identifier (example: theme_slug//template_slug).
    107  * @param string $template_type Optional. The template type (post type). Default 'wp_template'.
     681 * @param array  $template_type Optional. Template type: `'wp_template'` or '`wp_template_part'`.
     682 *                              Default `'wp_template'`.
     683 *
    108684 * @return WP_Block_Template|null Template.
    109685 */
    110686function get_block_template( $id, $template_type = 'wp_template' ) {
     687    /**
     688     * Filters the block templates array before the query takes place.
     689     *
     690     * Return a non-null value to bypass the WordPress queries.
     691     *
     692     * @since 5.9.0
     693     *
     694     * @param WP_Block_Template|null $block_template Return block template object to short-circuit the default query,
     695     *                                               or null to allow WP to run its normal queries.
     696     * @param string $id                             Template unique identifier (example: theme_slug//template_slug).
     697     * @param array  $template_type                  Template type: `'wp_template'` or '`wp_template_part'`.
     698     */
     699    $block_template = apply_filters( 'pre_get_block_template', null, $id, $template_type );
     700    if ( ! is_null( $block_template ) ) {
     701        return $block_template;
     702    }
     703
    111704    $parts = explode( '//', $id, 2 );
    112705    if ( count( $parts ) < 2 ) {
     
    132725
    133726    if ( count( $posts ) > 0 ) {
    134         $template = _build_template_result_from_post( $posts[0] );
     727        $template = _build_block_template_result_from_post( $posts[0] );
    135728
    136729        if ( ! is_wp_error( $template ) ) {
     
    139732    }
    140733
    141     return null;
    142 }
     734    $block_template = get_block_file_template( $id, $template_type );
     735
     736    /**
     737     * Filters the array of queried block templates array after they've been fetched.
     738     *
     739     * @since 5.9
     740     *
     741     * @param WP_Block_Template $block_template The found block template.
     742     * @param string            $id             Template unique identifier (example: theme_slug//template_slug).
     743     * @param array             $template_type  Template type: `'wp_template'` or '`wp_template_part'`.
     744     */
     745    return apply_filters( 'get_block_template', $block_template, $id, $template_type );
     746}
     747
     748/**
     749 * Retrieves a single unified template object using its id.
     750 *
     751 * @since 5.9.0
     752 *
     753 * @param string $id            Template unique identifier (example: theme_slug//template_slug).
     754 * @param array  $template_type Optional. Template type: `'wp_template'` or '`wp_template_part'`.
     755 *                              Default `'wp_template'`.
     756 */
     757function get_block_file_template( $id, $template_type = 'wp_template' ) {
     758    /**
     759     * Filters the block templates array before the query takes place.
     760     *
     761     * Return a non-null value to bypass the WordPress queries.
     762     *
     763     *
     764     * @since 5.9.0
     765     *
     766     * @param WP_Block_Template|null $block_template Return block template object to short-circuit the default query,
     767     *                                               or null to allow WP to run its normal queries.
     768     * @param string $id                             Template unique identifier (example: theme_slug//template_slug).
     769     * @param array  $template_type                  Template type: `'wp_template'` or '`wp_template_part'`.
     770     */
     771    $block_template = apply_filters( 'pre_get_block_file_template', null, $id, $template_type );
     772    if ( ! is_null( $block_template ) ) {
     773        return $block_template;
     774    }
     775
     776    $parts = explode( '//', $id, 2 );
     777    if ( count( $parts ) < 2 ) {
     778        /** This filter is documented at the end of this function */
     779        return apply_filters( 'get_block_file_template', null, $id, $template_type );
     780    }
     781    list( $theme, $slug ) = $parts;
     782
     783    if ( wp_get_theme()->get_stylesheet() !== $theme ) {
     784        /** This filter is documented at the end of this function */
     785        return apply_filters( 'get_block_file_template', null, $id, $template_type );
     786    }
     787
     788    $template_file = _get_block_template_file( $template_type, $slug );
     789    if ( null === $template_file ) {
     790        /** This filter is documented at the end of this function */
     791        return apply_filters( 'get_block_file_template', null, $id, $template_type );
     792    }
     793
     794    $block_template = _build_block_template_result_from_file( $template_file, $template_type );
     795
     796    /**
     797     * Filters the array of queried block templates array after they've been fetched.
     798     *
     799     * @since 5.9.0
     800     *
     801     * @param WP_Block_Template $block_template The found block template.
     802     * @param string            $id             Template unique identifier (example: theme_slug//template_slug).
     803     * @param array             $template_type  Template type: `'wp_template'` or '`wp_template_part'`.
     804     */
     805    return apply_filters( 'get_block_file_template', $block_template, $id, $template_type );
     806}
     807
     808/**
     809 * Print a template-part.
     810 *
     811 * @since 5.9.0
     812 *
     813 * @param string $part The template-part to print. Use "header" or "footer".
     814 */
     815function block_template_part( $part ) {
     816    $template_part = get_block_template( get_stylesheet() . '//' . $part, 'wp_template_part' );
     817    if ( ! $template_part || empty( $template_part->content ) ) {
     818        return;
     819    }
     820    echo do_blocks( $template_part->content );
     821}
     822
     823/**
     824 * Print the header template-part.
     825 *
     826 * @since 5.9.0
     827 */
     828function block_header_area() {
     829    block_template_part( 'header' );
     830}
     831
     832/**
     833 * Print the footer template-part.
     834 *
     835 * @since 5.9.0
     836 */
     837function block_footer_area() {
     838    block_template_part( 'footer' );
     839}
Note: See TracChangeset for help on using the changeset viewer.