Skip to content

Commit d0c1b9e

Browse files
oandregalntsekouras
authored andcommitted
Site Editor > Patterns & Parts: generate sidebar from view config (#76823)
Co-authored-by: oandregal <oandregal@git.wordpress.org> Co-authored-by: ntsekouras <ntsekouras@git.wordpress.org>
1 parent 372f7c3 commit d0c1b9e

3 files changed

Lines changed: 175 additions & 55 deletions

File tree

‎backport-changelog/7.1/11272.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ https://github.com/WordPress/wordpress-develop/pull/11272
33
* https://github.com/WordPress/gutenberg/pull/76573
44
* https://github.com/WordPress/gutenberg/pull/76734
55
* https://github.com/WordPress/gutenberg/pull/76622
6+
* https://github.com/WordPress/gutenberg/pull/76823

‎lib/compat/wordpress-7.1/class-gutenberg-rest-view-config-controller-7-1.php‎

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,11 @@ public function get_items( $request ) {
119119
} elseif ( 'postType' === $kind && 'wp_block' === $name ) {
120120
$default_layouts = $this->get_default_layouts_for_wp_block();
121121
$default_view = $this->get_default_view_for_wp_block( $default_layouts );
122+
$view_list = $this->get_view_list_for_wp_block();
122123
} elseif ( 'postType' === $kind && 'wp_template_part' === $name ) {
123124
$default_layouts = $this->get_default_layouts_for_wp_template_part();
124125
$default_view = $this->get_default_view_for_wp_template_part( $default_layouts );
126+
$view_list = $this->get_view_list_for_wp_template_part();
125127
} elseif ( 'postType' === $kind && 'wp_template' === $name ) {
126128
$default_view = $this->get_default_view_for_wp_template();
127129
$default_layouts = $this->get_default_layouts_for_wp_template();
@@ -789,6 +791,116 @@ private static function get_wp_templates_author_text_field( $template_object ) {
789791
return '';
790792
}
791793

794+
/**
795+
* Returns the view list for the wp_template_part post type.
796+
*
797+
* Builds entries from the registered template part areas (header, footer, etc.).
798+
*
799+
* @return array View list entries.
800+
*/
801+
private function get_view_list_for_wp_template_part() {
802+
$view_list = array(
803+
array(
804+
'title' => __( 'All template parts', 'gutenberg' ),
805+
'slug' => 'all-parts',
806+
),
807+
);
808+
809+
$areas = get_allowed_block_template_part_areas();
810+
811+
// Ensure default areas appear in a consistent order.
812+
$preferred_order = array( 'header', 'footer', 'sidebar', 'navigation-overlay', 'uncategorized' );
813+
$ordered_areas = array();
814+
$remaining_areas = array();
815+
foreach ( $areas as $area ) {
816+
$position = array_search( $area['area'], $preferred_order, true );
817+
if ( false !== $position ) {
818+
$ordered_areas[ $position ] = $area;
819+
} else {
820+
$remaining_areas[] = $area;
821+
}
822+
}
823+
ksort( $ordered_areas );
824+
$areas = array_merge( array_values( $ordered_areas ), $remaining_areas );
825+
826+
foreach ( $areas as $area ) {
827+
$view_list[] = array(
828+
'title' => $area['label'],
829+
'slug' => $area['area'],
830+
'view' => array(
831+
'filters' => array(
832+
array(
833+
'field' => 'area',
834+
'operator' => 'is',
835+
'value' => $area['area'],
836+
'isLocked' => true,
837+
),
838+
),
839+
),
840+
);
841+
}
842+
843+
return $view_list;
844+
}
845+
846+
/**
847+
* Returns the view list for the wp_block (patterns) post type.
848+
*
849+
* Builds entries from registered block pattern categories and user pattern categories.
850+
*
851+
* @return array View list entries.
852+
*/
853+
private function get_view_list_for_wp_block() {
854+
$view_list = array(
855+
array(
856+
'title' => __( 'All patterns', 'gutenberg' ),
857+
'slug' => 'all-patterns',
858+
),
859+
array(
860+
'title' => __( 'My patterns', 'gutenberg' ),
861+
'slug' => 'my-patterns',
862+
),
863+
);
864+
865+
// Gather categories from the block pattern categories registry.
866+
$registry = WP_Block_Pattern_Categories_Registry::get_instance();
867+
$categories = array();
868+
869+
foreach ( $registry->get_all_registered() as $category ) {
870+
$categories[ $category['name'] ] = $category['label'];
871+
}
872+
873+
// Ensure "Uncategorized" is always included for patterns
874+
// that have no category assigned.
875+
$categories['uncategorized'] ??= __( 'Uncategorized', 'gutenberg' );
876+
877+
// Also gather user-created pattern categories (wp_pattern_category taxonomy).
878+
$user_terms = get_terms(
879+
array(
880+
'taxonomy' => 'wp_pattern_category',
881+
'hide_empty' => false,
882+
)
883+
);
884+
885+
if ( ! is_wp_error( $user_terms ) ) {
886+
foreach ( $user_terms as $term ) {
887+
$categories[ $term->slug ] = $term->name;
888+
}
889+
}
890+
891+
// Sort categories alphabetically by label.
892+
asort( $categories, SORT_NATURAL | SORT_FLAG_CASE );
893+
894+
foreach ( $categories as $name => $label ) {
895+
$view_list[] = array(
896+
'title' => $label,
897+
'slug' => $name,
898+
);
899+
}
900+
901+
return $view_list;
902+
}
903+
792904
private function get_default_view_for_wp_template() {
793905
return array(
794906
'type' => 'grid',

‎packages/edit-site/src/components/sidebar-navigation-screen-patterns/index.js‎

Lines changed: 62 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import {
66
__experimentalItem as Item,
77
} from '@wordpress/components';
88
import { getTemplatePartIcon } from '@wordpress/editor';
9+
import { useMemo } from '@wordpress/element';
910
import { __ } from '@wordpress/i18n';
1011
import { file } from '@wordpress/icons';
1112
import { privateApis as routerPrivateApis } from '@wordpress/router';
13+
import { useViewConfig } from '@wordpress/views';
1214

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

3032
function CategoriesGroup( {
31-
templatePartAreas,
32-
patternCategories,
33+
templatePartViews,
34+
patternViews,
35+
templatePartCounts,
36+
patternCounts,
3337
currentCategory,
3438
currentType,
3539
} ) {
36-
const [ allPatterns, ...otherPatterns ] = patternCategories;
37-
3840
return (
3941
<ItemGroup className="edit-site-sidebar-navigation-screen-patterns__group">
40-
<CategoryItem
41-
key="all"
42-
count={ Object.values( templatePartAreas )
43-
.map( ( { templateParts } ) => templateParts?.length || 0 )
44-
.reduce( ( acc, val ) => acc + val, 0 ) }
45-
icon={ getTemplatePartIcon() } /* no name, so it provides the fallback icon */
46-
label={ __( 'All template parts' ) }
47-
id={ TEMPLATE_PART_ALL_AREAS_CATEGORY }
48-
type={ TEMPLATE_PART_POST_TYPE }
49-
isActive={
50-
currentCategory === TEMPLATE_PART_ALL_AREAS_CATEGORY &&
51-
currentType === TEMPLATE_PART_POST_TYPE
52-
}
53-
/>
54-
{ Object.entries( templatePartAreas ).map(
55-
( [ area, { label, templateParts, icon } ] ) => (
56-
<CategoryItem
57-
key={ area }
58-
count={ templateParts?.length }
59-
icon={ getTemplatePartIcon( icon ) }
60-
label={ label }
61-
id={ area }
62-
type={ TEMPLATE_PART_POST_TYPE }
63-
isActive={
64-
currentCategory === area &&
65-
currentType === TEMPLATE_PART_POST_TYPE
66-
}
67-
/>
68-
)
69-
) }
70-
<div className="edit-site-sidebar-navigation-screen-patterns__divider" />
71-
{ allPatterns && (
42+
{ templatePartViews?.map( ( view ) => (
7243
<CategoryItem
73-
key={ allPatterns.name }
74-
count={ allPatterns.count }
75-
label={ allPatterns.label }
76-
icon={ file }
77-
id={ allPatterns.name }
78-
type={ PATTERN_TYPES.user }
44+
key={ view.slug }
45+
count={ templatePartCounts[ view.slug ] }
46+
icon={ getTemplatePartIcon(
47+
view.slug === TEMPLATE_PART_ALL_AREAS_CATEGORY
48+
? undefined
49+
: view.slug
50+
) }
51+
label={ view.title }
52+
id={ view.slug }
53+
type={ TEMPLATE_PART_POST_TYPE }
7954
isActive={
80-
currentCategory === `${ allPatterns.name }` &&
81-
currentType === PATTERN_TYPES.user
55+
currentCategory === view.slug &&
56+
currentType === TEMPLATE_PART_POST_TYPE
8257
}
8358
/>
84-
) }
85-
{ otherPatterns.map( ( category ) => (
59+
) ) }
60+
<div className="edit-site-sidebar-navigation-screen-patterns__divider" />
61+
{ patternViews?.map( ( view ) => (
8662
<CategoryItem
87-
key={ category.name }
88-
count={ category.count }
89-
label={ category.label }
63+
key={ view.slug }
64+
count={ patternCounts[ view.slug ] }
65+
label={ view.title }
9066
icon={ file }
91-
id={ category.name }
67+
id={ view.slug }
9268
type={ PATTERN_TYPES.user }
9369
isActive={
94-
currentCategory === `${ category.name }` &&
70+
currentCategory === `${ view.slug }` &&
9571
currentType === PATTERN_TYPES.user
9672
}
9773
/>
@@ -110,9 +86,38 @@ export default function SidebarNavigationScreenPatterns( { backPath } ) {
11086
? PATTERN_DEFAULT_CATEGORY
11187
: TEMPLATE_PART_ALL_AREAS_CATEGORY );
11288

113-
const { templatePartAreas, hasTemplateParts, isLoading } =
89+
const { view_list: templatePartViews } = useViewConfig( {
90+
kind: 'postType',
91+
name: TEMPLATE_PART_POST_TYPE,
92+
} );
93+
const { view_list: patternViews } = useViewConfig( {
94+
kind: 'postType',
95+
name: PATTERN_TYPES.user,
96+
} );
97+
98+
const { templatePartAreas, isLoading, hasTemplateParts } =
11499
useTemplatePartAreas();
115-
const { patternCategories, hasPatterns } = usePatternCategories();
100+
const templatePartCounts = useMemo( () => {
101+
const counts = { [ TEMPLATE_PART_ALL_AREAS_CATEGORY ]: 0 };
102+
Object.entries( templatePartAreas ).forEach(
103+
( [ area, { templateParts } ] ) => {
104+
const count = templateParts?.length || 0;
105+
counts[ area ] = count;
106+
counts[ TEMPLATE_PART_ALL_AREAS_CATEGORY ] += count;
107+
}
108+
);
109+
return counts;
110+
}, [ templatePartAreas ] );
111+
const { patternCategories } = usePatternCategories();
112+
const patternCounts = useMemo( () => {
113+
const counts = {};
114+
patternCategories.forEach( ( cat ) => {
115+
counts[ cat.name ] = cat.count;
116+
} );
117+
return counts;
118+
}, [ patternCategories ] );
119+
120+
const hasPatterns = patternCounts[ PATTERN_DEFAULT_CATEGORY ] > 0;
116121

117122
return (
118123
<SidebarNavigationScreen
@@ -133,8 +138,10 @@ export default function SidebarNavigationScreenPatterns( { backPath } ) {
133138
</ItemGroup>
134139
) }
135140
<CategoriesGroup
136-
templatePartAreas={ templatePartAreas }
137-
patternCategories={ patternCategories }
141+
templatePartViews={ templatePartViews }
142+
patternViews={ patternViews }
143+
templatePartCounts={ templatePartCounts }
144+
patternCounts={ patternCounts }
138145
currentCategory={ currentCategory }
139146
currentType={ postType }
140147
/>

0 commit comments

Comments
 (0)