Skip to content

Commit

Permalink
[Site Editor]: Add fallback template content on creation (#42520)
Browse files Browse the repository at this point in the history
* [Site Editor]: Add fallback template content on creation

* Update lib/compat/wordpress-6.1/block-template-utils.php

Co-authored-by: Bernie Reiter <ockham@raz.or.at>

* fix function name typo

* rename the route

* move template hierarchy calculation client side

* move get_template_hierarchy server side

* remove js tests

Co-authored-by: Bernie Reiter <ockham@raz.or.at>
  • Loading branch information
ntsekouras and ockham committed Aug 4, 2022
1 parent 4f05cc4 commit f99819b
Show file tree
Hide file tree
Showing 10 changed files with 423 additions and 13 deletions.
60 changes: 60 additions & 0 deletions lib/compat/wordpress-6.1/block-template-utils.php
Expand Up @@ -296,3 +296,63 @@ function gutenberg_build_block_template_result_from_post( $post ) {
}
return $template;
}

/**
* Helper function to get the Template Hierarchy for a given slug.
* We need to Handle special cases here like `front-page`, `singular` and `archive` templates.
*
* Noting that we always add `index` as the last fallback template.
*
* @param string $slug The template slug to be created.
* @param boolean $is_custom Indicates if a template is custom or part of the template hierarchy.
* @param string $template_prefix The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`.
*
* @return array<string> The template hierarchy.
*/
function get_template_hierarchy( $slug, $is_custom = false, $template_prefix = '' ) {
if ( 'index' === $slug ) {
return array( 'index' );
}
if ( $is_custom ) {
return array( 'page', 'singular', 'index' );
}
if ( 'front-page' === $slug ) {
return array( 'front-page', 'home', 'index' );
}
$template_hierarchy = array( $slug );
// Most default templates don't have `$template_prefix` assigned.
if ( $template_prefix ) {
list($type) = explode( '-', $template_prefix );
// We need these checks because we always add the `$slug` above.
if ( ! in_array( $template_prefix, array( $slug, $type ), true ) ) {
$template_hierarchy[] = $template_prefix;
}
if ( $slug !== $type ) {
$template_hierarchy[] = $type;
}
}
// Handle `archive` template.
if (
str_starts_with( $slug, 'author' ) ||
str_starts_with( $slug, 'taxonomy' ) ||
str_starts_with( $slug, 'category' ) ||
str_starts_with( $slug, 'tag' ) ||
'date' === $slug
) {
$template_hierarchy[] = 'archive';
}
// Handle `single` template.
if ( 'attachment' === $slug ) {
$template_hierarchy[] = 'single';
}
// Handle `singular` template.
if (
str_starts_with( $slug, 'single' ) ||
str_starts_with( $slug, 'page' ) ||
'attachment' === $slug
) {
$template_hierarchy[] = 'singular';
}
$template_hierarchy[] = 'index';
return $template_hierarchy;
};
Expand Up @@ -10,6 +10,62 @@
* Base Templates REST API Controller.
*/
class Gutenberg_REST_Templates_Controller extends WP_REST_Templates_Controller {

/**
* Registers the controllers routes.
*
* @return void
*/
public function register_routes() {
// Get fallback template content.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/lookup',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_template_fallback' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => array(
'slug' => array(
'description' => __( 'The slug of the template to get the fallback for', 'gutenberg' ),
'type' => 'string',
),
'is_custom' => array(
'description' => __( ' Indicates if a template is custom or part of the template hierarchy', 'gutenberg' ),
'type' => 'boolean',
),
'template_prefix' => array(
'description' => __( 'The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`', 'gutenberg' ),
'type' => 'string',
),
),
),
)
);
parent::register_routes();
}

/**
* Returns the fallback template for a given slug.
*
* @param WP_REST_Request $request The request instance.
*
* @return WP_REST_Response|WP_Error
*/
public function get_template_fallback( $request ) {
if ( empty( $request['slug'] ) ) {
return new WP_Error(
'rest_invalid_param',
__( 'Invalid slug.', 'gutenberg' ),
array( 'status' => 400 )
);
}
$hierarchy = get_template_hierarchy( $request['slug'], $request['is_custom'], $request['template_prefix'] );
$fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' );
return rest_ensure_response( $fallback_template );
}

