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

Site Editor: Add theme taxonomy to templates and template parts #27016

Merged
merged 40 commits into from
Nov 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
80ab088
Register taxonomy
david-szabo97 Nov 16, 2020
deccab4
Remove register theme meta
david-szabo97 Nov 16, 2020
c6cc0d0
Change meta queries to tax queries
david-szabo97 Nov 16, 2020
9052368
Fix template parts not loading
david-szabo97 Nov 16, 2020
84ad8eb
Remove unnecessary check
david-szabo97 Nov 16, 2020
dc8150c
Remove unnecessary check
david-szabo97 Nov 16, 2020
aa54ff0
Add meta to taxonomy migration
david-szabo97 Nov 17, 2020
36fd29b
Fix missing variable
david-szabo97 Nov 17, 2020
d4e1442
Run on init
david-szabo97 Nov 17, 2020
c81329e
Reload page after migration
david-szabo97 Nov 17, 2020
5fd09f1
Formatting
david-szabo97 Nov 17, 2020
a25cca6
Add domain
david-szabo97 Nov 17, 2020
21a8a60
Add doc
david-szabo97 Nov 17, 2020
4251e85
Add checks for rest and ajax
david-szabo97 Nov 17, 2020
d0108ed
Use Yoda Condition checks, we must.
david-szabo97 Nov 17, 2020
888641c
Only request ids
david-szabo97 Nov 17, 2020
a4d4cae
Avoid too many redirects
david-szabo97 Nov 17, 2020
c4c0183
Add file_based and wp_theme_slug to rest response
david-szabo97 Nov 17, 2020
2f074de
Replace old meta with tax
david-szabo97 Nov 17, 2020
de6377c
Use boolean
david-szabo97 Nov 17, 2020
6e28745
Query by slug
david-szabo97 Nov 17, 2020
a8abce2
Remove meta
david-szabo97 Nov 17, 2020
0dd6751
Replace meta with new prop
david-szabo97 Nov 17, 2020
f85b712
Formatiing
david-szabo97 Nov 17, 2020
a9c24a3
Fix linter errors
david-szabo97 Nov 17, 2020
2e70dd3
Remove migration
david-szabo97 Nov 17, 2020
21b7e67
Add missing piece for post-meta to tax refactor (#27042)
aristath Nov 17, 2020
d6e456e
Add underscore
david-szabo97 Nov 17, 2020
f42fb8e
Fix theme slug being null
david-szabo97 Nov 17, 2020
527c2ff
Add filter to wp_template too
david-szabo97 Nov 17, 2020
7fbabe6
Unify set theme function
david-szabo97 Nov 17, 2020
9d956fb
Move rest prepare function to templates file
david-szabo97 Nov 17, 2020
f1b72cc
Fix callback
david-szabo97 Nov 17, 2020
6616bd9
Replace data-type with class selector for template part e2e
noahtallen Nov 17, 2020
4a9becd
Fix theme not being saved for newly created templates
david-szabo97 Nov 17, 2020
6bb007c
Add theme in all cases if there no theme terms
david-szabo97 Nov 18, 2020
f76dbd6
Fix perf test
david-szabo97 Nov 18, 2020
d35d17e
Fix perf test
david-szabo97 Nov 18, 2020
0d6df47
Fix perf test
david-szabo97 Nov 18, 2020
3fbb91b
Fix perf test
david-szabo97 Nov 18, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions lib/edit-site-export.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,13 @@ function gutenberg_edit_site_export() {
array(
'post_type' => 'wp_template',
'post_status' => array( 'publish', 'auto-draft' ),
'meta_key' => 'theme',
'meta_value' => $theme,
'tax_query' => array(
array(
'taxonomy' => 'wp_theme',
'field' => 'slug',
'terms' => $theme,
),
),
'posts_per_page' => -1,
'no_found_rows' => true,
)
Expand All @@ -49,8 +54,13 @@ function gutenberg_edit_site_export() {
array(
'post_type' => 'wp_template_part',
'post_status' => array( 'publish', 'auto-draft' ),
'meta_key' => 'theme',
'meta_value' => $theme,
'tax_query' => array(
array(
'taxonomy' => 'wp_theme',
'field' => 'slug',
'terms' => $theme,
),
),
'posts_per_page' => -1,
'no_found_rows' => true,
)
Expand Down
9 changes: 7 additions & 2 deletions lib/template-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,13 @@ function gutenberg_resolve_template( $template_type, $template_hierarchy = array
'orderby' => 'post_name__in',
'posts_per_page' => -1,
'no_found_rows' => true,
'meta_key' => 'theme',
'meta_value' => wp_get_theme()->get_stylesheet(),
'tax_query' => array(
array(
'taxonomy' => 'wp_theme',
'field' => 'slug',
'terms' => wp_get_theme()->get_stylesheet(),
),
),
)
);
$templates = $template_query->get_posts();
Expand Down
41 changes: 6 additions & 35 deletions lib/template-parts.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,40 +55,10 @@ function gutenberg_register_template_part_post_type() {
),
);

$meta_args = array(
'object_subtype' => 'wp_template_part',
'type' => 'string',
'description' => 'The theme that provided the template part, if any.',
'single' => true,
'show_in_rest' => true,
);

register_post_type( 'wp_template_part', $args );
register_meta( 'post', 'theme', $meta_args );
}
add_action( 'init', 'gutenberg_register_template_part_post_type' );

