Skip to content

Commit

Permalink
Add: Modal to choose a start pattern on new templates. (#46248)
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta authored Feb 9, 2023
1 parent 0daf720 commit ad9624a
Show file tree
Hide file tree
Showing 11 changed files with 341 additions and 32 deletions.
16 changes: 0 additions & 16 deletions lib/compat/wordpress-6.1/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,6 @@
* @package gutenberg
*/

/**
* Update `wp_template` and `wp_template-part` post types to use
* Gutenberg's REST controller.
*
* @param array $args Array of arguments for registering a post type.
* @param string $post_type Post type key.
*/
function gutenberg_update_templates_template_parts_rest_controller( $args, $post_type ) {
if ( in_array( $post_type, array( 'wp_template', 'wp_template-part' ), true ) ) {
$args['rest_controller_class'] = 'Gutenberg_REST_Templates_Controller';
}
return $args;
}
add_filter( 'register_post_type_args', 'gutenberg_update_templates_template_parts_rest_controller', 10, 2 );


/**
* Add the post type's `icon`(menu_icon) in the response.
* When we backport this change we will need to add the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php
/**
* REST API: Gutenberg_REST_Templates_Controller_6_2 class
*
* @package Gutenberg
* @subpackage REST_API
*/

/**
* Base Templates REST API Controller.
*/
class Gutenberg_REST_Templates_Controller_6_2 extends Gutenberg_REST_Templates_Controller {

/**
* Registers the controllers routes.
*
* @return void
*/
public function register_routes() {

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_item_permissions_check' ),
'args' => array(
'slug' => array(
'description' => __( 'The slug of the template to get the fallback for', 'gutenberg' ),
'type' => 'string',
'required' => true,
),
'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();
// Get fallback template content.
}

/**
* 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 ) {
$hierarchy = get_template_hierarchy( $request['slug'], $request['is_custom'], $request['template_prefix'] );
$fallback_template = null;
do {
$fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' );
array_shift( $hierarchy );
} while ( ! empty( $hierarchy ) && empty( $fallback_template->content ) );
$response = $this->prepare_item_for_response( $fallback_template, $request );
return rest_ensure_response( $response );
}
}
15 changes: 15 additions & 0 deletions lib/compat/wordpress-6.2/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@
* @package gutenberg
*/

/**
* Update `wp_template` and `wp_template-part` post types to use
* Gutenberg's REST controller.
*
* @param array $args Array of arguments for registering a post type.
* @param string $post_type Post type key.
*/
function gutenberg_update_templates_template_parts_rest_controller( $args, $post_type ) {
if ( in_array( $post_type, array( 'wp_template', 'wp_template-part' ), true ) ) {
$args['rest_controller_class'] = 'Gutenberg_REST_Templates_Controller_6_2';
}
return $args;
}
add_filter( 'register_post_type_args', 'gutenberg_update_templates_template_parts_rest_controller', 10, 2 );

/**
* Registers the block pattern categories REST API routes.
*/
Expand Down
1 change: 1 addition & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ function gutenberg_is_experiment_enabled( $name ) {
require_once __DIR__ . '/compat/wordpress-6.2/class-gutenberg-rest-block-patterns-controller-6-2.php';
require_once __DIR__ . '/compat/wordpress-6.2/class-gutenberg-rest-block-pattern-categories-controller.php';
require_once __DIR__ . '/compat/wordpress-6.2/class-gutenberg-rest-pattern-directory-controller-6-2.php';
require_once __DIR__ . '/compat/wordpress-6.2/class-gutenberg-rest-templates-controller-6-2.php';
require_once __DIR__ . '/compat/wordpress-6.2/rest-api.php';
require_once __DIR__ . '/compat/wordpress-6.2/block-patterns.php';
require_once __DIR__ . '/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/**
* WordPress dependencies
*/
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';
import {
DropdownMenu,
MenuGroup,
Expand Down Expand Up @@ -109,19 +107,7 @@ export default function NewTemplate( {
}
setIsCreatingTemplate( true );
try {
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.raw;
}
const { title, description, slug } = template;
const newTemplate = await saveEntityRecord(
'postType',
'wp_template',
Expand All @@ -131,7 +117,6 @@ export default function NewTemplate( {
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
2 changes: 2 additions & 0 deletions packages/edit-site/src/components/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import KeyboardShortcuts from '../keyboard-shortcuts';
import InserterSidebar from '../secondary-sidebar/inserter-sidebar';
import ListViewSidebar from '../secondary-sidebar/list-view-sidebar';
import WelcomeGuide from '../welcome-guide';
import StartTemplateOptions from '../start-template-options';
import { store as editSiteStore } from '../../store';
import { GlobalStylesRenderer } from '../global-styles-renderer';
import { GlobalStylesProvider } from '../global-styles/global-styles-provider';
Expand Down Expand Up @@ -170,6 +171,7 @@ export default function Editor() {
<GlobalStylesProvider>
<BlockContextProvider value={ blockContext }>
<SidebarComplementaryAreaFills />
{ isEditMode && <StartTemplateOptions /> }
<InterfaceSkeleton
enableRegionNavigation={ false }
className={
Expand Down
171 changes: 171 additions & 0 deletions packages/edit-site/src/components/start-template-options/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/**
* WordPress dependencies
*/
import { Modal } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useState, useEffect, useMemo } from '@wordpress/element';
import { __experimentalBlockPatternsList as BlockPatternsList } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';
import { useAsyncList } from '@wordpress/compose';
import { store as preferencesStore } from '@wordpress/preferences';
import { parse } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { store as editSiteStore } from '../../store';
import { store as coreStore, useEntityBlockEditor } from '@wordpress/core-data';
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';

function useFallbackTemplateContent( slug, isCustom = false ) {
const [ templateContent, setTemplateContent ] = useState( '' );

useEffect( () => {
apiFetch( {
path: addQueryArgs( '/wp/v2/templates/lookup', {
slug,
is_custom: isCustom,
ignore_empty: true,
} ),
} ).then( ( { content } ) => setTemplateContent( content.raw ) );
}, [ slug ] );
return templateContent;
}

const START_BLANK_TITLE = __( 'Start blank' );

function PatternSelection( { fallbackContent, onChoosePattern, postType } ) {
const [ , , onChange ] = useEntityBlockEditor( 'postType', postType );
const blockPatterns = useMemo(
() => [
{
name: 'fallback',
blocks: parse( fallbackContent ),
title: __( 'Fallback content' ),
},
{
name: 'start-blank',
blocks: parse(
'<!-- wp:paragraph --><p></p><!-- /wp:paragraph -->'
),
title: START_BLANK_TITLE,
},
],
[ fallbackContent ]
);
const shownBlockPatterns = useAsyncList( blockPatterns );

return (
<div
className="edit-site-start-template-options__pattern-container"
style={ {
'--wp-edit-site-start-template-options-start-blank': `"${ START_BLANK_TITLE }"`,
} }
>
<BlockPatternsList
blockPatterns={ blockPatterns }
shownPatterns={ shownBlockPatterns }
onClickPattern={ ( pattern, blocks ) => {
onChange( 'start-blank' === pattern.name ? [] : blocks, {
selection: undefined,
} );
onChoosePattern();
} }
/>
</div>
);
}

function StartModal( { slug, isCustom, onClose, postType } ) {
const fallbackContent = useFallbackTemplateContent( slug, isCustom );
if ( ! fallbackContent ) {
return null;
}
return (
<Modal
className="edit-site-start-template-options__modal"
title={ __( 'Choose a pattern' ) }
closeLabel={ __( 'Cancel' ) }
focusOnMount="firstElement"
onRequestClose={ onClose }
>
<div className="edit-site-start-template-options__modal-content">
<PatternSelection
fallbackContent={ fallbackContent }
slug={ slug }
isCustom={ isCustom }
postType={ postType }
onChoosePattern={ () => {
onClose();
} }
/>
</div>
</Modal>
);
}

const START_TEMPLATE_MODAL_STATES = {
INITIAL: 'INITIAL',
CLOSED: 'CLOSED',
};

export default function StartTemplateOptions() {
const [ modalState, setModalState ] = useState(
START_TEMPLATE_MODAL_STATES.INITIAL
);
const { shouldOpenModel, slug, isCustom, postType } = useSelect(
( select ) => {
const { getEditedPostType, getEditedPostId } =
select( editSiteStore );
const _postType = getEditedPostType();
const postId = getEditedPostId();
const {
__experimentalGetDirtyEntityRecords,
getEditedEntityRecord,
} = select( coreStore );
const templateRecord = getEditedEntityRecord(
'postType',
_postType,
postId
);

const hasDirtyEntityRecords =
__experimentalGetDirtyEntityRecords().length > 0;

return {
shouldOpenModel:
! hasDirtyEntityRecords &&
'' === templateRecord.content &&
'wp_template' === _postType &&
! select( preferencesStore ).get(
'core/edit-site',
'welcomeGuide'
),
slug: templateRecord.slug,
isCustom: templateRecord.is_custom,
postType: _postType,
};
},
[]
);

if (
( modalState === START_TEMPLATE_MODAL_STATES.INITIAL &&
! shouldOpenModel ) ||
modalState === START_TEMPLATE_MODAL_STATES.CLOSED
) {
return null;
}

return (
<StartModal
slug={ slug }
isCustom={ isCustom }
postType={ postType }
onClose={ () =>
setModalState( START_TEMPLATE_MODAL_STATES.CLOSED )
}
/>
);
}
Loading

0 comments on commit ad9624a

Please sign in to comment.