PluginProbe
Gutenberg / 19.6.1
Gutenberg v19.6.1
24.1.0 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 All 404 releases
gutenberg / lib / compat / wordpress-6.6 / block-template-utils.php

block-template-utils.php in Gutenberg 19.6.1, at lib/compat/wordpress-6.6/block-template-utils.php

363 lines 12.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Utilities used to fetch and create templates and template parts.
4 *
5 * @package gutenberg
6 */
7
8 /**
9 * Gets the template hierarchy for the given template slug to be created.
10 *
11 * Note: Always add `index` as the last fallback template.
12 *
13 *
14 * @param string $slug The template slug to be created.
15 * @param bool $is_custom Optional. Indicates if a template is custom or
16 * part of the template hierarchy. Default false.
17 * @param string $template_prefix Optional. The template prefix for the created template.
18 * Used to extract the main template type, e.g.
19 * in `taxonomy-books` the `taxonomy` is extracted.
20 * Default empty string.
21 * @return string[] The template hierarchy.
22 */
23 function gutenberg_get_template_hierarchy( $slug, $is_custom = false, $template_prefix = '' ) {
24 if ( 'index' === $slug ) {
25 /** This filter is documented in wp-includes/template.php */
26 return apply_filters( 'index_template_hierarchy', array( 'index' ) );
27 }
28 if ( $is_custom ) {
29 /** This filter is documented in wp-includes/template.php */
30 return apply_filters( 'page_template_hierarchy', array( 'page', 'singular', 'index' ) );
31 }
32 if ( 'front-page' === $slug ) {
33 /** This filter is documented in wp-includes/template.php */
34 return apply_filters( 'frontpage_template_hierarchy', array( 'front-page', 'home', 'index' ) );
35 }
36
37 $matches = array();
38
39 $template_hierarchy = array( $slug );
40 // Most default templates don't have `$template_prefix` assigned.
41 if ( ! empty( $template_prefix ) ) {
42 list( $type ) = explode( '-', $template_prefix );
43 // We need these checks because we always add the `$slug` above.
44 if ( ! in_array( $template_prefix, array( $slug, $type ), true ) ) {
45 $template_hierarchy[] = $template_prefix;
46 }
47 if ( $slug !== $type ) {
48 $template_hierarchy[] = $type;
49 }
50 } elseif ( preg_match( '/^(author|category|archive|tag|page)-.+$/', $slug, $matches ) ) {
51 $template_hierarchy[] = $matches[1];
52 } elseif ( preg_match( '/^(taxonomy|single)-(.+)$/', $slug, $matches ) ) {
53 $type = $matches[1];
54 $slug_remaining = $matches[2];
55
56 $items = 'single' === $type ? get_post_types() : get_taxonomies();
57 foreach ( $items as $item ) {
58 if ( ! str_starts_with( $slug_remaining, $item ) ) {
59 continue;
60 }
61
62 // If $slug_remaining is equal to $post_type or $taxonomy we have
63 // the single-$post_type template or the taxonomy-$taxonomy template.
64 if ( $slug_remaining === $item ) {
65 $template_hierarchy[] = $type;
66 break;
67 }
68
69 // If $slug_remaining is single-$post_type-$slug template.
70 if ( strlen( $slug_remaining ) > strlen( $item ) + 1 ) {
71 $template_hierarchy[] = "$type-$item";
72 $template_hierarchy[] = $type;
73 break;
74 }
75 }
76 }
77 // Handle `archive` template.
78 if (
79 str_starts_with( $slug, 'author' ) ||
80 str_starts_with( $slug, 'taxonomy' ) ||
81 str_starts_with( $slug, 'category' ) ||
82 str_starts_with( $slug, 'tag' ) ||
83 'date' === $slug
84 ) {
85 $template_hierarchy[] = 'archive';
86 }
87 // Handle `single` template.
88 if ( 'attachment' === $slug ) {
89 $template_hierarchy[] = 'single';
90 }
91 // Handle `singular` template.
92 if (
93 str_starts_with( $slug, 'single' ) ||
94 str_starts_with( $slug, 'page' ) ||
95 'attachment' === $slug
96 ) {
97 $template_hierarchy[] = 'singular';
98 }
99 $template_hierarchy[] = 'index';
100
101 $template_type = '';
102 if ( ! empty( $template_prefix ) ) {
103 list( $template_type ) = explode( '-', $template_prefix );
104 } else {
105 list( $template_type ) = explode( '-', $slug );
106 }
107 $valid_template_types = array( '404', 'archive', 'attachment', 'author', 'category', 'date', 'embed', 'frontpage', 'home', 'index', 'page', 'paged', 'privacypolicy', 'search', 'single', 'singular', 'tag', 'taxonomy' );
108 if ( in_array( $template_type, $valid_template_types, true ) ) {
109 /** This filter is documented in wp-includes/template.php */
110 return apply_filters( "{$template_type}_template_hierarchy", $template_hierarchy );
111 }
112 return $template_hierarchy;
113 }
114
115 /**
116 * Retrieves the template files from the theme.
117 *
118 * @since 5.9.0
119 * @since 6.3.0 Added the `$query` parameter.
120 * @access private
121 *
122 * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'.
123 * @param array $query {
124 * Arguments to retrieve templates. Optional, empty by default.
125 *
126 * @type string[] $slug__in List of slugs to include.
127 * @type string[] $slug__not_in List of slugs to skip.
128 * @type string $area A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only).
129 * @type string $post_type Post type to get the templates for.
130 * }
131 *
132 * @return array Template
133 */
134 function _gutenberg_get_block_templates_files( $template_type, $query = array() ) {
135 if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) {
136 return null;
137 }
138
139 // @core-merge: This code will go into Core's '_get_block_templates_files' function.
140 $default_template_types = array();
141 if ( 'wp_template' === $template_type ) {
142 $default_template_types = get_default_block_template_types();
143 }
144 // @core-merge: End of the code that will go into Core.
145
146 // Prepare metadata from $query.
147 $slugs_to_include = isset( $query['slug__in'] ) ? $query['slug__in'] : array();
148 $slugs_to_skip = isset( $query['slug__not_in'] ) ? $query['slug__not_in'] : array();
149 $area = isset( $query['area'] ) ? $query['area'] : null;
150 $post_type = isset( $query['post_type'] ) ? $query['post_type'] : '';
151
152 $stylesheet = get_stylesheet();
153 $template = get_template();
154 $themes = array(
155 $stylesheet => get_stylesheet_directory(),
156 );
157 // Add the parent theme if it's not the same as the current theme.
158 if ( $stylesheet !== $template ) {
159 $themes[ $template ] = get_template_directory();
160 }
161 $template_files = array();
162 foreach ( $themes as $theme_slug => $theme_dir ) {
163 $template_base_paths = get_block_theme_folders( $theme_slug );
164 $theme_template_files = _get_block_templates_paths( $theme_dir . '/' . $template_base_paths[ $template_type ] );
165 foreach ( $theme_template_files as $template_file ) {
166 $template_base_path = $template_base_paths[ $template_type ];
167 $template_slug = substr(
168 $template_file,
169 // Starting position of slug.
170 strpos( $template_file, $template_base_path . DIRECTORY_SEPARATOR ) + 1 + strlen( $template_base_path ),
171 // Subtract ending '.html'.
172 -5
173 );
174
175 // Skip this item if its slug doesn't match any of the slugs to include.
176 if ( ! empty( $slugs_to_include ) && ! in_array( $template_slug, $slugs_to_include, true ) ) {
177 continue;
178 }
179
180 // Skip this item if its slug matches any of the slugs to skip.
181 if ( ! empty( $slugs_to_skip ) && in_array( $template_slug, $slugs_to_skip, true ) ) {
182 continue;
183 }
184
185 /*
186 * The child theme items (stylesheet) are processed before the parent theme's (template).
187 * If a child theme defines a template, prevent the parent template from being added to the list as well.
188 */
189 if ( isset( $template_files[ $template_slug ] ) ) {
190 continue;
191 }
192
193 $new_template_item = array(
194 'slug' => $template_slug,
195 'path' => $template_file,
196 'theme' => $theme_slug,
197 'type' => $template_type,
198 );
199
200 if ( 'wp_template_part' === $template_type ) {
201 $candidate = _add_block_template_part_area_info( $new_template_item );
202 if ( ! isset( $area ) || ( isset( $area ) && $area === $candidate['area'] ) ) {
203 $template_files[ $template_slug ] = $candidate;
204 }
205 }
206
207 if ( 'wp_template' === $template_type ) {
208 $candidate = _add_block_template_info( $new_template_item );
209 $is_custom = ! isset( $default_template_types[ $candidate['slug'] ] );
210
211 if (
212 ! $post_type ||
213 ( $post_type && isset( $candidate['postTypes'] ) && in_array( $post_type, $candidate['postTypes'], true ) )
214 ) {
215 $template_files[ $template_slug ] = $candidate;
216 }
217
218 // @core-merge: This code will go into Core's '_get_block_templates_files' function.
219 // The custom templates with no associated post-types are available for all post-types.
220 if ( $post_type && ! isset( $candidate['postTypes'] ) && $is_custom ) {
221 $template_files[ $template_slug ] = $candidate;
222 }
223 // @core-merge: End of the code that will go into Core.
224 }
225 }
226 }
227
228 return array_values( $template_files );
229 }
230
231 /**
232 * Retrieves a list of unified template objects based on a query.
233 *
234 * @since 5.8.0
235 *
236 * @param array $query {
237 * Optional. Arguments to retrieve templates.
238 *
239 * @type string[] $slug__in List of slugs to include.
240 * @type int $wp_id Post ID of customized template.
241 * @type string $area A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only).
242 * @type string $post_type Post type to get the templates for.
243 * }
244 * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'.
245 * @return WP_Block_Template[] Array of block templates.
246 */
247 function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_template' ) {
248 /**
249 * Filters the block templates array before the query takes place.
250 *
251 * Return a non-null value to bypass the WordPress queries.
252 *
253 * @since 5.9.0
254 *
255 * @param WP_Block_Template[]|null $block_templates Return an array of block templates to short-circuit the default query,
256 * or null to allow WP to run its normal queries.
257 * @param array $query {
258 * Arguments to retrieve templates. All arguments are optional.
259 *
260 * @type string[] $slug__in List of slugs to include.
261 * @type int $wp_id Post ID of customized template.
262 * @type string $area A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only).
263 * @type string $post_type Post type to get the templates for.
264 * }
265 * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'.
266 */
267 $templates = apply_filters( 'pre_get_block_templates', null, $query, $template_type );
268 if ( ! is_null( $templates ) ) {
269 return $templates;
270 }
271
272 $post_type = isset( $query['post_type'] ) ? $query['post_type'] : '';
273 $wp_query_args = array(
274 'post_status' => array( 'auto-draft', 'draft', 'publish' ),
275 'post_type' => $template_type,
276 'posts_per_page' => -1,
277 'no_found_rows' => true,
278 'lazy_load_term_meta' => false,
279 'tax_query' => array(
280 array(
281 'taxonomy' => 'wp_theme',
282 'field' => 'name',
283 'terms' => get_stylesheet(),
284 ),
285 ),
286 );
287
288 if ( 'wp_template_part' === $template_type && isset( $query['area'] ) ) {
289 $wp_query_args['tax_query'][] = array(
290 'taxonomy' => 'wp_template_part_area',
291 'field' => 'name',
292 'terms' => $query['area'],
293 );
294 $wp_query_args['tax_query']['relation'] = 'AND';
295 }
296
297 if ( ! empty( $query['slug__in'] ) ) {
298 $wp_query_args['post_name__in'] = $query['slug__in'];
299 $wp_query_args['posts_per_page'] = count( array_unique( $query['slug__in'] ) );
300 }
301
302 // This is only needed for the regular templates/template parts post type listing and editor.
303 if ( isset( $query['wp_id'] ) ) {
304 $wp_query_args['p'] = $query['wp_id'];
305 } else {
306 $wp_query_args['post_status'] = 'publish';
307 }
308
309 $template_query = new WP_Query( $wp_query_args );
310 $query_result = array();
311 foreach ( $template_query->posts as $post ) {
312 $template = _build_block_template_result_from_post( $post );
313
314 if ( is_wp_error( $template ) ) {
315 continue;
316 }
317
318 if ( $post_type && ! $template->is_custom ) {
319 continue;
320 }
321
322 if (
323 $post_type &&
324 isset( $template->post_types ) &&
325 ! in_array( $post_type, $template->post_types, true )
326 ) {
327 continue;
328 }
329
330 $query_result[] = $template;
331 }
332
333 if ( ! isset( $query['wp_id'] ) ) {
334 /*
335 * If the query has found some use templates, those have priority
336 * over the theme-provided ones, so we skip querying and building them.
337 */
338 $query['slug__not_in'] = wp_list_pluck( $query_result, 'slug' );
339 $template_files = _gutenberg_get_block_templates_files( $template_type, $query );
340 foreach ( $template_files as $template_file ) {
341 $query_result[] = _build_block_template_result_from_file( $template_file, $template_type );
342 }
343 }
344
345 /**
346 * Filters the array of queried block templates array after they've been fetched.
347 *
348 * @since 5.9.0
349 *
350 * @param WP_Block_Template[] $query_result Array of found block templates.
351 * @param array $query {
352 * Arguments to retrieve templates. All arguments are optional.
353 *
354 * @type string[] $slug__in List of slugs to include.
355 * @type int $wp_id Post ID of customized template.
356 * @type string $area A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only).
357 * @type string $post_type Post type to get the templates for.
358 * }
359 * @param string $template_type wp_template or wp_template_part.
360 */
361 return apply_filters( 'get_block_templates', $query_result, $query, $template_type );
362 }
363