/**
* Automatically set the theme meta for template parts.
*
* @param array $post_id Template Part ID.
* @param array $post Template Part Post.
* @param bool $update Is update.
*/
function gutenberg_set_template_part_post_theme( $post_id, $post, $update ) {
if ( 'wp_template_part' !== $post->post_type || $update || 'trash' === $post->post_status ) {
return;
}

$theme = get_post_meta( $post_id, 'theme', true );

if ( ! $theme ) {
update_post_meta( $post_id, 'theme', wp_get_theme()->get_stylesheet() );
}
}

add_action( 'save_post', 'gutenberg_set_template_part_post_theme', 10, 3 );

/**
* Filters `wp_template_part` posts slug resolution to bypass deduplication logic as
* template part slugs should be unique.
Expand Down Expand Up @@ -191,13 +161,14 @@ function filter_rest_wp_template_part_collection_params( $query_params ) {
*/
function filter_rest_wp_template_part_query( $args, $request ) {
if ( $request['theme'] ) {
$meta_query = isset( $args['meta_query'] ) ? $args['meta_query'] : array();
$meta_query[] = array(
'key' => 'theme',
'value' => $request['theme'],
$tax_query = isset( $args['tax_query'] ) ? $args['tax_query'] : array();
$tax_query[] = array(
'taxonomy' => 'wp_theme',
'field' => 'slug',
'terms' => $request['theme'],
);

$args['meta_query'] = $meta_query;
$args['tax_query'] = $tax_query;
Copons marked this conversation as resolved.
Show resolved Hide resolved
}

return $args;
Expand Down
10 changes: 8 additions & 2 deletions lib/templates-sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@ function _gutenberg_create_auto_draft_for_template( $post_type, $slug, $theme, $
'post_type' => $post_type,
'post_status' => array( 'publish', 'auto-draft' ),
'title' => $slug,
'meta_key' => 'theme',
'meta_value' => $theme,
'tax_query' => array(
array(
'taxonomy' => 'wp_theme',
'field' => 'slug',
'terms' => $theme,
),
),
'posts_per_page' => 1,
'no_found_rows' => true,
)
Expand All @@ -42,6 +47,7 @@ function _gutenberg_create_auto_draft_for_template( $post_type, $slug, $theme, $
'post_status' => 'auto-draft',
'post_type' => $post_type,
'post_name' => $slug,
'tax_input' => array( 'wp_theme' => array( $theme, '_wp_file_based' ) ),
)
);
} elseif ( 'auto-draft' === $post->post_status && $content !== $post->post_content ) {
Expand Down
92 changes: 73 additions & 19 deletions lib/templates.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,39 +75,55 @@ function gutenberg_register_template_post_type() {
),
);

$meta_args = array(
'object_subtype' => 'wp_template',
'type' => 'string',
'description' => 'The theme that provided the template, if any.',
'single' => true,
'show_in_rest' => true,
);

register_post_type( 'wp_template', $args );
register_meta( 'post', 'theme', $meta_args );
}
add_action( 'init', 'gutenberg_register_template_post_type' );

