Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FSE: Fall back to next best template in hierarchy when querying through REST API (Take Two) #41848

Closed
86 changes: 63 additions & 23 deletions lib/compat/wordpress-6.1/block-template-utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,22 @@ function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_t
return apply_filters( 'get_block_templates', $query_result, $query, $template_type );
}

function gutenberg_get_template_slugs( $template ) {
$limit = 2;
if ( strpos( $template, 'single-' ) === 0 || strpos( $template, 'taxonomy-' ) === 0 ) {
// E.g. single-post-mypost or taxonomy-recipes-vegetarian.
$limit = 3;
}
$parts = explode( '-', $template, $limit );
$type = array_shift( $parts );
$slugs = array( $type );

foreach ( $parts as $part ) {
array_unshift( $slugs, $slugs[0] . '-' . $part );
}
return $slugs;
}

/**
* Retrieves a single unified template object using its id.
*
Expand Down Expand Up @@ -195,34 +211,58 @@ function gutenberg_get_block_template( $id, $template_type = 'wp_template' ) {
if ( count( $parts ) < 2 ) {
return null;
}
list( $theme, $slug ) = $parts;
$wp_query_args = array(
'post_name__in' => array( $slug ),
'post_type' => $template_type,
'post_status' => array( 'auto-draft', 'draft', 'publish', 'trash' ),
'posts_per_page' => 1,
'no_found_rows' => true,
'tax_query' => array(
array(
'taxonomy' => 'wp_theme',
'field' => 'name',
'terms' => $theme,
),
),
);
$template_query = new WP_Query( $wp_query_args );
$posts = $template_query->posts;
list( , $slug ) = $parts;

if ( count( $posts ) > 0 ) {
$template = gutenberg_build_block_template_result_from_post( $posts[0] );
$templates = gutenberg_get_template_slugs( $slug );
$block_template = resolve_block_template( $slug, $templates, '' );
if ( ! $block_template ) {
$block_template = resolve_block_template( 'index', array(), '' );
}
// This might give us a fallback template with a different ID,
// so we have to override it to make sure it's correct.
$block_template->id = $id;
$block_template->slug = $slug;
$default_template_types = get_default_block_template_types();

$slug_parts = explode( '-', $slug, 3 );
if ( count( $slug_parts ) > 1 ) {
if ( 'single' === $slug_parts [0] ) {
// Get CPT labels
$post_type = get_post_type_object( $slug_parts[1] );
$labels = $post_type->labels;

if ( ! is_wp_error( $template ) ) {
return $template;
if ( count( $slug_parts ) > 2 ) {
// Now we look for the CPT with slug as defined in $slug_parts[2]
$post = get_page_by_path( $slug_parts[2], OBJECT, $slug_parts[1] );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use this function over a WP_Query?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WP_Query is probably the better option; get_page_by_path was the stop-gap to make it work 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also can't we just do this?

Suggested change
$post = get_page_by_path( $slug_parts[2], OBJECT, $slug_parts[1] );
$post = get_page_by_path( $slug_parts[2], OBJECT, $template_type );

Copy link
Contributor Author

@ockham ockham Jun 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid that won't work -- $template_type will be something like single, category, or even 404.

If it's single, then $slug_parts[1] will be the post type that the template is for.

($template_type OTOH will be reflected in $slug_parts[0].)

$block_template->title = sprintf(
// translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the singular name of a post type and %2$s is the name of the post, e.g. "Post: Hello, WordPress"
__( '%1$s: %2$s' ),
$labels->singular_name,
$post->post_title
);
$block_template->description = sprintf(
// translators: Represents the description of a user's custom template in the Site Editor, e.g. "Template for Post: Hello, WordPress"
__( 'Template for %1$s' ),
$block_template->title
);
} else {
$block_template->title = sprintf(
// translators: %s: Name of the post type e.g: "Post".
__( 'Single item: %s' ),
$labels->singular_name
);
$block_template->description = sprintf(
// translators: %s: Name of the post type e.g: "Post".
__( 'Displays a single item: %s.' ),
$labels->singular_name
);
}
}
} elseif ( array_key_exists( $slug, $default_template_types ) ) {
$block_template->title = $default_template_types[ $slug ]['title'];
$block_template->description = $default_template_types[ $slug ]['description'];
}
ockham marked this conversation as resolved.
Show resolved Hide resolved

$block_template = get_block_file_template( $id, $template_type );

/**
* Filters the queried block template object after it's been fetched.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,23 @@ public function create_item( $request ) {
);
}

/**
* Deletes a single template.
*
* @since 5.8.0
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function delete_item( $request ) {
$template = get_block_template( $request['id'], $this->post_type );
if ( ! $template || $template->id !== $request['id'] ) { // Make sure there is a template for this ID (and not just a fallback one).
return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) );
}

return parent::delete_item( $request );
}

/**
* Updates a single template.
*
Expand Down
52 changes: 8 additions & 44 deletions packages/edit-site/src/components/add-new-template/new-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
NavigableMenu,
} from '@wordpress/components';
import { useState } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { store as editorStore } from '@wordpress/editor';
import {
Expand All @@ -32,15 +32,13 @@ import {
tag,
} from '@wordpress/icons';
import { __, sprintf } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';

/**
* Internal dependencies
*/
import AddCustomTemplateModal from './add-custom-template-modal';
import { usePostTypes, usePostTypesEntitiesInfo } from './utils';
import { useHistory } from '../routes';
import { store as editSiteStore } from '../../store';

