Skip to content

Commit

Permalink
Templates: allow templates to be activated and deactivated
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Nov 19, 2024
1 parent d478c08 commit 1d75cf3
Show file tree
Hide file tree
Showing 43 changed files with 674 additions and 413 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
<?php

Check failure on line 1 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Class file names should be based on the class name with "class-" prepended. Expected class-gutenberg-rest-templates-controller.php, but found class-gutenberg-rest-static-templates-controller.php.

// How does this work?
// 1. For wp_template, we remove the custom templates controller, so it becomes
// and normals posts endpoint.

function gutenberg_modify_wp_template_post_type_args( $args, $post_type ) {
if ( 'wp_template' === $post_type ) {
$args['rest_base'] = 'wp_template';
$args['rest_controller_class'] = 'Gutenberg_REST_Templates_Controller';
$args['autosave_rest_controller_class'] = null;
$args['revisions_rest_controller_class'] = null;
}
return $args;
}

add_filter( 'register_post_type_args', 'gutenberg_modify_wp_template_post_type_args', 10, 2 );

class Gutenberg_REST_Templates_Controller extends WP_REST_Posts_Controller {
protected function handle_status_param( $status, $request ) {
if ( $status === 'auto-draft' ) {

Check failure on line 21 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Use Yoda Condition checks, you must.
return $status;
}
return parent::handle_status_param( $status, $request );
}
protected function add_additional_fields_schema( $schema ) {
$schema = parent::add_additional_fields_schema( $schema );

Check warning on line 27 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Equals sign not aligned with surrounding assignments; expected 35 spaces but found 1 space
$schema['properties']['status']['enum'][] = 'auto-draft';
return $schema;
}
}

// 2. We maintain the routes for /templates and /templates/lookup. I think we'll
// need to deprecate /templates eventually, but we'll still want to be able to
// lookup the active template for a specific slug, and probably get a list of
// all _active_ templates. For that we can keep /lookup.

function gutenberg_maintain_templates_routes() {
// This should later be changed in core so we don't need initialise
// WP_REST_Templates_Controller with a post type.
global $wp_post_types;
$wp_post_types['wp_template']->rest_base = 'templates';
$controller = new WP_REST_Templates_Controller( 'wp_template' );
$wp_post_types['wp_template']->rest_base = 'wp_template';
$controller->register_routes();
}
add_action( 'rest_api_init', 'gutenberg_maintain_templates_routes' );

// 3. Even though this doesn't need to exist as a post type, we need routes to
// get that raw static templates from themes and plugins. I did not want to
// templates for back-compat. Also I registered these as a post type route
// because right now the EditorProvider assumes templates are posts.

function gutenberg_setup_static_template() {
global $wp_post_types;
$wp_post_types['_wp_static_template'] = clone $wp_post_types['wp_template'];

Check warning on line 56 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Equals sign not aligned with surrounding assignments; expected 24 spaces but found 26 spaces
$wp_post_types['_wp_static_template']->name = '_wp_static_template';

Check warning on line 57 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Equals sign not aligned with surrounding assignments; expected 18 spaces but found 1 space

Check failure on line 57 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Expected 1 space after "="; 18 found
$wp_post_types['_wp_static_template']->rest_base = '_wp_static_template';

Check warning on line 58 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Equals sign not aligned with surrounding assignments; expected 13 spaces but found 1 space

Check failure on line 58 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Expected 1 space after "="; 13 found
$wp_post_types['_wp_static_template']->rest_controller_class = 'Gutenberg_REST_Static_Templates_Controller';

register_setting( 'reading', 'active_templates', array(

Check failure on line 61 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Opening parenthesis of a multi-line function call must be the last content on the line

Check failure on line 61 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Only one argument is allowed per line in a multi-line function call

Check failure on line 61 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Only one argument is allowed per line in a multi-line function call
'type' => 'object',

Check warning on line 62 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Array double arrow not aligned correctly; expected 9 space(s) between "'type'" and double arrow, but found 1.
'show_in_rest' => array(
'schema' => array(
'type' => 'object',

Check warning on line 65 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Array double arrow not aligned correctly; expected 17 space(s) between "'type'" and double arrow, but found 1.
'additionalProperties' => true,
),
),
'default' => array(),

Check warning on line 69 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Array double arrow not aligned correctly; expected 6 space(s) between "'default'" and double arrow, but found 1.
) );

Check failure on line 70 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Closing parenthesis of a multi-line function call must be on a line by itself
}
add_action( 'init', 'gutenberg_setup_static_template' );

