Skip to content

Commit 39e33be

Browse files
committed
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. git-svn-id: https://develop.svn.wordpress.org/trunk@52062 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 81b29a2 commit 39e33be

18 files changed

Lines changed: 1828 additions & 44 deletions

src/wp-includes/block-template-utils.php

Lines changed: 715 additions & 18 deletions
Large diffs are not rendered by default.

src/wp-includes/blocks.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,8 @@ function build_query_vars_from_query_block( $block, $page ) {
11541154
*
11551155
* It's used in QueryPaginationNext and QueryPaginationPrevious blocks.
11561156
*
1157+
* @since 5.9.0
1158+
*
11571159
* @param WP_Block $block Block instance.
11581160
* @param boolean $is_next Flag for hanlding `next/previous` blocks.
11591161
*

src/wp-includes/blocks/index.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
require ABSPATH . WPINC . '/blocks/site-title.php';
3838
require ABSPATH . WPINC . '/blocks/social-link.php';
3939
require ABSPATH . WPINC . '/blocks/tag-cloud.php';
40+
require ABSPATH . WPINC . '/blocks/template-part.php';
4041

4142
/**
4243
* Registers core block types using metadata files.
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<?php
2+
/**
3+
* Server-side rendering of the `core/template-part` block.
4+
*
5+
* @package WordPress
6+
*/
7+
8+
/**
9+
* Renders the `core/template-part` block on the server.
10+
*
11+
* @param array $attributes The block attributes.
12+
*
13+
* @return string The render.
14+
*/
15+
function render_block_core_template_part( $attributes ) {
16+
static $seen_ids = array();
17+
18+
$template_part_id = null;
19+
$content = null;
20+
$area = WP_TEMPLATE_PART_AREA_UNCATEGORIZED;
21+
22+
if (
23+
isset( $attributes['slug'] ) &&
24+
isset( $attributes['theme'] ) &&
25+
wp_get_theme()->get_stylesheet() === $attributes['theme']
26+
) {
27+
$template_part_id = $attributes['theme'] . '//' . $attributes['slug'];
28+
$template_part_query = new WP_Query(
29+
array(
30+
'post_type' => 'wp_template_part',
31+
'post_status' => 'publish',
32+
'post_name__in' => array( $attributes['slug'] ),
33+
'tax_query' => array(
34+
array(
35+
'taxonomy' => 'wp_theme',
36+
'field' => 'slug',
37+
'terms' => $attributes['theme'],
38+
),
39+
),
40+
'posts_per_page' => 1,
41+
'no_found_rows' => true,
42+
)
43+
);
44+
$template_part_post = $template_part_query->have_posts() ? $template_part_query->next_post() : null;
45+
if ( $template_part_post ) {
46+
// A published post might already exist if this template part was customized elsewhere
47+
// or if it's part of a customized template.
48+
$content = $template_part_post->post_content;
49+
$area_terms = get_the_terms( $template_part_post, 'wp_template_part_area' );
50+
if ( ! is_wp_error( $area_terms ) && false !== $area_terms ) {
51+
$area = $area_terms[0]->name;
52+
}
53+
} else {
54+
// Else, if the template part was provided by the active theme,
55+
// render the corresponding file content.
56+
$template_part_file_path = get_theme_file_path( '/block-template-parts/' . $attributes['slug'] . '.html' );
57+
if ( 0 === validate_file( $attributes['slug'] ) && file_exists( $template_part_file_path ) ) {
58+
$content = _inject_theme_attribute_in_block_template_content( file_get_contents( $template_part_file_path ) );
59+
}
60+
}
61+
}
62+
63+
if ( is_null( $content ) && is_user_logged_in() ) {
64+
if ( ! isset( $attributes['slug'] ) ) {
65+
// If there is no slug this is a placeholder and we dont want to return any message.
66+
return;
67+
}
68+
return sprintf(
69+
/* translators: %s: Template part slug. */
70+
__( 'Template part has been deleted or is unavailable: %s' ),
71+
$attributes['slug']
72+
);
73+
}
74+
75+
if ( isset( $seen_ids[ $template_part_id ] ) ) {
76+
// WP_DEBUG_DISPLAY must only be honored when WP_DEBUG. This precedent
77+
// is set in `wp_debug_mode()`.
78+
$is_debug = defined( 'WP_DEBUG' ) && WP_DEBUG &&
79+
defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG_DISPLAY;
80+
81+
return $is_debug ?
82+
// translators: Visible only in the front end, this warning takes the place of a faulty block.
83+
__( '[block rendering halted]' ) :
84+
'';
85+
}
86+
87+
// Run through the actions that are typically taken on the_content.
88+
$seen_ids[ $template_part_id ] = true;
89+
$content = do_blocks( $content );
90+
unset( $seen_ids[ $template_part_id ] );
91+
$content = wptexturize( $content );
92+
$content = convert_smilies( $content );
93+
$content = shortcode_unautop( $content );
94+
$content = wp_filter_content_tags( $content );
95+
$content = do_shortcode( $content );
96+
97+
// Handle embeds for block template parts.
98+
global $wp_embed;
99+
$content = $wp_embed->autoembed( $content );
100+
101+
if ( empty( $attributes['tagName'] ) ) {
102+
$defined_areas = get_allowed_block_template_part_areas();
103+
$area_tag = 'div';
104+
foreach ( $defined_areas as $defined_area ) {
105+
if ( $defined_area['area'] === $area && isset( $defined_area['area_tag'] ) ) {
106+
$area_tag = $defined_area['area_tag'];
107+
}
108+
}
109+
$html_tag = $area_tag;
110+
} else {
111+
$html_tag = esc_attr( $attributes['tagName'] );
112+
}
113+
$wrapper_attributes = get_block_wrapper_attributes();
114+
115+
return "<$html_tag $wrapper_attributes>" . str_replace( ']]>', ']]&gt;', $content ) . "</$html_tag>";
116+
}
117+
118+
/**
119+
* Returns an array of variation objects for the template part block.
120+
*
121+
* @return array Array containing the block variation objects.
122+
*/
123+
function build_template_part_block_variations() {
124+
$variations = array();
125+
$defined_areas = get_allowed_block_template_part_areas();
126+
foreach ( $defined_areas as $area ) {
127+
if ( 'uncategorized' !== $area['area'] ) {
128+
$variations[] = array(
129+
'name' => $area['area'],
130+
'title' => $area['label'],
131+
'description' => $area['description'],
132+
'attributes' => array(
133+
'area' => $area['area'],
134+
),
135+
'scope' => array( 'inserter' ),
136+
'icon' => $area['icon'],
137+
);
138+
}
139+
}
140+
return $variations;
141+
}
142+
143+
/**
144+
* Registers the `core/template-part` block on the server.
145+
*/
146+
function register_block_core_template_part() {
147+
register_block_type_from_metadata(
148+
__DIR__ . '/template-part',
149+
array(
150+
'render_callback' => 'render_block_core_template_part',
151+
'variations' => build_template_part_block_variations(),
152+
)
153+
);
154+
}
155+
add_action( 'init', 'register_block_core_template_part' );
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"apiVersion": 2,
3+
"name": "core/template-part",
4+
"title": "Template Part",
5+
"category": "theme",
6+
"description": "Edit the different global regions of your site, like the header, footer, sidebar, or create your own.",
7+
"textdomain": "default",
8+
"attributes": {
9+
"slug": {
10+
"type": "string"
11+
},
12+
"theme": {
13+
"type": "string"
14+
},
15+
"tagName": {
16+
"type": "string"
17+
},
18+
"area": {
19+
"type": "string"
20+
}
21+
},
22+
"supports": {
23+
"align": true,
24+
"html": false,
25+
"color": {
26+
"gradients": true,
27+
"link": true
28+
},
29+
"spacing": {
30+
"padding": true
31+
},
32+
"__experimentalLayout": true
33+
},
34+
"editorStyle": "wp-block-template-part-editor"
35+
}

