Skip to content

Commit 8e2c2db

Browse files
committed
Templates: add PHP changes required for the template activation feature.
* Adds the `active_templates` setting, which is an object holding the template slug as a key and template post ID as the value. * To maintain backwards compatibility, any `wp_template` (post type) not created through the new API will be activated. * `get_block_template` and `get_block_templates` have been adjusted to check `active_templates`. These functions should never return inactive templates, just like before, to maintain backwards compatibility. * The pre-existing `/templates` endpoint and sub-endpoints remain and work exactly as before. * A new endpoint `/wp_template` has been added, but this is just a regular posts controller (`WP_REST_Posts_Controller`). We do register an additional `theme` field and expose the `is_wp_suggestion` meta. * Another new endpoint `/wp_registered_template` has been added, which is read-only and lists the registered templates from themes and plugin (un-edited, without activations applied). These changes are to be iterated on. See #8063. Props ellatrix, shailu25, ntsekouras. Fixes #62755. git-svn-id: https://develop.svn.wordpress.org/trunk@61029 602fd350-edb4-49c9-b593-d223f7449a82
1 parent eb3a4be commit 8e2c2db

14 files changed

+2008
-574
lines changed

src/wp-admin/site-editor.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ static function ( $classes ) {
182182
array( rest_get_route_for_post_type_items( 'attachment' ), 'OPTIONS' ),
183183
array( rest_get_route_for_post_type_items( 'page' ), 'OPTIONS' ),
184184
'/wp/v2/types?context=view',
185+
'/wp/v2/wp_registered_template?context=edit',
185186
'/wp/v2/types/wp_template?context=edit',
186187
'/wp/v2/types/wp_template_part?context=edit',
187188
'/wp/v2/templates?context=edit&per_page=-1',
@@ -244,7 +245,9 @@ static function ( $classes ) {
244245
);
245246
}
246247
}
247-
} else {
248+
} elseif ( isset( $_GET['p'] ) && '/' !== $_GET['p'] ) {
249+
// Only prefetch for the root. If we preload it for all pages and it's not
250+
// used it won't be possible to invalidate.
248251
$preload_paths[] = '/wp/v2/templates/lookup?slug=front-page';
249252
$preload_paths[] = '/wp/v2/templates/lookup?slug=home';
250253
}

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

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,46 @@ function _build_block_template_result_from_post( $post ) {
10741074
return $template;
10751075
}
10761076