const DEFAULT_TEMPLATE_SLUGS = [
'front-page',
Expand Down Expand Up @@ -79,7 +77,7 @@ export default function NewTemplate( { postType } ) {
const [ showCustomTemplateModal, setShowCustomTemplateModal ] =
useState( false );
const [ entityForSuggestions, setEntityForSuggestions ] = useState( {} );
const { existingTemplates, defaultTemplateTypes } = useSelect(
const { existingTemplates, defaultTemplateTypes, theme } = useSelect(
( select ) => ( {
existingTemplates: select( coreStore ).getEntityRecords(
'postType',
Expand All @@ -88,52 +86,18 @@ export default function NewTemplate( { postType } ) {
),
defaultTemplateTypes:
select( editorStore ).__experimentalGetDefaultTemplateTypes(),
theme: select( coreStore ).getCurrentTheme(),
} ),
[]
);
const postTypesEntitiesInfo = usePostTypesEntitiesInfo( existingTemplates );
const { saveEntityRecord } = useDispatch( coreStore );
const { createErrorNotice } = useDispatch( noticesStore );
const { setTemplate } = useDispatch( editSiteStore );

async function createTemplate( template ) {
try {
const { title, description, slug } = template;
const newTemplate = await saveEntityRecord(
'postType',
'wp_template',
{
description,
// Slugs need to be strings, so this is for template `404`
slug: slug.toString(),
status: 'publish',
title,
// This adds a post meta field in template that is part of `is_custom` value calculation.
is_wp_suggestion: true,
},
{ throwOnError: true }
);

// Set template before navigating away to avoid initial stale value.
setTemplate( newTemplate.id, newTemplate.slug );

// Navigate to the created template editor.
history.push( {
postId: newTemplate.id,
postType: newTemplate.type,
} );

// TODO: Add a success notice?
} catch ( error ) {
const errorMessage =
error.message && error.code !== 'unknown_error'
? error.message
: __( 'An error occurred while creating the template.' );

createErrorNotice( errorMessage, {
type: 'snackbar',
} );
}
const { slug } = template;
history.push( {
postId: theme.stylesheet + '//' + slug.toString(),
postType: 'wp_template',
} );
}
const existingTemplateSlugs = ( existingTemplates || [] ).map(
( { slug } ) => slug
Expand Down