PluginProbe
Gutenberg / 9.8.0
Gutenberg v9.8.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 12.6.0 All 403 releases
gutenberg / lib / full-site-editing / template-loader.php

template-loader.php in Gutenberg 9.8.0, at lib/full-site-editing/template-loader.php

231 lines 7.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Block template loader functions.
4 *
5 * @package gutenberg
6 */
7
8 /**
9 * Adds necessary filters to use 'wp_template' posts instead of theme template files.
10 */
11 function gutenberg_add_template_loader_filters() {
12 if ( ! gutenberg_is_fse_theme() ) {
13 return;
14 }
15
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 );
21 }
22 }
23 add_action( 'wp_loaded', 'gutenberg_add_template_loader_filters' );
24
25 /**
26 * Get the template hierarchy for a given template type.
27 *
28 * Internally, this filters into the "{$type}_template_hierarchy" hook to record the type-specific template hierarchy.
29 *
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.
56 *
57 * Internally, this communicates the block content that needs to be used by the template canvas through a global variable.
58 *
59 * @param string $template Path to the template. See locate_template().
60 * @param string $type Sanitized filename without extension.
61 * @param array $templates A list of template candidates, in descending order of priority.
62 * @return string The path to the Full Site Editing template canvas file.
63 */
64 function gutenberg_override_query_template( $template, $type, array $templates = array() ) {
65 global $_wp_current_template_content;
66 $current_template = gutenberg_resolve_template( $type, $templates );
67
68 if ( $current_template ) {
69 $_wp_current_template_content = empty( $current_template->content ) ? __( 'Empty template.', 'gutenberg' ) : $current_template->content;
70
71 if ( isset( $_GET['_wp-find-template'] ) ) {
72 wp_send_json_success( $current_template );
73 }
74 } else {
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 }
82 }
83
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';
94 }
95
96 /**
97 * Return the correct 'wp_template' to render fot the request template type.
98 *
99 * Accepts an optional $template_hierarchy argument as a hint.
100 *
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 * }
107 */
108 function gutenberg_resolve_template( $template_type, $template_hierarchy = array() ) {
109 if ( ! $template_type ) {
110 return null;
111 }
112
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 }
119 }
120
121 $slugs = array_map(
122 'gutenberg_strip_php_suffix',
123 $template_hierarchy
124 );
125
126 // Find all potential templates 'wp_template' post matching the hierarchy.
127 $query = array(
128 'theme' => wp_get_theme()->get_stylesheet(),
129 'slug__in' => $slugs,
130 );
131 $templates = gutenberg_get_block_templates( $query );
132
133 // Order these templates per slug priority.
134 // Build map of template slugs to their priority in the current hierarchy.
135 $slug_priorities = array_flip( $slugs );
136
137 usort(
138 $templates,
139 function ( $template_a, $template_b ) use ( $slug_priorities ) {
140 return $slug_priorities[ $template_a->slug ] - $slug_priorities[ $template_b->slug ];
141 }
142 );
143
144 return count( $templates ) ? $templates[0] : null;
145 }
146
147 /**
148 * Displays title tag with content, regardless of whether theme has title-tag support.
149 *
150 * @see _wp_render_title_tag()
151 */
152 function gutenberg_render_title_tag() {
153 echo '<title>' . wp_get_document_title() . '</title>' . "\n";
154 }
155
156 /**
157 * Renders the markup for the current template.
158 */
159 function gutenberg_render_the_template() {
160 global $_wp_current_template_content;
161 global $wp_embed;
162
163 if ( ! $_wp_current_template_content ) {
164 echo '<h1>' . esc_html__( 'No matching template found', 'gutenberg' ) . '</h1>';
165 return;
166 }
167
168 $content = $wp_embed->run_shortcode( $_wp_current_template_content );
169 $content = $wp_embed->autoembed( $content );
170 $content = do_blocks( $content );
171 $content = wptexturize( $content );
172 if ( function_exists( 'wp_filter_content_tags' ) ) {
173 $content = wp_filter_content_tags( $content );
174 } else {
175 $content = wp_make_content_images_responsive( $content );
176 }
177 $content = str_replace( ']]>', ']]&gt;', $content );
178
179 // Wrap block template in .wp-site-blocks to allow for specific descendant styles
180 // (e.g. `.wp-site-blocks > *`).
181 echo '<div class="wp-site-blocks">';
182 echo $content; // phpcs:ignore WordPress.Security.EscapeOutput
183 echo '</div>';
184 }
185
186 /**
187 * Renders a 'viewport' meta tag.
188 *
189 * This is hooked into {@see 'wp_head'} to decouple its output from the default template canvas.
190 */
191 function gutenberg_viewport_meta_tag() {
192 echo '<meta name="viewport" content="width=device-width, initial-scale=1" />' . "\n";
193 }
194
195 /**
196 * Strips .php suffix from template file names.
197 *
198 * @access private
199 *
200 * @param string $template_file Template file name.
201 * @return string Template file name without extension.
202 */
203 function gutenberg_strip_php_suffix( $template_file ) {
204 return preg_replace( '/\.(php|html)$/', '', $template_file );
205 }
206
207 /**
208 * Removes post details from block context when rendering a block template.
209 *
210 * @param array $context Default context.
211 *
212 * @return array Filtered context.
213 */
214 function gutenberg_template_render_without_post_block_context( $context ) {
215 /*
216 * When loading a template or template part directly and not through a page
217 * that resolves it, the top-level post ID and type context get set to that
218 * of the template part. Templates are just the structure of a site, and
219 * they should not be available as post context because blocks like Post
220 * Content would recurse infinitely.
221 */
222 if ( isset( $context['postType'] ) &&
223 ( 'wp_template' === $context['postType'] || 'wp_template_part' === $context['postType'] ) ) {
224 unset( $context['postId'] );
225 unset( $context['postType'] );
226 }
227
228 return $context;
229 }
230 add_filter( 'render_block_context', 'gutenberg_template_render_without_post_block_context' );
231