/**
* Registers block editor 'wp_theme' taxonomy.
*/
function gutenberg_register_wp_theme_taxonomy() {
if ( ! gutenberg_is_fse_theme() ) {
return;
}

register_taxonomy(
'wp_theme',
array( 'wp_template', 'wp_template_part' ),
Copy link
Contributor

Choose a reason for hiding this comment

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

I find the fact that we are registering in wp_template a taxonomy for both wp_template and wp_template_part slightly confusing.
I don't have a better solution though, unless we created a new file to contain FSE-related taxonomies, and load it after both templates and template parts have been registered.

I don't think it's a blocker either way, just something we might need to remember while working on this stuff. 🤔

array(
'public' => false,
'hierarchical' => false,
'labels' => array(
'name' => __( 'Themes', 'gutenberg' ),
'singular_name' => __( 'Theme', 'gutenberg' ),
),
'query_var' => false,
'rewrite' => false,
'show_ui' => false,
'_builtin' => true,
'show_in_nav_menus' => false,
'show_in_rest' => true,
)
);
}
add_action( 'init', 'gutenberg_register_wp_theme_taxonomy' );

/**
* Automatically set the theme meta for templates.
*
* @param array $post_id Template ID.
* @param array $post Template Post.
* @param bool $update Is update.
*/
function gutenberg_set_template_post_theme( $post_id, $post, $update ) {
if ( 'wp_template' !== $post->post_type || $update || 'trash' === $post->post_status ) {
return;
}

$theme = get_post_meta( $post_id, 'theme', true );

if ( ! $theme ) {
update_post_meta( $post_id, 'theme', wp_get_theme()->get_stylesheet() );
function gutenberg_set_template_and_template_part_post_theme( $post_id, $post, $update ) {
$themes = wp_get_post_terms( $post_id, 'wp_theme' );
if ( ! $themes ) {
wp_set_post_terms( $post_id, array( wp_get_theme()->get_stylesheet() ), 'wp_theme', true );
}
}

add_action( 'save_post', 'gutenberg_set_template_post_theme', 10, 3 );
add_action( 'save_post_wp_template', 'gutenberg_set_template_and_template_part_post_theme', 10, 3 );
add_action( 'save_post_wp_template_part', 'gutenberg_set_template_and_template_part_post_theme', 10, 3 );

/**
* Filters the capabilities of a user to conditionally grant them capabilities for managing 'wp_template' posts.
Expand Down Expand Up @@ -322,3 +338,41 @@ function filter_rest_wp_template_query( $args, $request ) {
}
add_filter( 'rest_wp_template_query', 'filter_rest_wp_template_query', 99, 2 );

/**
* Filters the post data for a response.
*
* @param WP_REST_Response $response The response object.
* @return WP_REST_Response
*/
function filter_rest_prepare_add_wp_theme_slug_and_file_based( $response ) {
if ( isset( $response->data ) && is_array( $response->data ) && isset( $response->data['id'] ) ) {
$response->data['wp_theme_slug'] = false;

// Get the wp_theme terms.
$wp_themes = wp_get_post_terms( $response->data['id'], 'wp_theme' );

// If a theme is assigned, add it to the REST response.
if ( $wp_themes && is_array( $wp_themes ) ) {
$wp_theme_slugs = array_column( $wp_themes, 'slug' );

$file_based = in_array( '_wp_file_based', $wp_theme_slugs, true );
$response->data['file_based'] = $file_based;

$theme_slug = array_values(
array_filter(
$wp_theme_slugs,
function( $slug ) {
return '_wp_file_based' !== $slug;
}
)
);
if ( $theme_slug ) {
$response->data['wp_theme_slug'] = $theme_slug[0];
}
}
}

return $response;
}
add_filter( 'rest_prepare_wp_template', 'filter_rest_prepare_add_wp_theme_slug_and_file_based' );
add_filter( 'rest_prepare_wp_template_part', 'filter_rest_prepare_add_wp_theme_slug_and_file_based' );
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@ export default function TemplatePartPlaceholder( {
title,
status: 'publish',
slug,
meta: { theme: '' },
content: serialize( innerBlocks ),
}
);
setAttributes( {
postId: templatePart.id,
slug: templatePart.slug,
theme: templatePart.meta.theme,
theme: templatePart.wp_theme_slug,
} );
}, [ setAttributes ] );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,7 @@ function TemplatePartItem( {
onClose,
composite,
} ) {
const {
id,
slug,
meta: { theme },
} = templatePart;
const { id, slug, wp_theme_slug: theme } = templatePart;
// The 'raw' property is not defined for a brief period in the save cycle.
// The fallback prevents an error in the parse function while saving.
const content = templatePart.content.raw || '';
Expand Down Expand Up @@ -103,15 +99,15 @@ function TemplatePartsByTheme( {
composite,
} ) {
const templatePartsByTheme = useMemo( () => {
return Object.values( groupBy( templateParts, 'meta.theme' ) );
return Object.values( groupBy( templateParts, 'wp_theme_slug' ) );
}, [ templateParts ] );
const currentShownTPs = useAsyncList( templateParts );

return templatePartsByTheme.map( ( templatePartList ) => (
<PanelGroup
key={ templatePartList[ 0 ].meta.theme }
key={ templatePartList[ 0 ].wp_theme_slug }
// Falsy theme implies custom template part.
title={ templatePartList[ 0 ].meta.theme || __( 'Custom' ) }
title={ templatePartList[ 0 ].wp_theme_slug || __( 'Custom' ) }
>
{ templatePartList.map( ( templatePart ) => {
return currentShownTPs.includes( templatePart ) ? (
Expand Down Expand Up @@ -142,7 +138,7 @@ function TemplatePartSearchResults( {
// Remove diacritics and convert to lowercase to normalize.
const normalizedFilterValue = deburr( filterValue ).toLowerCase();
const searchResults = templateParts.filter(
( { slug, meta: { theme } } ) =>
( { slug, wp_theme_slug: theme } ) =>
slug.toLowerCase().includes( normalizedFilterValue ) ||
// Since diacritics can be used in theme names, remove them for the comparison.
deburr( theme ).toLowerCase().includes( normalizedFilterValue )
Expand All @@ -166,10 +162,10 @@ function TemplatePartSearchResults( {
// Second prioritize index found in theme.
// Since diacritics can be used in theme names, remove them for the comparison.
return (
deburr( a.meta.theme )
deburr( a.wp_theme_slug )
.toLowerCase()
.indexOf( normalizedFilterValue ) -
deburr( b.meta.theme )
deburr( b.wp_theme_slug )
.toLowerCase()
.indexOf( normalizedFilterValue )
);
Expand All @@ -182,7 +178,7 @@ function TemplatePartSearchResults( {
return filteredTPs.map( ( templatePart ) => (
<PanelGroup
key={ templatePart.id }
title={ templatePart.meta.theme || __( 'Custom' ) }
title={ templatePart.wp_theme_slug || __( 'Custom' ) }
>
{ currentShownTPs.includes( templatePart ) ? (
<TemplatePartItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,12 @@ export default function useTemplatePartPost( postId, slug, theme ) {
theme,
}
);
const foundPosts = posts?.filter(
( post ) =>
post.slug === cleanedSlug &&
post.meta &&
post.meta.theme === theme
);

// A published post might already exist if this template part was customized elsewhere
// or if it's part of a customized template.
const foundPost =
foundPosts?.find( ( post ) => post.status === 'publish' ) ||
foundPosts?.find(
( post ) => post.status === 'auto-draft'
);
posts?.find( ( post ) => post.status === 'publish' ) ||
posts?.find( ( post ) => post.status === 'auto-draft' );
return foundPost?.id;
}
},
Expand Down
9 changes: 7 additions & 2 deletions packages/block-library/src/template-part/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@ function render_block_core_template_part( $attributes ) {
'post_type' => 'wp_template_part',
'post_status' => 'publish',
'name' => $attributes['slug'],
'meta_key' => 'theme',
'meta_value' => $attributes['theme'],
'tax_query' => array(
array(
'taxonomy' => 'wp_theme',
'field' => 'slug',
'terms' => $attributes['theme'],
),
),
'posts_per_page' => 1,
'no_found_rows' => true,
)
Expand Down
1 change: 1 addition & 0 deletions packages/e2e-test-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ Navigates to the post listing screen and bulk-trashes any posts which exist.
_Parameters_

- _postType_ `string`: String slug for type of post to trash.
- _postStatus_ `string`: String status of posts to trash.

_Returns_

Expand Down
4 changes: 3 additions & 1 deletion packages/e2e-test-utils/src/posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ import { visitAdminPage } from './visit-admin-page';
* Navigates to the post listing screen and bulk-trashes any posts which exist.
*
* @param {string} postType - String slug for type of post to trash.
* @param {string} postStatus - String status of posts to trash.
*
* @return {Promise} Promise resolving once posts have been trashed.
*/
export async function trashAllPosts( postType = 'post' ) {
export async function trashAllPosts( postType = 'post', postStatus ) {
await switchUserToAdmin();
// Visit `/wp-admin/edit.php` so we can see a list of posts and delete them.
const query = addQueryArgs( '', {
post_type: postType,
post_status: postStatus,
} ).slice( 1 );
await visitAdminPage( 'edit.php', query );

Expand Down
Loading