Skip to content
Merged
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
1 change: 1 addition & 0 deletions backport-changelog/7.1/11272.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ https://github.com/WordPress/wordpress-develop/pull/11272
* https://github.com/WordPress/gutenberg/pull/76573
* https://github.com/WordPress/gutenberg/pull/76734
* https://github.com/WordPress/gutenberg/pull/76622
* https://github.com/WordPress/gutenberg/pull/76823
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,11 @@ public function get_items( $request ) {
} elseif ( 'postType' === $kind && 'wp_block' === $name ) {
$default_layouts = $this->get_default_layouts_for_wp_block();
$default_view = $this->get_default_view_for_wp_block( $default_layouts );
$view_list = $this->get_view_list_for_wp_block();
} elseif ( 'postType' === $kind && 'wp_template_part' === $name ) {
$default_layouts = $this->get_default_layouts_for_wp_template_part();
$default_view = $this->get_default_view_for_wp_template_part( $default_layouts );
$view_list = $this->get_view_list_for_wp_template_part();
} elseif ( 'postType' === $kind && 'wp_template' === $name ) {
$default_view = $this->get_default_view_for_wp_template();
$default_layouts = $this->get_default_layouts_for_wp_template();
Expand Down Expand Up @@ -789,6 +791,116 @@ private static function get_wp_templates_author_text_field( $template_object ) {
return '';
}

/**
* Returns the view list for the wp_template_part post type.
*
* Builds entries from the registered template part areas (header, footer, etc.).
*
* @return array View list entries.
*/
private function get_view_list_for_wp_template_part() {
$view_list = array(
array(
'title' => __( 'All template parts', 'gutenberg' ),
'slug' => 'all-parts',
),
);

$areas = get_allowed_block_template_part_areas();

// Ensure default areas appear in a consistent order.
$preferred_order = array( 'header', 'footer', 'sidebar', 'navigation-overlay', 'uncategorized' );
$ordered_areas = array();
$remaining_areas = array();
foreach ( $areas as $area ) {
$position = array_search( $area['area'], $preferred_order, true );
if ( false !== $position ) {
$ordered_areas[ $position ] = $area;
} else {
$remaining_areas[] = $area;
}
}
ksort( $ordered_areas );
$areas = array_merge( array_values( $ordered_areas ), $remaining_areas );
Comment thread
oandregal marked this conversation as resolved.

foreach ( $areas as $area ) {
$view_list[] = array(
'title' => $area['label'],
'slug' => $area['area'],
'view' => array(
'filters' => array(
array(
'field' => 'area',
'operator' => 'is',
'value' => $area['area'],
'isLocked' => true,
),
),
),
);
}

return $view_list;
}

/**
* Returns the view list for the wp_block (patterns) post type.
*
* Builds entries from registered block pattern categories and user pattern categories.
*
* @return array View list entries.
*/
private function get_view_list_for_wp_block() {
$view_list = array(
array(
'title' => __( 'All patterns', 'gutenberg' ),
'slug' => 'all-patterns',
),
array(
'title' => __( 'My patterns', 'gutenberg' ),
'slug' => 'my-patterns',
),
);

// Gather categories from the block pattern categories registry.
$registry = WP_Block_Pattern_Categories_Registry::get_instance();
$categories = array();

foreach ( $registry->get_all_registered() as $category ) {
$categories[ $category['name'] ] = $category['label'];
}

// Ensure "Uncategorized" is always included for patterns
// that have no category assigned.
$categories['uncategorized'] ??= __( 'Uncategorized', 'gutenberg' );

// Also gather user-created pattern categories (wp_pattern_category taxonomy).
$user_terms = get_terms(
array(
'taxonomy' => 'wp_pattern_category',
'hide_empty' => false,
)
);

if ( ! is_wp_error( $user_terms ) ) {
foreach ( $user_terms as $term ) {
$categories[ $term->slug ] = $term->name;
}
}

// Sort categories alphabetically by label.
asort( $categories, SORT_NATURAL | SORT_FLAG_CASE );

foreach ( $categories as $name => $label ) {
$view_list[] = array(
'title' => $label,
'slug' => $name,
);
}

return $view_list;
}

private function get_default_view_for_wp_template() {
return array(
'type' => 'grid',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
__experimentalItem as Item,
} from '@wordpress/components';
import { getTemplatePartIcon } from '@wordpress/editor';
import { useMemo } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { file } from '@wordpress/icons';
import { privateApis as routerPrivateApis } from '@wordpress/router';
import { useViewConfig } from '@wordpress/views';

/**
* Internal dependencies
Expand All @@ -28,70 +30,44 @@ import { unlock } from '../../lock-unlock';
const { useLocation } = unlock( routerPrivateApis );

function CategoriesGroup( {
templatePartAreas,
patternCategories,
templatePartViews,
patternViews,
templatePartCounts,
patternCounts,
currentCategory,
currentType,
} ) {
const [ allPatterns, ...otherPatterns ] = patternCategories;

return (
<ItemGroup className="edit-site-sidebar-navigation-screen-patterns__group">
<CategoryItem
key="all"
count={ Object.values( templatePartAreas )
.map( ( { templateParts } ) => templateParts?.length || 0 )
.reduce( ( acc, val ) => acc + val, 0 ) }
icon={ getTemplatePartIcon() } /* no name, so it provides the fallback icon */
label={ __( 'All template parts' ) }
id={ TEMPLATE_PART_ALL_AREAS_CATEGORY }
type={ TEMPLATE_PART_POST_TYPE }
isActive={
currentCategory === TEMPLATE_PART_ALL_AREAS_CATEGORY &&
currentType === TEMPLATE_PART_POST_TYPE
}
/>
{ Object.entries( templatePartAreas ).map(
( [ area, { label, templateParts, icon } ] ) => (
<CategoryItem
key={ area }
count={ templateParts?.length }
icon={ getTemplatePartIcon( icon ) }
label={ label }
id={ area }
type={ TEMPLATE_PART_POST_TYPE }
isActive={
currentCategory === area &&
currentType === TEMPLATE_PART_POST_TYPE
}
/>
)
) }
<div className="edit-site-sidebar-navigation-screen-patterns__divider" />
{ allPatterns && (
{ templatePartViews?.map( ( view ) => (
<CategoryItem
key={ allPatterns.name }
count={ allPatterns.count }
label={ allPatterns.label }
icon={ file }
id={ allPatterns.name }
type={ PATTERN_TYPES.user }
key={ view.slug }
count={ templatePartCounts[ view.slug ] }
icon={ getTemplatePartIcon(
view.slug === TEMPLATE_PART_ALL_AREAS_CATEGORY
? undefined
: view.slug
) }
label={ view.title }
id={ view.slug }
type={ TEMPLATE_PART_POST_TYPE }
isActive={
currentCategory === `${ allPatterns.name }` &&
currentType === PATTERN_TYPES.user
currentCategory === view.slug &&
currentType === TEMPLATE_PART_POST_TYPE
}
/>
) }
{ otherPatterns.map( ( category ) => (
) ) }
<div className="edit-site-sidebar-navigation-screen-patterns__divider" />
{ patternViews?.map( ( view ) => (
<CategoryItem
key={ category.name }
count={ category.count }
label={ category.label }
key={ view.slug }
count={ patternCounts[ view.slug ] }
label={ view.title }
icon={ file }
id={ category.name }
id={ view.slug }
type={ PATTERN_TYPES.user }
isActive={
currentCategory === `${ category.name }` &&
currentCategory === `${ view.slug }` &&
currentType === PATTERN_TYPES.user
}
/>
Expand All @@ -110,9 +86,38 @@ export default function SidebarNavigationScreenPatterns( { backPath } ) {
? PATTERN_DEFAULT_CATEGORY
: TEMPLATE_PART_ALL_AREAS_CATEGORY );

const { templatePartAreas, hasTemplateParts, isLoading } =
const { view_list: templatePartViews } = useViewConfig( {
kind: 'postType',
name: TEMPLATE_PART_POST_TYPE,
} );
const { view_list: patternViews } = useViewConfig( {
kind: 'postType',
name: PATTERN_TYPES.user,
} );

const { templatePartAreas, isLoading, hasTemplateParts } =
useTemplatePartAreas();
const { patternCategories, hasPatterns } = usePatternCategories();
const templatePartCounts = useMemo( () => {
const counts = { [ TEMPLATE_PART_ALL_AREAS_CATEGORY ]: 0 };
Object.entries( templatePartAreas ).forEach(
( [ area, { templateParts } ] ) => {
const count = templateParts?.length || 0;
counts[ area ] = count;
counts[ TEMPLATE_PART_ALL_AREAS_CATEGORY ] += count;
}
);
return counts;
}, [ templatePartAreas ] );
const { patternCategories } = usePatternCategories();
const patternCounts = useMemo( () => {
const counts = {};
patternCategories.forEach( ( cat ) => {
counts[ cat.name ] = cat.count;
} );
return counts;
}, [ patternCategories ] );

const hasPatterns = patternCounts[ PATTERN_DEFAULT_CATEGORY ] > 0;

return (
<SidebarNavigationScreen
Expand All @@ -133,8 +138,10 @@ export default function SidebarNavigationScreenPatterns( { backPath } ) {
</ItemGroup>
) }
<CategoriesGroup
templatePartAreas={ templatePartAreas }
patternCategories={ patternCategories }
templatePartViews={ templatePartViews }
patternViews={ patternViews }
templatePartCounts={ templatePartCounts }
patternCounts={ patternCounts }
Comment on lines +143 to +144

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Computing the counts per category client-side is a design decision, the same as retrieving the icons client-side. The rationale for this is that the experimental site editor doesn't have any, so I'm not convinced counts/icon need to be part of the endpoint. If that changes, we can add them later — which is easier than removing them once they've part of the endpoint.

currentCategory={ currentCategory }
currentType={ postType }
/>
Expand Down
Loading