1077+
function get_registered_block_templates( $query ) {
1078+
$template_files = _get_block_templates_files( 'wp_template', $query );
1079+
$query_result = array();
1080+
1081+
// _get_block_templates_files seems broken, it does not obey the query.
1082+
if ( isset( $query['slug__in'] ) && is_array( $query['slug__in'] ) ) {
1083+
$template_files = array_filter(
1084+
$template_files,
1085+
function ( $template_file ) use ( $query ) {
1086+
return in_array( $template_file['slug'], $query['slug__in'], true );
1087+
}
1088+
);
1089+
}
1090+
1091+
foreach ( $template_files as $template_file ) {
1092+
$query_result[] = _build_block_template_result_from_file( $template_file, 'wp_template' );
1093+
}
1094+
1095+
// Add templates registered through the template registry. Filtering out the
1096+
// ones which have a theme file.
1097+
$registered_templates = WP_Block_Templates_Registry::get_instance()->get_by_query( $query );
1098+
$matching_registered_templates = array_filter(
1099+
$registered_templates,
1100+
function ( $registered_template ) use ( $template_files ) {
1101+
foreach ( $template_files as $template_file ) {
1102+
if ( $template_file['slug'] === $registered_template->slug ) {
1103+
return false;
1104+
}
1105+
}
1106+
return true;
1107+
}
1108+
);
1109+
1110+
$query_result = array_merge( $query_result, $matching_registered_templates );
1111+
1112+
// Templates added by PHP filter also count as registered templates.
1113+
/** This filter is documented in wp-includes/block-template-utils.php */
1114+
return apply_filters( 'get_block_templates', $query_result, $query, 'wp_template' );
1115+
}
1116+
10771117
/**
10781118
* Retrieves a list of unified template objects based on a query.
10791119
*
@@ -1152,6 +1192,8 @@ function get_block_templates( $query = array(), $template_type = 'wp_template' )
11521192
$wp_query_args['post_status'] = 'publish';
11531193
}
11541194

1195+
$active_templates = get_option( 'active_templates', array() );
1196+
11551197
$template_query = new WP_Query( $wp_query_args );
11561198
$query_result = array();
11571199
foreach ( $template_query->posts as $post ) {
@@ -1173,7 +1215,14 @@ function get_block_templates( $query = array(), $template_type = 'wp_template' )
11731215
continue;
11741216
}
11751217

1176-
$query_result[] = $template;
1218+
if ( $template->is_custom || isset( $query['wp_id'] ) ) {
1219+
// Custom templates don't need to be activated, leave them be.
1220+
// Also don't filter out templates when querying by wp_id.
1221+
$query_result[] = $template;
1222+
} elseif ( isset( $active_templates[ $template->slug ] ) && $active_templates[ $template->slug ] === $post->ID ) {
1223+
// Only include active templates.
1224+
$query_result[] = $template;
1225+
}
11771226
}
11781227

11791228
if ( ! isset( $query['wp_id'] ) ) {
@@ -1296,7 +1345,25 @@ function get_block_template( $id, $template_type = 'wp_template' ) {
12961345
return null;
12971346
}
12981347
list( $theme, $slug ) = $parts;
1299-
$wp_query_args = array(
1348+
1349+
$active_templates = get_option( 'active_templates', array() );
1350+
1351+
if ( ! empty( $active_templates[ $slug ] ) ) {
1352+
if ( is_int( $active_templates[ $slug ] ) ) {
1353+
$post = get_post( $active_templates[ $slug ] );
1354+
if ( $post && 'publish' === $post->post_status ) {
1355+
$template = _build_block_template_result_from_post( $post );
1356+
1357+
if ( ! is_wp_error( $template ) && $theme === $template->theme ) {
1358+
return $template;
1359+
}
1360+
}
1361+
} elseif ( false === $active_templates[ $slug ] ) {
1362+
return null;
1363+
}
1364+
}
1365+
1366+
$wp_query_args = array(
13001367
'post_name__in' => array( $slug ),
13011368
'post_type' => $template_type,
13021369
'post_status' => array( 'auto-draft', 'draft', 'publish', 'trash' ),
@@ -1310,12 +1377,18 @@ function get_block_template( $id, $template_type = 'wp_template' ) {
13101377
),
13111378
),
13121379
);
1313-
$template_query = new WP_Query( $wp_query_args );
1314-
$posts = $template_query->posts;
1380+
$template_query = new WP_Query( $wp_query_args );
1381+
$posts = $template_query->posts;
13151382

13161383
if ( count( $posts ) > 0 ) {
13171384
$template = _build_block_template_result_from_post( $posts[0] );
13181385

1386+
// Custom templates don't need to be activated, so if it's a custom
1387+
// template, return it.
1388+
if ( ! is_wp_error( $template ) && $template->is_custom ) {
1389+
return $template;
1390+
}
1391+
13191392
if ( ! is_wp_error( $template ) ) {
13201393
return $template;
13211394
}
@@ -1779,3 +1852,33 @@ function inject_ignored_hooked_blocks_metadata_attributes( $changes, $deprecated
17791852

17801853
return $changes;
17811854
}
1855+
1856+
function wp_assign_new_template_to_theme( $changes, $request ) {
1857+
// Do not run this for templates created through the old enpoint.
1858+
$template = $request['id'] ? get_block_template( $request['id'], 'wp_template' ) : null;
1859+
if ( $template ) {
1860+
return $changes;
1861+
}
1862+
if ( ! isset( $changes->tax_input ) ) {
1863+
$changes->tax_input = array();
1864+
}
1865+
$changes->tax_input['wp_theme'] = isset( $request['theme'] ) ? $request['theme'] : get_stylesheet();
1866+
// All new templates saved will receive meta so we can distinguish between
1867+
// templates created the old way as edits and templates created the new way.
1868+
if ( ! isset( $changes->meta_input ) ) {
1869+
$changes->meta_input = array();
1870+
}
1871+
$changes->meta_input['is_inactive_by_default'] = true;
1872+
return $changes;
1873+
}
1874+
1875+
function wp_maybe_activate_template( $post_id ) {
1876+
$post = get_post( $post_id );
1877+
$is_inactive_by_default = get_post_meta( $post_id, 'is_inactive_by_default', true );
1878+
if ( $is_inactive_by_default ) {
1879+
return;
1880+
}
1881+
$active_templates = get_option( 'active_templates', array() );
1882+
$active_templates[ $post->post_name ] = $post->ID;
1883+
update_option( 'active_templates', $active_templates );
1884+
}

src/wp-includes/block-template.php

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,77 @@ function resolve_block_template( $template_type, $template_hierarchy, $fallback_
164164
$template_hierarchy
165165
);
166166

167-
// Find all potential templates 'wp_template' post matching the hierarchy.
167+
$object = get_queried_object();
168+
$specific_template = $object ? get_page_template_slug( $object ) : null;
169+
$active_templates = (array) get_option( 'active_templates', array() );
170+
171+
// Remove templates slugs that are deactivated, except if it's the specific
172+
// template or index.
173+
$slugs = array_filter(
174+
$slugs,
175+
function ( $slug ) use ( $specific_template, $active_templates ) {
176+
$should_ignore = $slug === $specific_template || 'index' === $slug;
177+
return $should_ignore || ( ! isset( $active_templates[ $slug ] ) || false !== $active_templates[ $slug ] );
178+
}
179+
);
180+
181+
// We expect one template for each slug. Use the active template if it is
182+
// set and exists. Otherwise use the static template.
183+
$templates = array();
184+
$remaining_slugs = array();
185+
186+
foreach ( $slugs as $slug ) {
187+
if ( $slug === $specific_template || empty( $active_templates[ $slug ] ) ) {
188+
$remaining_slugs[] = $slug;
189+
continue;
190+
}
191+
192+
// TODO: it need to be possible to set a static template as active.
193+
$post = get_post( $active_templates[ $slug ] );
194+
if ( ! $post || 'publish' !== $post->post_status ) {
195+
$remaining_slugs[] = $slug;
196+
continue;
197+
}
198+
199+
$template = _build_block_template_result_from_post( $post );
200+
201+
// Ensure the active templates are associated with the active theme.
202+
// See _build_block_template_object_from_post_object.
203+
if ( get_stylesheet() !== $template->theme ) {
204+
$remaining_slugs[] = $slug;
205+
continue;
206+
}
207+
208+
$templates[] = $template;
209+
}
210+
211+
// Apply the filter to the active templates for backward compatibility.
212+
/** This filter is documented in wp-includes/block-template-utils.php */
213+
if ( ! empty( $templates ) ) {
214+
$templates = apply_filters(
215+
'get_block_templates',
216+
$templates,
217+
array(
218+
'slug__in' => array_map(
219+
function ( $template ) {
220+
return $template->slug;
221+
},
222+
$templates
223+
),
224+
),
225+
'wp_template'
226+
);
227+
}
228+
229+
// For any remaining slugs, use the static template.
168230
$query = array(
169-
'slug__in' => $slugs,
231+
'slug__in' => $remaining_slugs,
170232
);
171-
$templates = get_block_templates( $query );
233+
$templates = array_merge( $templates, get_registered_block_templates( $query ) );
234+
235+
if ( $specific_template ) {
236+
$templates = array_merge( $templates, get_block_templates( array( 'slug__in' => array( $specific_template ) ) ) );
237+
}
172238