class Gutenberg_REST_Static_Templates_Controller extends WP_REST_Templates_Controller {

Check failure on line 74 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Only one object structure is allowed in a file
public function __construct( $post_type ) {
parent::__construct( $post_type );
}

public function register_routes() {
// Lists all templates.
register_rest_route(
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);

// Lists/updates a single template based on the given id.
register_rest_route(
$this->namespace,
// The route.
sprintf(
'/%s/(?P<id>%s%s)',
$this->rest_base,
/*
* Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
* Excludes invalid directory name characters: `/:<>*?"|`.
*/
'([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)',
// Matches the template name.
'[\/\w%-]+'
),
array(
'args' => array(
'id' => array(
'description' => __( 'The id of a template' ),
'type' => 'string',
'sanitize_callback' => array( $this, '_sanitize_template_id' ),
),
),
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_item_permissions_check' ),
'args' => array(
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);
}

public function get_item_schema() {
$schema = parent::get_item_schema();

Check warning on line 132 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Equals sign not aligned with surrounding assignments; expected 28 spaces but found 1 space
$schema['properties']['is_custom'] = array(
'description' => __( 'Whether a template is a custom template.' ),
'type' => 'bool',
'context' => array( 'embed', 'view', 'edit' ),
'readonly' => true,
);
$schema['properties']['plugin'] = array(
'type' => 'string',
'description' => __( 'Plugin that registered the template.' ),
'readonly' => true,
'context' => array( 'view', 'edit', 'embed' ),
);
return $schema;
}

public function get_items( $request ) {
$query = array();
if ( isset( $request['area'] ) ) {
$query['area'] = $request['area'];
}
if ( isset( $request['post_type'] ) ) {
$query['post_type'] = $request['post_type'];
}
$template_files = _get_block_templates_files( 'wp_template', $query );

Check warning on line 156 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Equals sign not aligned correctly; expected 1 space but found 8 spaces
foreach ( $template_files as $template_file ) {
$query_result[] = _build_block_template_result_from_file( $template_file, 'wp_template' );

Check warning on line 158 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Array variable $query_result is undefined.
}

// Add templates registered in the template registry. Filtering out the ones which have a theme file.
$registered_templates = WP_Block_Templates_Registry::get_instance()->get_by_query( $query );
$matching_registered_templates = array_filter(
$registered_templates,
function ( $registered_template ) use ( $template_files ) {
foreach ( $template_files as $template_file ) {
if ( $template_file['slug'] === $registered_template->slug ) {
return false;
}
}
return true;
}
);
$query_result = array_merge( $query_result, $matching_registered_templates );

$templates = array();
foreach ( $query_result as $template ) {
$item = $this->prepare_item_for_response( $template, $request );
$item->data['type'] = '_wp_static_template';
$templates[] = $this->prepare_response_for_collection( $item );
}

return rest_ensure_response( $templates );
}

public function get_item( $request ) {
$template = get_block_file_template( $request['id'], 'wp_template' );

if ( ! $template ) {
return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) );
}

$item = $this->prepare_item_for_response( $template, $request );
// adjust the template type here instead
$item->data['type'] = '_wp_static_template';
return rest_ensure_response( $item );
}
}

function gutenberg_allow_template_slugs_to_be_duplicated( $override, $slug, $post_id, $post_status, $post_type ) {
return $post_type === 'wp_template' ? $slug : $override;

Check failure on line 201 in lib/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Use Yoda Condition checks, you must.
}

add_filter( 'pre_wp_unique_post_slug', 'gutenberg_allow_template_slugs_to_be_duplicated', 10, 5 );

function gutenberg_pre_get_block_templates( $output, $query, $template_type ) {
if ( $template_type === 'wp_template' && ! empty( $query['slug__in'] ) ) {
$active_templates = get_option( 'active_templates', array() );
$slugs = $query['slug__in'];
$output = array();
foreach ( $slugs as $slug ) {
if ( isset( $active_templates[ $slug ] ) ) {
if ( $active_templates[ $slug ] !== false ) {
$post = get_post( $active_templates[ $slug ] );
if ( $post ) {
$output[] = _build_block_template_result_from_post( $post );
}
} else {
// Deactivated template, fall back to next slug.
$output[] = array();
}
}
}
if ( empty( $output ) ) {
$output = null;
}
}
return $output;
}

