Skip to content

Commit bc16c8d

Browse files
authored
[Block Library - Query Loop]: Add allowedControls in block variations for better extensibility (#43632)
* allowedControls in Query Loop variations * allow empty array as value of allowedControls * remove test variation * move to utils * allow to hide the 'inherit' control * fix typo
1 parent e5dca9d commit bc16c8d

File tree

4 files changed

+191
-115
lines changed

4 files changed

+191
-115
lines changed

docs/reference-guides/core-blocks.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ An advanced block that allows displaying post types based on different query par
609609
- **Name:** core/query
610610
- **Category:** theme
611611
- **Supports:** align (full, wide), color (background, gradients, link, text), ~~html~~
612-
- **Attributes:** displayLayout, query, queryId, tagName
612+
- **Attributes:** displayLayout, namespace, query, queryId, tagName
613613

614614
## No results
615615

packages/block-library/src/query/block.json

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
"default": {
3838
"type": "list"
3939
}
40+
},
41+
"namespace": {
42+
"type": "string"
4043
}
4144
},
4245
"providesContext": {

packages/block-library/src/query/edit/inspector-controls/index.js

+139-113
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ import {
1919
import { __ } from '@wordpress/i18n';
2020
import { InspectorControls } from '@wordpress/block-editor';
2121
import { useEffect, useState, useCallback } from '@wordpress/element';
22-
import { useSelect } from '@wordpress/data';
23-
import { store as coreStore } from '@wordpress/core-data';
2422

2523
/**
2624
* Internal dependencies
@@ -30,23 +28,19 @@ import AuthorControl from './author-control';
3028
import ParentControl from './parent-control';
3129
import { TaxonomyControls, useTaxonomiesInfo } from './taxonomy-controls';
3230
import StickyControl from './sticky-control';
33-
import { usePostTypes } from '../../utils';
34-
35-
function useIsPostTypeHierarchical( postType ) {
36-
return useSelect(
37-
( select ) => {
38-
const type = select( coreStore ).getPostType( postType );
39-
return type?.viewable && type?.hierarchical;
40-
},
41-
[ postType ]
42-
);
43-
}
31+
import {
32+
usePostTypes,
33+
useIsPostTypeHierarchical,
34+
useAllowedControls,
35+
isControlAllowed,
36+
} from '../../utils';
4437

4538
export default function QueryInspectorControls( {
46-
attributes: { query, displayLayout },
39+
attributes,
4740
setQuery,
4841
setDisplayLayout,
4942
} ) {
43+
const { query, displayLayout } = attributes;
5044
const {
5145
order,
5246
orderBy,
@@ -57,6 +51,7 @@ export default function QueryInspectorControls( {
5751
taxQuery,
5852
parents,
5953
} = query;
54+
const allowedControls = useAllowedControls( attributes );
6055
const [ showSticky, setShowSticky ] = useState( postType === 'post' );
6156
const { postTypesTaxonomiesMap, postTypesSelectOptions } = usePostTypes();
6257
const taxonomiesInfo = useTaxonomiesInfo( postType );
@@ -102,70 +97,90 @@ export default function QueryInspectorControls( {
10297
onChangeDebounced();
10398
return onChangeDebounced.cancel;
10499
}, [ querySearch, onChangeDebounced ] );
100+
const showInheritControl = isControlAllowed( allowedControls, 'inherit' );
101+
const showPostTypeControl =
102+
! inherit && isControlAllowed( allowedControls, 'postType' );
103+
const showColumnsControl = displayLayout?.type === 'flex';
104+
const showOrderControl =
105+
! inherit && isControlAllowed( allowedControls, 'order' );
106+
const showStickyControl =
107+
! inherit &&
108+
showSticky &&
109+
isControlAllowed( allowedControls, 'sticky' );
110+
const showSettingsPanel =
111+
showInheritControl ||
112+
showPostTypeControl ||
113+
showColumnsControl ||
114+
showOrderControl ||
115+
showStickyControl;
105116
return (
106117
<>
107-
<InspectorControls>
108-
<PanelBody title={ __( 'Settings' ) }>
109-
<ToggleControl
110-
label={ __( 'Inherit query from template' ) }
111-
help={ __(
112-
'Toggle to use the global query context that is set with the current template, such as an archive or search. Disable to customize the settings independently.'
118+
{ showSettingsPanel && (
119+
<InspectorControls>
120+
<PanelBody title={ __( 'Settings' ) }>
121+
{ showInheritControl && (
122+
<ToggleControl
123+
label={ __( 'Inherit query from template' ) }
124+
help={ __(
125+
'Toggle to use the global query context that is set with the current template, such as an archive or search. Disable to customize the settings independently.'
126+
) }
127+
checked={ !! inherit }
128+
onChange={ ( value ) =>
129+
setQuery( { inherit: !! value } )
130+
}
131+
/>
113132
) }
114-
checked={ !! inherit }
115-
onChange={ ( value ) =>
116-
setQuery( { inherit: !! value } )
117-
}
118-
/>
119-
{ ! inherit && (
120-
<SelectControl
121-
options={ postTypesSelectOptions }
122-
value={ postType }
123-
label={ __( 'Post type' ) }
124-
onChange={ onPostTypeChange }
125-
help={ __(
126-
'WordPress contains different types of content and they are divided into collections called "Post types". By default there are a few different ones such as blog posts and pages, but plugins could add more.'
127-
) }
128-
/>
129-
) }
130-
{ displayLayout?.type === 'flex' && (
131-
<>
132-
<RangeControl
133-
label={ __( 'Columns' ) }
134-
value={ displayLayout.columns }
133+
{ showPostTypeControl && (
134+
<SelectControl
135+
options={ postTypesSelectOptions }
136+
value={ postType }
137+
label={ __( 'Post type' ) }
138+
onChange={ onPostTypeChange }
139+
help={ __(
140+
'WordPress contains different types of content and they are divided into collections called "Post types". By default there are a few different ones such as blog posts and pages, but plugins could add more.'
141+
) }
142+
/>
143+
) }
144+
{ showColumnsControl && (
145+
<>
146+
<RangeControl
147+
label={ __( 'Columns' ) }
148+
value={ displayLayout.columns }
149+
onChange={ ( value ) =>
150+
setDisplayLayout( { columns: value } )
151+
}
152+
min={ 2 }
153+
max={ Math.max( 6, displayLayout.columns ) }
154+
/>
155+
{ displayLayout.columns > 6 && (
156+
<Notice
157+
status="warning"
158+
isDismissible={ false }
159+
>
160+
{ __(
161+
'This column count exceeds the recommended amount and may cause visual breakage.'
162+
) }
163+
</Notice>
164+
) }
165+
</>
166+
) }
167+
{ showOrderControl && (
168+
<OrderControl
169+
{ ...{ order, orderBy } }
170+
onChange={ setQuery }
171+
/>
172+
) }
173+
{ showStickyControl && (
174+
<StickyControl
175+
value={ sticky }
135176
onChange={ ( value ) =>
136-
setDisplayLayout( { columns: value } )
177+
setQuery( { sticky: value } )
137178
}
138-
min={ 2 }
139-
max={ Math.max( 6, displayLayout.columns ) }
140179
/>
141-
{ displayLayout.columns > 6 && (
142-
<Notice
143-
status="warning"
144-
isDismissible={ false }
145-
>
146-
{ __(
147-
'This column count exceeds the recommended amount and may cause visual breakage.'
148-
) }
149-
</Notice>
150-
) }
151-
</>
152-
) }
153-
{ ! inherit && (
154-
<OrderControl
155-
{ ...{ order, orderBy } }
156-
onChange={ setQuery }
157-
/>
158-
) }
159-
{ ! inherit && showSticky && (
160-
<StickyControl
161-
value={ sticky }
162-
onChange={ ( value ) =>
163-
setQuery( { sticky: value } )
164-
}
165-
/>
166-
) }
167-
</PanelBody>
168-
</InspectorControls>
180+
) }
181+
</PanelBody>
182+
</InspectorControls>
183+
) }
169184
{ ! inherit && (
170185
<InspectorControls>
171186
<ToolsPanel
@@ -181,58 +196,69 @@ export default function QueryInspectorControls( {
181196
setQuerySearch( '' );
182197
} }
183198
>
184-
{ !! taxonomiesInfo?.length && (
199+
{ !! taxonomiesInfo?.length &&
200+
isControlAllowed( allowedControls, 'taxQuery' ) && (
201+
<ToolsPanelItem
202+
label={ __( 'Taxonomies' ) }
203+
hasValue={ () =>
204+
Object.values( taxQuery || {} ).some(
205+
( terms ) => !! terms.length
206+
)
207+
}
208+
onDeselect={ () =>
209+
setQuery( { taxQuery: null } )
210+
}
211+
>
212+
<TaxonomyControls
213+
onChange={ setQuery }
214+
query={ query }
215+
/>
216+
</ToolsPanelItem>
217+
) }
218+
{ isControlAllowed( allowedControls, 'author' ) && (
185219
<ToolsPanelItem
186-
label={ __( 'Taxonomies' ) }
187-
hasValue={ () =>
188-
Object.values( taxQuery || {} ).some(
189-
( terms ) => !! terms.length
190-
)
191-
}
192-
onDeselect={ () =>
193-
setQuery( { taxQuery: null } )
194-
}
220+
hasValue={ () => !! authorIds }
221+
label={ __( 'Authors' ) }
222+
onDeselect={ () => setQuery( { author: '' } ) }
195223
>
196-
<TaxonomyControls
224+
<AuthorControl
225+
value={ authorIds }
197226
onChange={ setQuery }
198-
query={ query }
199227
/>
200228
</ToolsPanelItem>
201229
) }
202-
<ToolsPanelItem
203-
hasValue={ () => !! authorIds }
204-
label={ __( 'Authors' ) }
205-
onDeselect={ () => setQuery( { author: '' } ) }
206-
>
207-
<AuthorControl
208-
value={ authorIds }
209-
onChange={ setQuery }
210-
/>
211-
</ToolsPanelItem>
212-
<ToolsPanelItem
213-
hasValue={ () => !! querySearch }
214-
label={ __( 'Keyword' ) }
215-
onDeselect={ () => setQuerySearch( '' ) }
216-
>
217-
<TextControl
218-
label={ __( 'Keyword' ) }
219-
value={ querySearch }
220-
onChange={ setQuerySearch }
221-
/>
222-
</ToolsPanelItem>
223-
{ isPostTypeHierarchical && (
230+
{ isControlAllowed( allowedControls, 'search' ) && (
224231
<ToolsPanelItem
225-
hasValue={ () => !! parents?.length }
226-
label={ __( 'Parents' ) }
227-
onDeselect={ () => setQuery( { parents: [] } ) }
232+
hasValue={ () => !! querySearch }
233+
label={ __( 'Keyword' ) }
234+
onDeselect={ () => setQuerySearch( '' ) }
228235
>
229-
<ParentControl
230-
parents={ parents }
231-
postType={ postType }
232-
onChange={ setQuery }
236+
<TextControl
237+
label={ __( 'Keyword' ) }
238+
value={ querySearch }
239+
onChange={ setQuerySearch }
233240
/>
234241
</ToolsPanelItem>
235242
) }
243+
{ isPostTypeHierarchical &&
244+
! isControlAllowed(
245+
allowedControls,
246+
'parents'
247+
) && (
248+
<ToolsPanelItem
249+
hasValue={ () => !! parents?.length }
250+
label={ __( 'Parents' ) }
251+
onDeselect={ () =>
252+
setQuery( { parents: [] } )
253+
}
254+
>
255+
<ParentControl
256+
parents={ parents }
257+
postType={ postType }
258+
onChange={ setQuery }
259+
/>
260+
</ToolsPanelItem>
261+
) }
236262
</ToolsPanel>
237263
</InspectorControls>
238264
) }

packages/block-library/src/query/utils.js

+48-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ import { useSelect } from '@wordpress/data';
1010
import { useMemo } from '@wordpress/element';
1111
import { store as coreStore } from '@wordpress/core-data';
1212
import { decodeEntities } from '@wordpress/html-entities';
13-
import { cloneBlock } from '@wordpress/blocks';
13+
import { cloneBlock, store as blocksStore } from '@wordpress/blocks';
14+
15+
/**
16+
* Internal dependencies
17+
*/
18+
import { name as queryLoopName } from './block.json';
1419

1520
/**
1621
* @typedef IHasNameAndId
@@ -127,6 +132,48 @@ export const useTaxonomies = ( postType ) => {
127132
return taxonomies;
128133
};
129134

135+
/**
136+
* Hook that returns whether a specific post type is hierarchical.
137+
*
138+
* @param {string} postType The post type to check.
139+
* @return {boolean} Whether a specific post type is hierarchical.
140+
*/
141+
export function useIsPostTypeHierarchical( postType ) {
142+
return useSelect(
143+
( select ) => {
144+
const type = select( coreStore ).getPostType( postType );
145+
return type?.viewable && type?.hierarchical;
146+
},
147+
[ postType ]
148+
);
149+
}
150+
151+
/**
152+
* Hook that returns the query properties' names defined by the active
153+
* block variation, to determine which block's filters to show.
154+
*
155+
* @param {Object} attributes Block attributes.
156+
* @return {string[]} An array of the query attributes.
157+
*/
158+
export function useAllowedControls( attributes ) {
159+
return useSelect(
160+
( select ) =>
161+
select( blocksStore ).getActiveBlockVariation(
162+
queryLoopName,
163+
attributes
164+
)?.allowControls,
165+
166+
[ attributes ]
167+
);
168+
}
169+
export function isControlAllowed( allowedControls, key ) {
170+
// Every controls is allowed if the list is not defined.
171+
if ( ! allowedControls ) {
172+
return true;
173+
}
174+
return allowedControls.includes( key );
175+
}
176+
130177
/**
131178
* Clones a pattern's blocks and then recurses over that list of blocks,
132179
* transforming them to retain some `query` attribute properties.

0 commit comments

Comments
 (0)