get_block_templates()
云策文档标注
概述
get_block_templates() 函数用于根据查询参数检索统一的块模板对象列表,支持 'wp_template' 和 'wp_template_part' 类型。它通过 WP_Query 和主题文件系统获取模板,并允许通过过滤器进行自定义。
关键要点
- 函数接受两个参数:$query(可选数组,包含 slug__in、wp_id、area、post_type 等过滤条件)和 $template_type(可选字符串,默认为 'wp_template')。
- 返回 WP_Block_Template[] 数组,包含查询到的块模板对象。
- 内部使用 pre_get_block_templates 过滤器在查询前拦截,以及 get_block_templates 过滤器在查询后修改结果。
- 支持从数据库(自定义模板)和主题文件(默认模板)中检索模板,并处理模板注册表中的插件注册模板。
- 对于 'wp_template_part' 类型,可使用 area 参数基于 wp_template_part_area 分类进行过滤。
代码示例
add_filter('get_block_templates', function($query_result, $query, $template_type){
// 检查查询条件
if( isset($query['theme']) && isset($query['slug__in']) && isset($query['slug__in'][1])){
// 为每个 slug 检查模板文件
foreach($query['slug__in'] as $slug){
$template_file_path = plugin_dir_path(__FILE__).'/templates/' . $slug . '.html';
if(file_exists($template_file_path)){
// 向查询结果添加伪模板
$html = file_get_contents($template_file_path);
array_push($query_result, (object) [
'title' => sprintf(__('Default %s', 'textdomain'), $slug),
'slug' => $slug,
'status' => 'publish',
'type' => 'wp_template',
'description' => sprintf(__('Default %s template', 'textdomain'), $slug),
'content' => $html,
'source' => 'plugin',
'is_custom' => false,
'is_customized' => false,
'is_reusable' => false,
'is_reserved' => false,
'is_published' => true,
'is_wp_template_part' => false,
]);
}
}
}
return $query_result;
}, 10, 3);注意事项
- 插件注册的模板优先级低于主题和编辑器中的模板,会被覆盖。
- 使用 area 参数时,仅适用于 'wp_template_part' 类型,基于 wp_template_part_area 分类值过滤。
- 函数内部处理了自定义模板和主题文件的合并,避免重复,并优先显示用户自定义模板。
原文内容
Retrieves a list of unified template objects based on a query.
Parameters
$queryarrayoptional-
Arguments to retrieve templates.
slug__instring[]List of slugs to include.wp_idintPost ID of customized template.areastringA'wp_template_part_area'taxonomy value to filter by (for'wp_template_part'template type only).post_typestringPost type to get the templates for.
Default:
array() $template_typestringoptional-
Template type. Either
'wp_template'or'wp_template_part'.
Source
function get_block_templates( $query = array(), $template_type = 'wp_template' ) {
/**
* Filters the block templates array before the query takes place.
*
* Return a non-null value to bypass the WordPress queries.
*
* @since 5.9.0
*
* @param WP_Block_Template[]|null $block_templates Return an array of block templates to short-circuit the default query,
* or null to allow WP to run its normal queries.
* @param array $query {
* Arguments to retrieve templates. All arguments are optional.
*
* @type string[] $slug__in List of slugs to include.
* @type int $wp_id Post ID of customized template.
* @type string $area A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only).
* @type string $post_type Post type to get the templates for.
* }
* @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'.
*/
$templates = apply_filters( 'pre_get_block_templates', null, $query, $template_type );
if ( ! is_null( $templates ) ) {
return $templates;
}
$post_type = isset( $query['post_type'] ) ? $query['post_type'] : '';
$wp_query_args = array(
'post_status' => array( 'auto-draft', 'draft', 'publish' ),
'post_type' => $template_type,
'posts_per_page' => -1,
'no_found_rows' => true,
'lazy_load_term_meta' => false,
'tax_query' => array(
array(
'taxonomy' => 'wp_theme',
'field' => 'name',
'terms' => get_stylesheet(),
),
),
);
if ( 'wp_template_part' === $template_type && isset( $query['area'] ) ) {
$wp_query_args['tax_query'][] = array(
'taxonomy' => 'wp_template_part_area',
'field' => 'name',
'terms' => $query['area'],
);
$wp_query_args['tax_query']['relation'] = 'AND';
}
if ( ! empty( $query['slug__in'] ) ) {
$wp_query_args['post_name__in'] = $query['slug__in'];
$wp_query_args['posts_per_page'] = count( array_unique( $query['slug__in'] ) );
}
// This is only needed for the regular templates/template parts post type listing and editor.
if ( isset( $query['wp_id'] ) ) {
$wp_query_args['p'] = $query['wp_id'];
} else {
$wp_query_args['post_status'] = 'publish';
}
$template_query = new WP_Query( $wp_query_args );
$query_result = array();
foreach ( $template_query->posts as $post ) {
$template = _build_block_template_result_from_post( $post );
if ( is_wp_error( $template ) ) {
continue;
}
if ( $post_type && ! $template->is_custom ) {
continue;
}
if (
$post_type &&
isset( $template->post_types ) &&
! in_array( $post_type, $template->post_types, true )
) {
continue;
}
$query_result[] = $template;
}
if ( ! isset( $query['wp_id'] ) ) {
/*
* If the query has found some user templates, those have priority
* over the theme-provided ones, so we skip querying and building them.
*/
$query['slug__not_in'] = wp_list_pluck( $query_result, 'slug' );
/*
* We need to unset the post_type query param because some templates
* would be excluded otherwise, like `page.html` when looking for
* `page` templates. We need all templates so we can exclude duplicates
* from plugin-registered templates.
* See: https://github.com/WordPress/gutenberg/issues/65584
*/
$template_files_query = $query;
unset( $template_files_query['post_type'] );
$template_files = _get_block_templates_files( $template_type, $template_files_query );
foreach ( $template_files as $template_file ) {
// If the query doesn't specify a post type, or it does and the template matches the post type, add it.
if (
! isset( $query['post_type'] ) ||
(
isset( $template_file['postTypes'] ) &&
in_array( $query['post_type'], $template_file['postTypes'], true )
)
) {
$query_result[] = _build_block_template_result_from_file( $template_file, $template_type );
} elseif ( ! isset( $template_file['postTypes'] ) ) {
// The custom templates with no associated post types are available for all post types as long
// as they are not default templates.
$candidate = _build_block_template_result_from_file( $template_file, $template_type );
$default_template_types = get_default_block_template_types();
if ( ! isset( $default_template_types[ $candidate->slug ] ) ) {
$query_result[] = $candidate;
}
}
}
if ( 'wp_template' === $template_type ) {
// Add templates registered in the template registry. Filtering out the ones which have a theme file.
$registered_templates = WP_Block_Templates_Registry::get_instance()->get_by_query( $query );
$matching_registered_templates = array_filter(
$registered_templates,
function ( $registered_template ) use ( $template_files ) {
foreach ( $template_files as $template_file ) {
if ( $template_file['slug'] === $registered_template->slug ) {
return false;
}
}
return true;
}
);
$matching_registered_templates = array_map(
function ( $template ) {
$template->content = apply_block_hooks_to_content(
$template->content,
$template,
'insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata'
);
return $template;
},
$matching_registered_templates
);
$query_result = array_merge( $query_result, $matching_registered_templates );
}
}
/**
* Filters the array of queried block templates array after they've been fetched.
*
* @since 5.9.0
*
* @param WP_Block_Template[] $query_result Array of found block templates.
* @param array $query {
* Arguments to retrieve templates. All arguments are optional.
*
* @type string[] $slug__in List of slugs to include.
* @type int $wp_id Post ID of customized template.
* @type string $area A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only).
* @type string $post_type Post type to get the templates for.
* }
* @param string $template_type wp_template or wp_template_part.
*/
return apply_filters( 'get_block_templates', $query_result, $query, $template_type );
}
Hooks
- apply_filters( ‘get_block_templates’, WP_Block_Template[] $query_result, array $query, string $template_type )
-
Filters the array of queried block templates array after they’ve been fetched.
- apply_filters( ‘pre_get_block_templates’, WP_Block_Template[]|null $block_templates, array $query, string $template_type )
-
Filters the block templates array before the query takes place.
Changelog
| Version | Description |
|---|---|
| 5.8.0 | Introduced. |
Skip to note 2 content
Bastien Ho
Setting default templates by a plugin can be done like this:
add_filter('get_block_templates', function($query_result, $query, $template_type){ // Check if query is not altered if( isset($query['theme']) && isset($query['slug__in']) && isset($query['slug__in'][1])){ // Check if a template exists for each slug foreach($query['slug__in'] as $slug){ $template_file_path = plugin_dir_path(__FILE__).'/templates/' . $slug . '.html'; if(file_exists($template_file_path)){ // Append a fake template to query results $html = file_get_contents($template_file_path); array_push($query_result, (object) [ 'title' => sprintf(__('Default %s', 'textdomain'), $slug), 'slug' => $slug, 'status' => 'publish', 'type' => 'wp_template', 'description' => sprintf(__('Default %s template', 'textdomain'), $slug), 'content' => $html, 'source' => 'plugin', 'is_custom' => false, 'is_customized' => false, 'is_reusable' => false, 'is_reserved' => false, 'is_published' => true, 'is_wp_template_part' => false, ]); } } } return $query_result; }, 10, 3);Template files created in the `templates` directory will be low level templates. They’ll be overridden by templates from the Theme, and from the Editor.