add_filter( 'pre_get_block_templates', 'gutenberg_pre_get_block_templates', 10, 3 );

// Bypass the terms check in _build_block_template_result_from_post.
function gutenberg_get_the_terms( $terms, $object_id, $taxonomy ) {
if ( $taxonomy === 'wp_theme' ) {
$stylesheet = get_stylesheet();
return array(
new WP_Term(
(object) array(
'term_id' => 0,
'name' => $stylesheet,
'slug' => $stylesheet,
'taxonomy' => 'wp_theme',
),
),
);
}
return $terms;
}
add_filter( 'get_the_terms', 'gutenberg_get_the_terms', 10, 3 );
5 changes: 3 additions & 2 deletions lib/compat/wordpress-6.8/preload.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ function gutenberg_block_editor_preload_paths_6_8( $paths, $context ) {
'url',
)
);
$paths[] = '/wp/v2/templates/lookup?slug=front-page';
$paths[] = '/wp/v2/templates/lookup?slug=home';
// There's an issue where preloaded data does not invalidate.
// $paths[] = '/wp/v2/templates/lookup?slug=front-page';
// $paths[] = '/wp/v2/templates/lookup?slug=home';
}

// Preload theme and global styles paths.
Expand Down
1 change: 1 addition & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/compat/wordpress-6.7/rest-api.php';

// WordPress 6.8 compat.
require __DIR__ . '/compat/wordpress-6.8/class-gutenberg-rest-static-templates-controller.php';
require __DIR__ . '/compat/wordpress-6.8/block-comments.php';
require __DIR__ . '/compat/wordpress-6.8/class-gutenberg-rest-comment-controller-6-8.php';
require __DIR__ . '/compat/wordpress-6.8/class-gutenberg-rest-post-types-controller-6-8.php';
Expand Down
10 changes: 10 additions & 0 deletions packages/core-data/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ export const editEntityRecord =
`The entity being edited (${ kind }, ${ name }) does not have a loaded config.`
);
}
if ( ! select.canUser( 'update', { kind, name, id: recordId } ) ) {
return;
}
const { mergedEdits = {} } = entityConfig;
const record = select.getRawEntityRecord( kind, name, recordId );
const editedRecord = select.getEditedEntityRecord(
Expand Down Expand Up @@ -673,6 +676,13 @@ export const saveEntityRecord =
),
};
}
if (
! edits.status &&
persistedRecord?.status === 'auto-draft'
) {
edits.status =
name === 'wp_template' ? 'publish' : 'draft';
}
updatedRecord = await __unstableFetch( {
path,
method: recordId ? 'PUT' : 'POST',
Expand Down
4 changes: 4 additions & 0 deletions packages/core-data/src/private-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ export function receiveRegisteredPostMeta( postType, registeredPostMeta ) {
registeredPostMeta,
};
}

export function receiveTemplateAutoDraftId( target, id ) {
return { type: 'RECEIVE_TEMPLATE_AUTO_DRAFT_ID', target, id };
}
4 changes: 4 additions & 0 deletions packages/core-data/src/private-selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,7 @@ export const getTemplateId = createRegistrySelector(
} );
}
);

export function getTemplateAutoDraftId( state: State, target: string ) {
return state.templateAutoDraftId[ target ];
}
7 changes: 7 additions & 0 deletions packages/core-data/src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,12 @@ export function registeredPostMeta( state = {}, action ) {
return state;
}

export function templateAutoDraftId( state = {}, action ) {
return action.type === 'RECEIVE_TEMPLATE_AUTO_DRAFT_ID'
? { ...state, [ action.target ]: action.id }
: state;
}

export default combineReducers( {
terms,
users,
Expand All @@ -669,4 +675,5 @@ export default combineReducers( {
navigationFallbackId,
defaultTemplates,
registeredPostMeta,
templateAutoDraftId,
} );
Loading

0 comments on commit 1d75cf3

Please sign in to comment.