/**
* Returns a list of templates.
*
Expand Down
Expand Up @@ -192,9 +192,18 @@ function AddCustomTemplateModal( { onClose, onSelect, entityForSuggestions } ) {
isBlock
as={ Button }
onClick={ () => {
const { slug, title, description } =
entityForSuggestions.template;
onSelect( { slug, title, description } );
const {
slug,
title,
description,
templatePrefix,
} = entityForSuggestions.template;
onSelect( {
slug,
title,
description,
templatePrefix,
} );
} }
>
<Text as="span" weight={ 600 }>
Expand Down
@@ -1,6 +1,8 @@
/**
* WordPress dependencies
*/
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';
import {
DropdownMenu,
MenuGroup,
Expand Down Expand Up @@ -91,7 +93,19 @@ export default function NewTemplate( { postType } ) {

async function createTemplate( template, isWPSuggestion = true ) {
try {
const { title, description, slug } = template;
const { title, description, slug, templatePrefix } = template;
let templateContent = template.content;
// Try to find fallback content from existing templates.
if ( ! templateContent ) {
const fallbackTemplate = await apiFetch( {
path: addQueryArgs( '/wp/v2/templates/lookup', {
slug,
is_custom: ! isWPSuggestion,
template_prefix: templatePrefix,
} ),
} );
templateContent = fallbackTemplate.content;
}
const newTemplate = await saveEntityRecord(
'postType',
'wp_template',
Expand All @@ -101,6 +115,7 @@ export default function NewTemplate( { postType } ) {
slug: slug.toString(),
status: 'publish',
title,
content: templateContent,
// This adds a post meta field in template that is part of `is_custom` value calculation.
is_wp_suggestion: isWPSuggestion,
},
Expand Down
17 changes: 14 additions & 3 deletions packages/edit-site/src/components/add-new-template/utils.js
Expand Up @@ -152,7 +152,10 @@ export const usePostTypeMenuItems = ( onClickMenuItem ) => {
);
}
const menuItem = defaultTemplateType
? { ...defaultTemplateType }
? {
...defaultTemplateType,
templatePrefix: templatePrefixes[ slug ],
}
: {
slug: generalTemplateSlug,
title: menuItemTitle,
Expand All @@ -167,6 +170,7 @@ export const usePostTypeMenuItems = ( onClickMenuItem ) => {
icon: icon?.startsWith( 'dashicons-' )
? icon.slice( 10 )
: post,
templatePrefix: templatePrefixes[ slug ],
};
const hasEntities = postTypesInfo?.[ slug ]?.hasEntities;
// We have a different template creation flow only if they have entities.
Expand Down Expand Up @@ -210,6 +214,7 @@ export const usePostTypeMenuItems = ( onClickMenuItem ) => {
title,
description,
slug: `${ templatePrefixes[ slug ] }-${ suggestion.slug }`,
templatePrefix: templatePrefixes[ slug ],
};
},
},
Expand Down Expand Up @@ -317,7 +322,10 @@ export const useTaxonomiesMenuItems = ( onClickMenuItem ) => {
);
}
const menuItem = defaultTemplateType
? { ...defaultTemplateType }
? {
...defaultTemplateType,
templatePrefix: templatePrefixes[ slug ],
}
: {
slug: generalTemplateSlug,
title: menuItemTitle,
Expand All @@ -327,6 +335,7 @@ export const useTaxonomiesMenuItems = ( onClickMenuItem ) => {
labels.singular_name
),
icon: blockMeta,
templatePrefix: templatePrefixes[ slug ],
};
const hasEntities = taxonomiesInfo?.[ slug ]?.hasEntities;
// We have a different template creation flow only if they have entities.
Expand Down Expand Up @@ -369,6 +378,7 @@ export const useTaxonomiesMenuItems = ( onClickMenuItem ) => {
title,
description,
slug: `${ templatePrefixes[ slug ] }-${ suggestion.slug }`,
templatePrefix: templatePrefixes[ slug ],
};
},
},
Expand Down Expand Up @@ -455,7 +465,7 @@ export function useAuthorMenuItem( onClickMenuItem ) {
( { slug } ) => slug === 'author'
);
if ( authorInfo.user?.hasEntities ) {
authorMenuItem = { ...authorMenuItem };
authorMenuItem = { ...authorMenuItem, templatePrefix: 'author' };
authorMenuItem.onClick = ( template ) => {
onClickMenuItem( {
type: 'root',
Expand Down Expand Up @@ -494,6 +504,7 @@ export function useAuthorMenuItem( onClickMenuItem ) {
title,
description,
slug: `author-${ suggestion.slug }`,
templatePrefix: 'author',
};
},
},
Expand Down

0 comments on commit f99819b

Please sign in to comment.