Skip to content
This repository has been archived by the owner on Oct 16, 2024. It is now read-only.

[DO NOT MERGE] Use category registration utility file in the patterns dir #124

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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: 18 additions & 0 deletions wp-modules/editor/editor.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,24 @@ function register_pattern_post_type() {
'default' => get_pattern_defaults()['keywords'],
)
);

register_post_meta(
$post_type_key,
'customCategories',
array(
'show_in_rest' => array(
'schema' => array(
'type' => 'array',
'items' => array(
'type' => 'string',
),
),
),
'single' => true,
'type' => 'array',
'default' => [],
)
);
}
add_action( 'init', __NAMESPACE__ . '\register_pattern_post_type' );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export default function PatternManagerMetaControls() {
<CategoriesPanel
categories={ postMeta.categories }
categoryOptions={ queriedCategories }
customCategories={ postMeta.customCategories }
handleChange={ updatePostMeta }
/>
<KeywordsPanel
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { __ } from '@wordpress/i18n';
import { PluginDocumentSettingPanel } from '@wordpress/edit-post';
import { Spinner } from '@wordpress/components';
import Select from 'react-select';
import Creatable from 'react-select/creatable';
import convertToSlug from '../../utils/convertToSlug';

import type { BaseSidebarProps, AdditionalSidebarProps } from './types';

Expand All @@ -12,36 +13,77 @@ import type { BaseSidebarProps, AdditionalSidebarProps } from './types';
export default function CategoriesPanel( {
categories,
categoryOptions,
customCategories,
handleChange,
}: BaseSidebarProps< 'categories' > &
}: BaseSidebarProps< 'categories' | 'customCategories' > &
AdditionalSidebarProps< 'categoryOptions' > ) {
// The list of currently selected categories, formatted for react-select.
const selectedCategories: typeof categoryOptions = categories.reduce(
( acc, categoryName ) =>
! acc.includes( categoryName )
? [
...acc,
categoryOptions.find(
( matchedCategory ) =>
matchedCategory.value === categoryName
),
]
: acc,
[]
);

return (
<PluginDocumentSettingPanel
name="patternmanager-pattern-editor-pattern-categories"
title={ __( 'Pattern Categories', 'pattern-manager' ) }
>
{ categoryOptions ? (
<Select
<Creatable
isMulti
isClearable
closeMenuOnSelect={ false }
aria-label={ __(
'Add Pattern Categories',
'pattern-manager'
) }
value={ categories?.map( ( category ) =>
categoryOptions.find(
( matchedCategory ) =>
matchedCategory.value === category
)
) }
value={ selectedCategories }
options={ categoryOptions }
onChange={ ( categorySelections ) => {
const selections = categorySelections.map(
( category ) => category.value
);

const customCategorySelections = categoryOptions.reduce(
( acc, category ) => {
const customCategoryFound =
selections.includes( category.value ) &&
/^pm_custom_category_/.test(
category.value
);
Comment on lines +60 to +62
Copy link
Contributor Author

@mike-day mike-day Mar 24, 2023

Choose a reason for hiding this comment

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

Parsing to find which registered categories are custom (and from PM) is a bit tricky.

Initially, I tried adding another array item called pm_meta to the registration call, but querying registered categories from either the core data store (or via a PHP call to the category registry) does not always return the custom item.

Prepending the value (registered as name) with a custom string and checking against it has been the only reliable method I've found to fix this issue for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The drawback to this method — if the utility file is deleted for some reason, custom category labels will be ugly.


return customCategoryFound
? [ ...acc, category.label ]
: acc;
},
[]
);

handleChange( 'categories', selections, {
customCategories: customCategorySelections,
} );
} }
onCreateOption={ ( newCategoryTitle ) => {
handleChange(
'categories',
categorySelections.map(
( category ) => category.value
)
'customCategories',
[ ...customCategories, newCategoryTitle ],
{
categories: [
...categories,
`pm_custom_category_${ convertToSlug(
newCategoryTitle
) }`,
],
}
);
} }
menuPlacement="auto"
Expand Down
27 changes: 26 additions & 1 deletion wp-modules/editor/js/src/hooks/usePatternData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import sortAlphabetically from '../utils/sortAlphabetically';
import { useSelect, useDispatch } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import { PostMeta, SelectQuery } from '../types';
import convertToSlug from '../utils/convertToSlug';

export default function usePatternData( postMeta: PostMeta ) {
const { editPost } = useDispatch( 'core/editor' );
Expand Down Expand Up @@ -70,6 +71,30 @@ export default function usePatternData( postMeta: PostMeta ) {
);
}, [] );

/**
* Registered and newly added custom categories, combined.
* Needed for including new categories before the post is saved.
*/
const combinedCategories = [
...postMeta.customCategories.reduce( ( acc, categoryLabel ) => {
const missingCategory = ! categories.some(
( queriedCategory ) => queriedCategory.label === categoryLabel
);

return missingCategory
? [
...acc,
{
label: categoryLabel,
value: `pm_custom_category_${ convertToSlug(
categoryLabel
) }`,
},
]
: acc;
}, categories ),
];

/**
* The alphabetized list of transformable block types, mapped for react-select.
* Template-part types are added to support template part replacement in site editor.
Expand Down Expand Up @@ -195,7 +220,7 @@ export default function usePatternData( postMeta: PostMeta ) {

return {
queriedBlockTypes: blockTypes,
queriedCategories: categories,
queriedCategories: combinedCategories,
queriedPostTypes: postTypes,
updatePostMeta,
updatePostMetaMulti,
Expand Down
7 changes: 6 additions & 1 deletion wp-modules/editor/js/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
export type PostMeta = {
blockTypes: string[];
categories: string[];
customCategories: string[];
description: string;
inserter: boolean;
keywords: string[];
Expand All @@ -16,7 +17,10 @@ export type PatternPostData = PostMeta & {
};

export type SelectQuery = ( dataStore: string ) => {
getBlockPatternCategories: () => { name: string; label: string }[];
getBlockPatternCategories: () => {
name: string;
label: string;
}[];
getBlockTypes: () => { name: string; transforms?: unknown }[];
getCurrentPostAttribute: ( attributeName: 'meta' ) => PostMeta;
getEditedPostAttribute: ( postAttribute: string ) => unknown;
Expand All @@ -34,6 +38,7 @@ export type SelectQuery = ( dataStore: string ) => {
export type Pattern = {
blockTypes: string[];
categories: string[];
customCategories: string[];
content: string;
description: string;
inserter: boolean;
Expand Down
4 changes: 4 additions & 0 deletions wp-modules/editor/model.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use function PatternManager\PatternDataHandlers\delete_pattern;
use function PatternManager\PatternDataHandlers\tree_shake_theme_images;
use function PatternManager\PatternDataHandlers\update_pattern;
use function PatternManager\PatternDataHandlers\create_category_registration_file;

/**
* Gets the pattern content and title from the PHP file.
Expand Down Expand Up @@ -54,6 +55,9 @@ function save_pattern_to_file( WP_Post $post ) {
return;
}

// Add the utility file for custom category registration.
create_category_registration_file();
Comment on lines +58 to +59
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The registration file is written to /patterns/utilities/ each time the pattern is saved to file.

Maybe there is a more efficient way to approach this kind of idea.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I think it's too much to maintain a separate utility file like this.

Also, it invites questions, like "Is it insecure that PM writes PHP to my theme?"

It's not insecure, but this is writing a lot of logic to PHP files.

I think a simple register_block_pattern_category() in a pattern file is fine.

But this is too abstract, in my opinion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah you might be right — this might be getting a bit too abstract unnecessarily.

I like the idea of having a separate utility for this kind of thing, but we are actually writing this to themes, and a theme-maker might view this as being a bit overbearing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Still, it's cool to know this is possible!


$pattern = get_pattern_by_name( $post->post_name );

update_pattern(
Expand Down
Loading