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

Query Loop: Add 'menu_order' as sorting option #68781

Merged
merged 28 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3b58ff3
Add support for menu order
kasparsd Jan 20, 2025
da4bda6
Add the menu order option
kasparsd Jan 20, 2025
4485aaa
Two more copy-paste location
kasparsd Jan 20, 2025
e1df800
Match the order
kasparsd Jan 20, 2025
ab8e64c
Update labels per discussion
kasparsd Jan 21, 2025
415d628
Helper for resolving order by options for a post type
kasparsd Feb 17, 2025
033fbb8
Add the option type
kasparsd Feb 17, 2025
1574bed
Pass in the options
kasparsd Feb 17, 2025
ec4b822
Restrict the values to only known values
kasparsd Feb 17, 2025
328bd7c
Keep the order
kasparsd Feb 17, 2025
bc1d68b
Define the type for just the option
kasparsd Feb 17, 2025
7823620
Document the updated fields
kasparsd Feb 17, 2025
7d9ea7c
Update the examples
kasparsd Feb 17, 2025
4a1c5e6
Reference the type
kasparsd Feb 17, 2025
3fb27ec
This is really required for the drop-down component, keep it simple here
kasparsd Feb 17, 2025
749d3b6
Add back the default options to prevent breaking changes
kasparsd Feb 28, 2025
184dba9
Use memo to avoid rebuilding the list of options
kasparsd Feb 28, 2025
bf24a8b
Add back the defaults to avoid breaking changes
kasparsd Feb 28, 2025
fdf0915
Keep the default as prefix to match the rest of coding style
kasparsd Feb 28, 2025
9e36a1e
Rely on the default orderby options for now
kasparsd Feb 28, 2025
48ede3a
Remove for now
kasparsd Feb 28, 2025
a40f1ad
Resolve the options via the helper instead
kasparsd Feb 28, 2025
02a8ecb
Latest posts list only posts which don’t support custom menu order fo…
kasparsd Feb 28, 2025
b3533c1
Add our changelog
kasparsd Feb 28, 2025
b1bf9bd
Formatting
kasparsd Feb 28, 2025
e40c9b3
Document the change
kasparsd Feb 28, 2025
233b9d8
Move to respective section
kasparsd Mar 3, 2025
59c632d
Rely on default ordering options for posts for now
kasparsd Mar 3, 2025
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
4 changes: 4 additions & 0 deletions packages/block-library/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Enhancements

- Query Loop Block: Enable custom order or `menu_order` ordering option for post types that support it. ([#68781](https://github.com/WordPress/gutenberg/pull/68781))

## 9.19.0 (2025-02-28)

## 9.18.0 (2025-02-12)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
useAllowedControls,
isControlAllowed,
useTaxonomies,
useOrderByOptions,
} from '../../utils';
import { useToolsPanelDropdownMenuProps } from '../../../utils/hooks';

Expand Down Expand Up @@ -111,6 +112,7 @@ export default function QueryInspectorControls( props ) {
return onChangeDebounced.cancel;
}, [ querySearch, onChangeDebounced ] );