173239
// Order these templates per slug priority.
174240
// Build map of template slugs to their priority in the current hierarchy.

src/wp-includes/default-filters.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@
740740
// Block templates post type and rendering.
741741
add_filter( 'render_block_context', '_block_template_render_without_post_block_context' );
742742
add_filter( 'pre_wp_unique_post_slug', 'wp_filter_wp_template_unique_post_slug', 10, 5 );
743+
add_action( 'save_post_wp_template', 'wp_maybe_activate_template' );
743744
add_action( 'save_post_wp_template_part', 'wp_set_unique_slug_on_create_template_part' );
744745
add_action( 'wp_enqueue_scripts', 'wp_enqueue_block_template_skip_link' );
745746
add_action( 'wp_footer', 'the_block_template_skip_link' ); // Retained for backwards-compatibility. Unhooked by wp_enqueue_block_template_skip_link().
@@ -780,6 +781,10 @@
780781
add_filter( 'rest_pre_insert_wp_template', 'inject_ignored_hooked_blocks_metadata_attributes' );
781782
add_filter( 'rest_pre_insert_wp_template_part', 'inject_ignored_hooked_blocks_metadata_attributes' );
782783

784+
// Assign the wp_theme term to any newly created wp_template with the new endpoint.
785+
// Must run before `inject_ignored_hooked_blocks_metadata_attributes`.
786+
add_action( 'rest_pre_insert_wp_template', 'wp_assign_new_template_to_theme', 9, 2 );
787+
783788
// Update ignoredHookedBlocks postmeta for some post types.
784789
add_filter( 'rest_pre_insert_page', 'update_ignored_hooked_blocks_postmeta' );
785790
add_filter( 'rest_pre_insert_post', 'update_ignored_hooked_blocks_postmeta' );

