Skip to content

Commit

Permalink
Query Loop: Add 'menu_order' as sorting option (#68781)
Browse files Browse the repository at this point in the history
Co-authored-by: kasparsd <[email protected]>
Co-authored-by: carolinan <[email protected]>
Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: karmatosed <[email protected]>
Co-authored-by: Humanify-nl <[email protected]>
Co-authored-by: mikeritter <[email protected]>
  • Loading branch information
7 people authored Mar 3, 2025
1 parent 2103d50 commit e093fef
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 31 deletions.
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,
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;

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

0 comments on commit e093fef

Please sign in to comment.