PluginProbe
Gutenberg / 9.7.2
Gutenberg v9.7.2
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
← All changes | lib/template-loader.php +122 -169 7.4.09.7.2 View file →
@@ -8,208 +8,154 @@
8 8 /**
9 9 * Adds necessary filters to use 'wp_template' posts instead of theme template files.
10 10 */
11 11 function gutenberg_add_template_loader_filters() {
12 - if ( ! post_type_exists( 'wp_template' ) ) {
12 + if ( ! gutenberg_is_fse_theme() ) {
13 13 return;
14 14 }
15 15
16 - /**
17 - * Array of all overrideable default template types.
18 - *
19 - * @see get_query_template
20 - *
21 - * @var array
22 - */
23 - $template_types = array(
24 - 'index',
25 - '404',
26 - 'archive',
27 - 'author',
28 - 'category',
29 - 'tag',
30 - 'taxonomy',
31 - 'date',
32 - // Skip 'embed' for now because it is not a regular template type.
33 - 'home',
34 - 'frontpage',
35 - 'privacypolicy',
36 - 'page',
37 - 'search',
38 - 'single',
39 - 'singular',
40 - 'attachment',
41 - );
42 - foreach ( $template_types as $template_type ) {
43 - add_filter( $template_type . '_template', 'gutenberg_override_query_template', 20, 3 );
16 + foreach ( gutenberg_get_template_type_slugs() as $template_type ) {
17 + if ( 'embed' === $template_type ) { // Skip 'embed' for now because it is not a regular template type.
18 + continue;
19 + }
20 + add_filter( str_replace( '-', '', $template_type ) . '_template', 'gutenberg_override_query_template', 20, 3 );
44 21 }
45 -
46 - add_filter( 'template_include', 'gutenberg_find_template', 20 );
47 22 }
48 23 add_action( 'wp_loaded', 'gutenberg_add_template_loader_filters' );
49 24
50 25 /**
51 - * Filters into the "{$type}_template" hooks to record the current template hierarchy.
26 + * Get the template hierarchy for a given template type.
52 27 *
53 - * The method returns an empty result for every template so that a 'wp_template' post
54 - * is used instead.
28 + * Internally, this filters into the "{$type}_template_hierarchy" hook to record the type-specific template hierarchy.
55 29 *
56 - * @see gutenberg_find_template
30 + * @param string $template_type A template type.
31 + * @return string[] A list of template candidates, in descending order of priority.
32 + */
33 +function get_template_hierarchy( $template_type ) {
34 + if ( ! in_array( $template_type, gutenberg_get_template_type_slugs(), true ) ) {
35 + return array();
36 + }
37 +
38 + $get_template_function = 'get_' . str_replace( '-', '_', $template_type ) . '_template'; // front-page -> get_front_page_template.
39 + $template_hierarchy_filter = str_replace( '-', '', $template_type ) . '_template_hierarchy'; // front-page -> frontpage_template_hierarchy.
40 +
41 + $result = array();
42 + $template_hierarchy_filter_function = function( $templates ) use ( &$result ) {
43 + $result = $templates;
44 + return $templates;
45 + };
46 +
47 + add_filter( $template_hierarchy_filter, $template_hierarchy_filter_function, 20, 1 );
48 + call_user_func( $get_template_function ); // This invokes template_hierarchy_filter.
49 + remove_filter( $template_hierarchy_filter, $template_hierarchy_filter_function, 20 );
50 +
51 + return $result;
52 +}
53 +
54 +/**
55 + * Filters into the "{$type}_template" hooks to redirect them to the Full Site Editing template canvas.
57 56 *
57 + * Internally, this communicates the block content that needs to be used by the template canvas through a global variable.
58 + *
58 59 * @param string $template Path to the template. See locate_template().
59 60 * @param string $type Sanitized filename without extension.
60 61 * @param array $templates A list of template candidates, in descending order of priority.
61 - * @return string Empty string to ensure template file is considered not found.
62 + * @return string The path to the Full Site Editing template canvas file.
62 63 */
63 64 function gutenberg_override_query_template( $template, $type, array $templates = array() ) {
64 - global $_wp_current_template_hierarchy;
65 + global $_wp_current_template_content;
66 + $current_template = gutenberg_resolve_template( $type, $templates );
65 67
66 - if ( ! is_array( $_wp_current_template_hierarchy ) ) {
67 - $_wp_current_template_hierarchy = $templates;
68 + if ( $current_template ) {
69 + $_wp_current_template_content = empty( $current_template->post_content ) ? __( 'Empty template.', 'gutenberg' ) : $current_template->post_content;
70 +
71 + if ( isset( $_GET['_wp-find-template'] ) ) {
72 + wp_send_json_success( $current_template );
73 + }
68 74 } else {
69 - $_wp_current_template_hierarchy = array_merge( $_wp_current_template_hierarchy, $templates );
75 + if ( 'index' === $type ) {
76 + if ( isset( $_GET['_wp-find-template'] ) ) {
77 + wp_send_json_error( array( 'message' => __( 'No matching template found.', 'gutenberg' ) ) );
78 + }
79 + } else {
80 + return false; // So that the template loader keeps looking for templates.
81 + }
70 82 }
71 83
72 - return '';
84 + // Add hooks for template canvas.
85 + // Add viewport meta tag.
86 + add_action( 'wp_head', 'gutenberg_viewport_meta_tag', 0 );
87 +
88 + // Render title tag with content, regardless of whether theme has title-tag support.
89 + remove_action( 'wp_head', '_wp_render_title_tag', 1 ); // Remove conditional title tag rendering...
90 + add_action( 'wp_head', 'gutenberg_render_title_tag', 1 ); // ...and make it unconditional.
91 +
92 + // This file will be included instead of the theme's template file.
93 + return gutenberg_dir_path() . 'lib/template-canvas.php';
73 94 }
74 95
75 96 /**
76 - * Recursively traverses a block tree, creating auto drafts
77 - * for any encountered template parts without a fixed post.
97 + * Return the correct 'wp_template' to render fot the request template type.
78 98 *
79 - * @access private
99 + * Accepts an optional $template_hierarchy argument as a hint.
80 100 *
81 - * @param array $block The root block to start traversing from.
101 + * @param string $template_type The current template type.
102 + * @param string[] $template_hierarchy (optional) The current template hierarchy, ordered by priority.
103 + * @return null|array {
104 + * @type WP_Post|null template_post A template post object, or null if none could be found.
105 + * @type int[] A list of template parts IDs for the template.
106 + * }
82 107 */
83 -function create_auto_draft_for_template_part_block( $block ) {
84 - if ( 'core/template-part' === $block['blockName'] && ! isset( $block['attrs']['id'] ) ) {
85 - $template_part_file_path =
86 - get_stylesheet_directory() . '/block-template-parts/' . $block['attrs']['slug'] . '.html';
87 - if ( ! file_exists( $template_part_file_path ) ) {
88 - return;
89 - }
90 - wp_insert_post(
91 - array(
92 - 'post_content' => file_get_contents( $template_part_file_path ),
93 - 'post_title' => ucfirst( $block['attrs']['slug'] ),
94 - 'post_status' => 'auto-draft',
95 - 'post_type' => 'wp_template_part',
96 - 'post_name' => $block['attrs']['slug'],
97 - 'meta_input' => array(
98 - 'theme' => $block['attrs']['theme'],
99 - ),
100 - )
101 - );
108 +function gutenberg_resolve_template( $template_type, $template_hierarchy = array() ) {
109 + if ( ! $template_type ) {
110 + return null;
102 111 }
103 112
104 - foreach ( $block['innerBlocks'] as $inner_block ) {
105 - create_auto_draft_for_template_part_block( $inner_block );
113 + if ( empty( $template_hierarchy ) ) {
114 + if ( 'index' === $template_type ) {
115 + $template_hierarchy = get_template_hierarchy( 'index' );
116 + } else {
117 + $template_hierarchy = array_merge( get_template_hierarchy( $template_type ), get_template_hierarchy( 'index' ) );
118 + }
106 119 }
107 -}
108 120
109 -/**
110 - * Find the correct 'wp_template' post for the current hierarchy and return the path
111 - * to the canvas file that will render it.
112 - *
113 - * @param string $template_file Original template file. Will be overridden.
114 - * @return string Path to the canvas file to include.
115 - */
116 -function gutenberg_find_template( $template_file ) {
117 - global $_wp_current_template_id, $_wp_current_template_content, $_wp_current_template_hierarchy;
118 -
119 - // Bail if no relevant template hierarchy was determined, or if the template file
120 - // was overridden another way.
121 - if ( ! $_wp_current_template_hierarchy || $template_file ) {
122 - return $template_file;
123 - }
124 -
125 121 $slugs = array_map(
126 122 'gutenberg_strip_php_suffix',
127 - $_wp_current_template_hierarchy
123 + $template_hierarchy
128 124 );
129 125
130 - // Find most specific 'wp_template' post matching the hierarchy.
126 + // Find all potential templates 'wp_template' post matching the hierarchy.
131 127 $template_query = new WP_Query(
132 128 array(
133 129 'post_type' => 'wp_template',
134 - 'post_status' => 'publish',
130 + 'post_status' => array( 'publish', 'auto-draft' ),
135 131 'post_name__in' => $slugs,
136 132 'orderby' => 'post_name__in',
137 - 'posts_per_page' => 1,
133 + 'posts_per_page' => -1,
134 + 'no_found_rows' => true,
135 + 'tax_query' => array(
136 + array(
137 + 'taxonomy' => 'wp_theme',
138 + 'field' => 'slug',
139 + 'terms' => wp_get_theme()->get_stylesheet(),
140 + ),
141 + ),
138 142 )
139 143 );
144 + $templates = $template_query->get_posts();
140 145
141 - $template_posts = $template_query->get_posts();
142 - $current_template_post = array_shift( $template_posts );
143 -
146 + // Order these templates per slug priority.
144 147 // Build map of template slugs to their priority in the current hierarchy.
145 148 $slug_priorities = array_flip( $slugs );
146 149
147 - // See if there is a theme block template with higher priority than the resolved template post.
148 - $higher_priority_block_template_path = null;
149 - $higher_priority_block_template_priority = PHP_INT_MAX;
150 - $block_template_files = glob( get_stylesheet_directory() . '/block-templates/*.html' ) ?: array();
151 - if ( is_child_theme() ) {
152 - $block_template_files = array_merge( $block_template_files, glob( get_template_directory() . '/block-templates/*.html' ) ?: array() );
153 - }
154 - if ( gutenberg_is_experiment_enabled( 'gutenberg-full-site-editing-demo' ) ) {
155 - $block_template_files = array_merge( $block_template_files, glob( dirname( __FILE__ ) . '/demo-block-templates/*.html' ) ?: array() );
156 - }
157 - foreach ( $block_template_files as $path ) {
158 - if ( ! isset( $slug_priorities[ basename( $path, '.html' ) ] ) ) {
159 - continue;
150 + usort(
151 + $templates,
152 + function ( $template_a, $template_b ) use ( $slug_priorities ) {
153 + return $slug_priorities[ $template_a->post_name ] - $slug_priorities[ $template_b->post_name ];
160 154 }
161 - $theme_block_template_priority = $slug_priorities[ basename( $path, '.html' ) ];
162 - if (
163 - $theme_block_template_priority < $higher_priority_block_template_priority &&
164 - ( empty( $current_template_post ) || $theme_block_template_priority < $slug_priorities[ $current_template_post->post_name ] )
165 - ) {
166 - $higher_priority_block_template_path = $path;
167 - $higher_priority_block_template_priority = $theme_block_template_priority;
168 - }
169 - }
155 + );
170 156
171 - // If there is, use it instead.
172 - if ( isset( $higher_priority_block_template_path ) ) {
173 - $post_name = basename( $higher_priority_block_template_path, '.html' );
174 - $current_template_post = array(
175 - 'post_content' => file_get_contents( $higher_priority_block_template_path ),
176 - 'post_title' => ucfirst( $post_name ),
177 - 'post_status' => 'auto-draft',
178 - 'post_type' => 'wp_template',
179 - 'post_name' => $post_name,
180 - );
181 - if ( is_admin() ) {
182 - // Only create auto-draft of block template for editing
183 - // in admin screens, similarly to how we do it for new
184 - // posts in the editor.
185 - $current_template_post = get_post(
186 - wp_insert_post( $current_template_post )
187 - );
188 - } else {
189 - $current_template_post = new WP_Post(
190 - (object) $current_template_post
191 - );
192 - }
193 - }
194 -
195 - if ( $current_template_post ) {
196 - if ( is_admin() ) {
197 - foreach ( parse_blocks( $current_template_post->post_content ) as $block ) {
198 - create_auto_draft_for_template_part_block( $block );
199 - }
200 - }
201 - $_wp_current_template_id = $current_template_post->ID;
202 - $_wp_current_template_content = $current_template_post->post_content;
203 - }
204 -
205 - // Add extra hooks for template canvas.
206 - add_action( 'wp_head', 'gutenberg_viewport_meta_tag', 0 );
207 - remove_action( 'wp_head', '_wp_render_title_tag', 1 );
208 - add_action( 'wp_head', 'gutenberg_render_title_tag', 1 );
209 -
210 - // This file will be included instead of the theme's template file.
211 - return gutenberg_dir_path() . 'lib/template-canvas.php';
157 + return count( $templates ) ? $templates[0] : null;
212 158 }
213 159
214 160 /**
215 161 * Displays title tag with content, regardless of whether theme has title-tag support.
@@ -235,9 +181,13 @@
235 181 $content = $wp_embed->run_shortcode( $_wp_current_template_content );
236 182 $content = $wp_embed->autoembed( $content );
237 183 $content = do_blocks( $content );
238 184 $content = wptexturize( $content );
239 - $content = wp_make_content_images_responsive( $content );
185 + if ( function_exists( 'wp_filter_content_tags' ) ) {
186 + $content = wp_filter_content_tags( $content );
187 + } else {
188 + $content = wp_make_content_images_responsive( $content );
189 + }
240 190 $content = str_replace( ']]>', ']]&gt;', $content );
241 191
242 192 // Wrap block template in .wp-site-blocks to allow for specific descendant styles
243 193 // (e.g. `.wp-site-blocks > *`).
@@ -263,28 +213,31 @@
263 213 * @param string $template_file Template file name.
264 214 * @return string Template file name without extension.
265 215 */
266 216 function gutenberg_strip_php_suffix( $template_file ) {
267 - return preg_replace( '/\.php$/', '', $template_file );
217 + return preg_replace( '/\.(php|html)$/', '', $template_file );
268 218 }
269 219
270 220 /**
271 - * Extends default editor settings to enable template and template part editing.
221 + * Removes post details from block context when rendering a block template.
272 222 *
273 - * @param array $settings Default editor settings.
223 + * @param array $context Default context.
274 224 *
275 - * @return array Filtered editor settings.
225 + * @return array Filtered context.
276 226 */
277 -function gutenberg_template_loader_filter_block_editor_settings( $settings ) {
278 - if ( ! post_type_exists( 'wp_template' ) || ! post_type_exists( 'wp_template_part' ) ) {
279 - return $settings;
227 +function gutenberg_template_render_without_post_block_context( $context ) {
228 + /*
229 + * When loading a template or template part directly and not through a page
230 + * that resolves it, the top-level post ID and type context get set to that
231 + * of the template part. Templates are just the structure of a site, and
232 + * they should not be available as post context because blocks like Post
233 + * Content would recurse infinitely.
234 + */
235 + if ( isset( $context['postType'] ) &&
236 + ( 'wp_template' === $context['postType'] || 'wp_template_part' === $context['postType'] ) ) {
237 + unset( $context['postId'] );
238 + unset( $context['postType'] );
280 239 }
281 240
282 - // Create template part auto-drafts for the edited post.
283 - foreach ( parse_blocks( get_post()->post_content ) as $block ) {
284 - create_auto_draft_for_template_part_block( $block );
285 - }
286 -
287 - // TODO: Set editing mode and current template ID for editing modes support.
288 - return $settings;
241 + return $context;
289 242 }
290 -add_filter( 'block_editor_settings', 'gutenberg_template_loader_filter_block_editor_settings' );
243 +add_filter( 'render_block_context', 'gutenberg_template_render_without_post_block_context' );