src/wp-includes/class-wp-block-template.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,13 @@ class WP_Block_Template {
100100
* @var boolean
101101
*/
102102
public $has_theme_file;
103+
104+
/**
105+
* Whether a template is a custom template.
106+
*
107+
* @since 5.9.0
108+
*
109+
* @var boolean
110+
*/
111+
public $is_custom = true;
103112
}

src/wp-includes/class-wp-theme-json.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets'
601601
*/
602602
public function get_custom_templates() {
603603
$custom_templates = array();
604-
if ( ! isset( $this->theme_json['customTemplates'] ) ) {
604+
if ( ! isset( $this->theme_json['customTemplates'] ) || ! is_array( $this->theme_json['customTemplates'] ) ) {
605605
return $custom_templates;
606606
}
607607

@@ -625,7 +625,7 @@ public function get_custom_templates() {
625625
*/
626626
public function get_template_parts() {
627627
$template_parts = array();
628-
if ( ! isset( $this->theme_json['templateParts'] ) ) {
628+
if ( ! isset( $this->theme_json['templateParts'] ) || ! is_array( $this->theme_json['templateParts'] ) ) {
629629
return $template_parts;
630630
}
631631

src/wp-includes/default-filters.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@
664664
// Block Templates CPT and Rendering
665665
add_filter( 'render_block_context', '_block_template_render_without_post_block_context' );
666666
add_filter( 'pre_wp_unique_post_slug', 'wp_filter_wp_template_unique_post_slug', 10, 5 );
667+
add_action( 'save_post_wp_template_part', 'wp_set_unique_slug_on_create_template_part' );
667668
add_action( 'wp_footer', 'the_block_template_skip_link' );
668669
add_action( 'setup_theme', 'wp_enable_block_templates' );
669670

src/wp-includes/post.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,64 @@ function create_initial_post_types() {
365365
)
366366
);
367367

368+
register_post_type(
369+
'wp_template_part',
370+
array(
371+
'labels' => array(
372+
'name' => __( 'Template Parts' ),
373+
'singular_name' => __( 'Template Part' ),
374+
'add_new' => _x( 'Add New', 'Template Part' ),
375+
'add_new_item' => __( 'Add New Template Part' ),
376+
'new_item' => __( 'New Template Part' ),
377+
'edit_item' => __( 'Edit Template Part' ),
378+
'view_item' => __( 'View Template Part' ),
379+
'all_items' => __( 'All Template Parts' ),
380+
'search_items' => __( 'Search Template Parts' ),
381+
'parent_item_colon' => __( 'Parent Template Part:' ),
382+
'not_found' => __( 'No template parts found.' ),
383+
'not_found_in_trash' => __( 'No template parts found in Trash.' ),
384+
'archives' => __( 'Template part archives' ),
385+
'insert_into_item' => __( 'Insert into template part' ),
386+
'uploaded_to_this_item' => __( 'Uploaded to this template part' ),
387+
'filter_items_list' => __( 'Filter template parts list' ),
388+
'items_list_navigation' => __( 'Template parts list navigation' ),
389+
'items_list' => __( 'Template parts list' ),
390+
),
391+
'description' => __( 'Template parts to include in your templates.' ),
392+
'public' => false,
393+
'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
394+
'has_archive' => false,
395+
'show_ui' => false,
396+
'show_in_menu' => false,
397+
'show_in_rest' => true,
398+
'rewrite' => false,
399+
'rest_base' => 'template-parts',
400+
'rest_controller_class' => 'WP_REST_Templates_Controller',
401+
'map_meta_cap' => true,
402+
'capabilities' => array(
403+
'create_posts' => 'edit_theme_options',
404+
'delete_posts' => 'edit_theme_options',
405+
'delete_others_posts' => 'edit_theme_options',
406+
'delete_private_posts' => 'edit_theme_options',
407+
'delete_published_posts' => 'edit_theme_options',
408+
'edit_posts' => 'edit_theme_options',
409+
'edit_others_posts' => 'edit_theme_options',
410+
'edit_private_posts' => 'edit_theme_options',
411+
'edit_published_posts' => 'edit_theme_options',
412+
'publish_posts' => 'edit_theme_options',
413+
'read' => 'edit_theme_options',
414+
'read_private_posts' => 'edit_theme_options',
415+
),
416+
'supports' => array(
417+
'title',
418+
'slug',
419+
'excerpt',
420+
'editor',
421+
'revisions',
422+
),
423+
)
424+
);
425+
368426
register_post_type(
369427
'wp_global_styles',
370428
array(

0 commit comments

Comments
 (0)