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

Add menu_order sorting option to Query Loop block #68781

Open
wants to merge 27 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f0c3039
Add support for menu order
kasparsd Jan 20, 2025
11fca2e
Add the menu order option
kasparsd Jan 20, 2025
681186c
Two more copy-paste location
kasparsd Jan 20, 2025
27dd5a1
Match the order
kasparsd Jan 20, 2025
a50362f
Update labels per discussion
kasparsd Jan 21, 2025
6def53a
Helper for resolving order by options for a post type
kasparsd Feb 17, 2025
0ed2ac0
Add the option type
kasparsd Feb 17, 2025
066e3e3
Pass in the options
kasparsd Feb 17, 2025
f40d2b6
Restrict the values to only known values
kasparsd Feb 17, 2025
777debf
Keep the order
kasparsd Feb 17, 2025
ba52675
Define the type for just the option
kasparsd Feb 17, 2025
016c83e
Document the updated fields
kasparsd Feb 17, 2025
568fd9d
Update the examples
kasparsd Feb 17, 2025
f6af1ec
Reference the type
kasparsd Feb 17, 2025
27a3c60
This is really required for the drop-down component, keep it simple here
kasparsd Feb 17, 2025
ef44e18
Merge remote-tracking branch 'origin/trunk' into 42710-add-menu-order…
kasparsd Feb 28, 2025
a6c408a
Add back the default options to prevent breaking changes
kasparsd Feb 28, 2025
49affb3
Use memo to avoid rebuilding the list of options
kasparsd Feb 28, 2025
1becd19
Add back the defaults to avoid breaking changes
kasparsd Feb 28, 2025
27c04ea
Keep the default as prefix to match the rest of coding style
kasparsd Feb 28, 2025
924364c
Rely on the default orderby options for now
kasparsd Feb 28, 2025
2cca836
Remove for now
kasparsd Feb 28, 2025
d7e34aa
Resolve the options via the helper instead
kasparsd Feb 28, 2025
ca99bbd
Latest posts list only posts which don’t support custom menu order fo…
kasparsd Feb 28, 2025
3947b6a
Add our changelog
kasparsd Feb 28, 2025
7cc05e8
Formatting
kasparsd Feb 28, 2025
4c6a316
Document the change
kasparsd Feb 28, 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
3 changes: 2 additions & 1 deletion packages/block-library/src/latest-posts/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) {
postsToShow,
order,
orderBy,
orderByOptions,
categories,
selectedAuthor,
displayFeaturedImage,
Expand Down Expand Up @@ -372,7 +373,7 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) {

<PanelBody title={ __( 'Sorting and filtering' ) }>
<QueryControls
{ ...{ order, orderBy } }
{ ...{ order, orderBy, orderByOptions } }
numberOfItems={ postsToShow }
onOrderChange={ ( value ) =>
setAttributes( { order: value } )
Expand Down
3 changes: 2 additions & 1 deletion packages/block-library/src/latest-posts/edit.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ class LatestPostsEdit extends Component {
addLinkToFeaturedImage,
order,
orderBy,
orderByOptions,
postsToShow,
categories,
} = attributes;
Expand Down Expand Up @@ -215,7 +216,7 @@ class LatestPostsEdit extends Component {

<PanelBody title={ __( 'Sorting and filtering' ) }>
<QueryControls
{ ...{ order, orderBy } }
{ ...{ order, orderBy, orderByOptions } }
numberOfItems={ postsToShow }
categoriesList={ categoriesList }
selectedCategoryId={
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,34 +4,14 @@
import { SelectControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

const orderOptions = [
{
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',
},
];
function OrderControl( { order, orderBy, onChange } ) {
function OrderControl( { order, orderBy, orderByOptions, 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
55 changes: 55 additions & 0 deletions packages/block-library/src/query/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ 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,
Expand Down Expand Up @@ -186,6 +187,60 @@ export function useIsPostTypeHierarchical( postType ) {
);
}

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

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;
}

/**
* Hook that returns the query properties' names defined by the active
* block variation, to determine which block's filters to show.
Expand Down
27 changes: 22 additions & 5 deletions packages/components/src/query-controls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,29 @@ const QUERY_DEFAULTS = {
numberOfItems: 10,
order: 'asc',
orderBy: 'title',
orderByOptions: [
{
label: 'Title Ascending',
value: 'title/asc',
},
{
label: 'Title Descending',
value: 'title/desc',
},
],
};

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, orderByOptions } = query;

const updateQuery = ( newQuery ) => {
setQuery( { ...query, ...newQuery } );
};

return (
<QueryControls
{ ...{ maxItems, minItems, numberOfItems, order, orderBy } }
{ ...{ maxItems, minItems, numberOfItems, order, orderBy, orderByOptions } }
onOrderByChange={ ( newOrderBy ) => updateQuery( { orderBy: newOrderBy } ) }
onOrderChange={ ( newOrder ) => updateQuery( { order: newOrder } ) }
categoriesList={ categories }
Expand Down Expand Up @@ -108,7 +118,7 @@ const MyQueryControls = () => {

return (
<QueryControls
{ ...{ orderBy, order, numberOfItems } }
{ ...{ orderBy, order, orderByOptions, numberOfItems } }
onOrderByChange={ ( newOrderBy ) => updateQuery( { orderBy: newOrderBy } ) }
onOrderChange={ ( newOrder ) => updateQuery( { order: newOrder } ) }
categorySuggestions={ categories }
Expand Down Expand Up @@ -213,7 +223,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 +263,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`
24 changes: 2 additions & 22 deletions packages/components/src/query-controls/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,14 @@ import CategorySelect from './category-select';
const DEFAULT_MIN_ITEMS = 1;
const DEFAULT_MAX_ITEMS = 100;

const 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',
},
];

const QueryControls = memo(
( {
categoriesList,
selectedCategoryId,
numberOfItems,
order,
orderBy,
orderByOptions,
maxItems = DEFAULT_MAX_ITEMS,
minItems = DEFAULT_MIN_ITEMS,
onCategoryChange,
Expand All @@ -68,7 +48,7 @@ const QueryControls = memo(
<SelectControl
label={ __( 'Order by' ) }
value={ `${ orderBy }/${ order }` }
options={ options }
options={ orderByOptions }
onChange={ onChange }
hideCancelButton
/>
Expand Down
24 changes: 3 additions & 21 deletions packages/components/src/query-controls/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function isMultipleCategorySelection(
* ```jsx
* const MyQueryControls = () => (
* <QueryControls
* { ...{ maxItems, minItems, numberOfItems, order, orderBy } }
* { ...{ maxItems, minItems, numberOfItems, order, orderBy, orderByOptions } }
* onOrderByChange={ ( newOrderBy ) => {
* updateQuery( { orderBy: newOrderBy } )
* }
Expand All @@ -65,6 +65,7 @@ export function QueryControls( {
numberOfItems,
order,
orderBy,
orderByOptions,
maxItems = DEFAULT_MAX_ITEMS,
minItems = DEFAULT_MIN_ITEMS,
onAuthorChange,
Expand All @@ -89,26 +90,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
16 changes: 15 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,17 @@ export type AuthorSelectProps = Pick<
};

type Order = 'asc' | 'desc';
type OrderBy = 'date' | 'title';
type OrderBy = 'date' | 'title' | 'menu_order';
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 }`;
} & Omit< React.OptionHTMLAttributes< HTMLOptionElement >, 'label' | 'value' >;

type BaseQueryControlsProps = {
/**
Expand Down Expand Up @@ -99,6 +109,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