const orderByOptions = useOrderByOptions( postType );
const showInheritControl =
! isSingular && isControlAllowed( allowedControls, 'inherit' );
const showPostTypeControl =
Expand Down Expand Up @@ -329,7 +331,7 @@ export default function QueryInspectorControls( props ) {
isShownByDefault
>
<OrderControl
{ ...{ order, orderBy } }
{ ...{ order, orderBy, orderByOptions } }
onChange={ setQuery }
/>
</ToolsPanelItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { SelectControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

const orderOptions = [
const defaultOrderByOptions = [
{
label: __( 'Newest to oldest' ),
value: 'date/desc',
Expand All @@ -24,14 +24,20 @@ const orderOptions = [
value: 'title/desc',
},
];
function OrderControl( { order, orderBy, onChange } ) {

function OrderControl( {
order,
orderBy,
orderByOptions = defaultOrderByOptions,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We're keeping the defaults as fallback to prevent breaking changes.

onChange,
} ) {
return (
<SelectControl
__nextHasNoMarginBottom
__next40pxDefaultSize
label={ __( 'Order by' ) }
value={ `${ orderBy }/${ order }` }
options={ orderOptions }
options={ orderByOptions }
onChange={ ( value ) => {
const [ newOrderBy, newOrder ] = value.split( '/' );
onChange( { order: newOrder, orderBy: newOrderBy } );
Expand Down
58 changes: 58 additions & 0 deletions packages/block-library/src/query/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import { useMemo } from '@wordpress/element';
import { store as coreStore } from '@wordpress/core-data';
import { store as blockEditorStore } from '@wordpress/block-editor';
import { decodeEntities } from '@wordpress/html-entities';
import { __ } from '@wordpress/i18n';
import {
cloneBlock,
getBlockSupport,
store as blocksStore,
} from '@wordpress/blocks';

/** @typedef {import('@wordpress/blocks').WPBlockVariation} WPBlockVariation */
/** @typedef {import('@wordpress/components/build-types/query-controls/types').OrderByOption} OrderByOption */

/**
* @typedef IHasNameAndId
Expand Down Expand Up @@ -186,6 +188,62 @@ export function useIsPostTypeHierarchical( postType ) {
);
}

/**
* List of avaiable options to order by.
*
* @param {string} postType The post type to check.
* @return {OrderByOption[]} List of order options.
*/
export function useOrderByOptions( postType ) {
const supportsCustomOrder = useSelect(
( select ) => {
const type = select( coreStore ).getPostType( postType );
return !! type?.supports?.[ 'page-attributes' ];
},
[ postType ]
);

return useMemo( () => {
const orderByOptions = [
{
label: __( 'Newest to oldest' ),
value: 'date/desc',
},
{
label: __( 'Oldest to newest' ),
value: 'date/asc',
},
{
/* translators: Label for ordering posts by title in ascending order. */
label: __( 'A → Z' ),
value: 'title/asc',
},
{
/* translators: Label for ordering posts by title in descending order. */
label: __( 'Z → A' ),
value: 'title/desc',
},
];

if ( supportsCustomOrder ) {
orderByOptions.push(
{
/* translators: Label for ordering posts by ascending menu order. */
label: __( 'Ascending by order' ),
value: 'menu_order/asc',
},
{
/* translators: Label for ordering posts by descending menu order. */
label: __( 'Descending by order' ),
value: 'menu_order/desc',
}
);
}

return orderByOptions;
}, [ supportsCustomOrder ] );
}

/**
* Hook that returns the query properties' names defined by the active
* block variation, to determine which block's filters to show.
Expand Down
4 changes: 4 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Enhancement

- `QueryControls`: Add menu_order sorting option if supported by the post type. ([#68781](https://github.com/WordPress/gutenberg/pull/68781)).

## 29.5.0 (2025-02-28)

### Documentation
Expand Down
13 changes: 10 additions & 3 deletions packages/components/src/query-controls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const QUERY_DEFAULTS = {

const MyQueryControls = () => {
const [ query, setQuery ] = useState( QUERY_DEFAULTS );
const { category, categories, maxItems, minItems, numberOfItems, order, orderBy } = query;
const { category, categories, maxItems, minItems, numberOfItems, order, orderBy } = query;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Mamaduka I got confused by the use of categories here. Technically that is also not part of the query coming from block attributes. How do you suggest we represent the orderByOptions here, if at all?

Copy link
Member

Choose a reason for hiding this comment

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

The new options are included now in QueryControls types, which should be a good hint for developers.

We should also update the categories handler, but that's for a different PR.


const updateQuery = ( newQuery ) => {
setQuery( { ...query, ...newQuery } );
Expand Down Expand Up @@ -213,7 +213,14 @@ The order in which to retrieve posts.
- Required: No
- Platform: Web

#### `orderBy`: `'date' | 'title'`
#### `orderBy`: `'date' | 'title' | 'menu_order'`

The meta key by which to order posts.

- Required: No
- Platform: Web

#### `orderByOptions`: `OrderByOption[]`

The meta key by which to order posts.

Expand Down Expand Up @@ -246,4 +253,4 @@ The selected category for the `categoriesList` prop.
Start opting into the larger default height that will become the default size in a future version.

- Required: No
- Default: `false`
- Default: `false`
5 changes: 3 additions & 2 deletions packages/components/src/query-controls/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import CategorySelect from './category-select';
const DEFAULT_MIN_ITEMS = 1;
const DEFAULT_MAX_ITEMS = 100;

const options = [
const defaultOrderByOptions = [
{
label: __( 'Newest to oldest' ),
value: 'date/desc',
Expand Down Expand Up @@ -42,6 +42,7 @@ const QueryControls = memo(
numberOfItems,
order,
orderBy,
orderByOptions = defaultOrderByOptions,
maxItems = DEFAULT_MAX_ITEMS,
minItems = DEFAULT_MIN_ITEMS,
onCategoryChange,
Expand All @@ -68,7 +69,7 @@ const QueryControls = memo(
<SelectControl
label={ __( 'Order by' ) }
value={ `${ orderBy }/${ order }` }
options={ options }
options={ orderByOptions }
onChange={ onChange }
hideCancelButton
/>
Expand Down
46 changes: 25 additions & 21 deletions packages/components/src/query-controls/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
QueryControlsProps,
QueryControlsWithMultipleCategorySelectionProps,
QueryControlsWithSingleCategorySelectionProps,
OrderByOption,
} from './types';

const DEFAULT_MIN_ITEMS = 1;
Expand All @@ -34,13 +35,34 @@ function isMultipleCategorySelection(
return 'categorySuggestions' in props;
}

const defaultOrderByOptions: OrderByOption[] = [
{
label: __( 'Newest to oldest' ),
value: 'date/desc',
},
{
label: __( 'Oldest to newest' ),
value: 'date/asc',
},
{
/* translators: Label for ordering posts by title in ascending order. */
label: __( 'A → Z' ),
value: 'title/asc',
},
{
/* translators: Label for ordering posts by title in descending order. */
label: __( 'Z → A' ),
value: 'title/desc',
},
];

/**
* Controls to query for posts.
*
* ```jsx
* const MyQueryControls = () => (
* <QueryControls
* { ...{ maxItems, minItems, numberOfItems, order, orderBy } }
* { ...{ maxItems, minItems, numberOfItems, order, orderBy, orderByOptions } }
* onOrderByChange={ ( newOrderBy ) => {
* updateQuery( { orderBy: newOrderBy } )
* }
Expand All @@ -65,6 +87,7 @@ export function QueryControls( {
numberOfItems,
order,
orderBy,
orderByOptions = defaultOrderByOptions,
maxItems = DEFAULT_MAX_ITEMS,
minItems = DEFAULT_MIN_ITEMS,
onAuthorChange,
Expand All @@ -89,26 +112,7 @@ export function QueryControls( {
? undefined
: `${ orderBy }/${ order }`
}
options={ [
{
label: __( 'Newest to oldest' ),
value: 'date/desc',
},
{
label: __( 'Oldest to newest' ),
value: 'date/asc',
},
{
/* translators: Label for ordering posts by title in ascending order. */
label: __( 'A → Z' ),
value: 'title/asc',
},
{
/* translators: Label for ordering posts by title in descending order. */
label: __( 'Z → A' ),
value: 'title/desc',
},
] }
options={ orderByOptions }
onChange={ ( value ) => {
if ( typeof value !== 'string' ) {
return;
Expand Down
17 changes: 16 additions & 1 deletion packages/components/src/query-controls/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,18 @@ export type AuthorSelectProps = Pick<
};

type Order = 'asc' | 'desc';
type OrderBy = 'date' | 'title';
type OrderBy = 'date' | 'title' | 'menu_order';

export type OrderByOption = {
/**
* The label to be shown to the user.
*/
label: string;
/**
* Option value passed to `onChange` when the option is selected.
*/
value: `${ OrderBy }/${ Order }`;
};

type BaseQueryControlsProps = {
/**
Expand Down Expand Up @@ -99,6 +110,10 @@ type BaseQueryControlsProps = {
* The meta key by which to order posts.
*/
orderBy?: OrderBy;
/**
* List of available ordering options.
*/
orderByOptions?: OrderByOption[];
/**
* The selected author ID.
*/
Expand Down
Loading