src/wp-includes/option.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2959,6 +2959,25 @@ function register_initial_settings() {
29592959
'description' => __( 'Allow people to submit comments on new posts.' ),
29602960
)
29612961
);
2962+
2963+
register_setting(
2964+
'reading',
2965+
'active_templates',
2966+
array(
2967+
'type' => 'object',
2968+
// Do not set the default value to an empty array! For some reason
2969+
// that will prevent the option from being set to an empty array.
2970+
'show_in_rest' => array(
2971+
'schema' => array(
2972+
'type' => 'object',
2973+
// Properties can be integers, strings, or false
2974+
// (deactivated).
2975+
'additionalProperties' => true,
2976+
),
2977+
),
2978+
'label' => 'Active Templates',
2979+
)
2980+
);
29622981
}
29632982

29642983
/**

src/wp-includes/post.php

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -398,10 +398,8 @@ function create_initial_post_types() {
398398
'show_in_menu' => false,
399399
'show_in_rest' => true,
400400
'rewrite' => false,
401-
'rest_base' => 'templates',
402-
'rest_controller_class' => 'WP_REST_Templates_Controller',
403-
'autosave_rest_controller_class' => 'WP_REST_Template_Autosaves_Controller',
404-
'revisions_rest_controller_class' => 'WP_REST_Template_Revisions_Controller',
401+
'rest_base' => 'wp_template',
402+
'rest_controller_class' => 'WP_REST_Posts_Controller',
405403
'late_route_registration' => true,
406404
'capability_type' => array( 'template', 'templates' ),
407405
'capabilities' => array(
@@ -426,6 +424,7 @@ function create_initial_post_types() {
426424
'editor',
427425
'revisions',
428426
'author',
427+
'custom-fields',
429428
),
430429
)
431430
);
@@ -8629,4 +8628,16 @@ function wp_create_initial_post_meta() {
86298628
),
86308629
)
86318630
);
8631+
8632+
// Allow setting the is_wp_suggestion meta field, which partly determines if
8633+
// a template is a custom template.
8634+
register_post_meta(
8635+
'wp_template',
8636+
'is_wp_suggestion',
8637+
array(
8638+
'type' => 'boolean',
8639+
'show_in_rest' => true,
8640+
'single' => true,
8641+
)
8642+
);
86328643
}

0 commit comments

Comments
 (0)