diff --git a/lib/compat/wordpress-5.8/index.php b/lib/compat/wordpress-5.8/index.php index 29a97fb20de81..35b0f11eeae1f 100644 --- a/lib/compat/wordpress-5.8/index.php +++ b/lib/compat/wordpress-5.8/index.php @@ -164,3 +164,39 @@ function gutenberg_register_legacy_query_loop_block() { add_action( 'init', 'gutenberg_register_legacy_query_loop_block' ); } + +if ( ! function_exists( 'get_query_pagination_arrow' ) ) { + /** + * Helper function that returns the proper pagination arrow html for + * `QueryPaginationNext` and `QueryPaginationPrevious` blocks based + * on the provided `paginationArrow` from `QueryPagination` context. + * + * It's used in QueryPaginationNext and QueryPaginationPrevious blocks. + * + * @param WP_Block $block Block instance. + * @param boolean $is_next Flag for hanlding `next/previous` blocks. + * + * @return string|null Returns the constructed WP_Query arguments. + */ + function get_query_pagination_arrow( $block, $is_next ) { + $arrow_map = array( + 'none' => '', + 'arrow' => array( + 'next' => '→', + 'previous' => '←', + ), + 'chevron' => array( + 'next' => '»', + 'previous' => '«', + ), + ); + if ( ! empty( $block->context['paginationArrow'] ) && array_key_exists( $block->context['paginationArrow'], $arrow_map ) && ! empty( $arrow_map[ $block->context['paginationArrow'] ] ) ) { + $pagination_type = $is_next ? 'next' : 'previous'; + $arrow_attribute = $block->context['paginationArrow']; + $arrow = $arrow_map[ $block->context['paginationArrow'] ][ $pagination_type ]; + $arrow_classes = "wp-block-query-pagination-$pagination_type-arrow is-arrow-$arrow_attribute"; + return "$arrow"; + } + return null; + } +} diff --git a/packages/block-library/src/query-pagination-next/block.json b/packages/block-library/src/query-pagination-next/block.json index afc69d6e14a3b..f7d4850413222 100644 --- a/packages/block-library/src/query-pagination-next/block.json +++ b/packages/block-library/src/query-pagination-next/block.json @@ -11,7 +11,7 @@ "type": "string" } }, - "usesContext": [ "queryId", "query" ], + "usesContext": [ "queryId", "query", "paginationArrow" ], "supports": { "reusable": false, "html": false, diff --git a/packages/block-library/src/query-pagination-next/edit.js b/packages/block-library/src/query-pagination-next/edit.js index 4e48c0bcecaa6..d91f3d7e0ba30 100644 --- a/packages/block-library/src/query-pagination-next/edit.js +++ b/packages/block-library/src/query-pagination-next/edit.js @@ -4,19 +4,41 @@ import { __ } from '@wordpress/i18n'; import { useBlockProps, PlainText } from '@wordpress/block-editor'; +const arrowMap = { + none: '', + arrow: '→', + chevron: '»', +}; + export default function QueryPaginationNextEdit( { attributes: { label }, setAttributes, + context: { paginationArrow }, } ) { + const displayArrow = arrowMap[ paginationArrow ]; return ( - setAttributes( { label: newLabel } ) } + <a + href="#pagination-next-pseudo-link" + onClick={ ( event ) => event.preventDefault() } { ...useBlockProps() } - /> + > + <PlainText + __experimentalVersion={ 2 } + tagName="span" + aria-label={ __( 'Next page link' ) } + placeholder={ __( 'Next Page' ) } + value={ label } + onChange={ ( newLabel ) => + setAttributes( { label: newLabel } ) + } + /> + { displayArrow && ( + <span + className={ `wp-block-query-pagination-next-arrow is-arrow-${ paginationArrow }` } + > + { displayArrow } + </span> + ) } + </a> ); } diff --git a/packages/block-library/src/query-pagination-next/index.php b/packages/block-library/src/query-pagination-next/index.php index 7b0b4051f1aac..d091e1c6bbc0f 100644 --- a/packages/block-library/src/query-pagination-next/index.php +++ b/packages/block-library/src/query-pagination-next/index.php @@ -22,7 +22,11 @@ function render_block_core_query_pagination_next( $attributes, $content, $block $wrapper_attributes = get_block_wrapper_attributes(); $default_label = __( 'Next Page' ); $label = isset( $attributes['label'] ) && ! empty( $attributes['label'] ) ? $attributes['label'] : $default_label; - $content = ''; + $pagination_arrow = get_query_pagination_arrow( $block, true ); + if ( $pagination_arrow ) { + $label .= $pagination_arrow; + } + $content = ''; // Check if the pagination is for Query that inherits the global context. if ( isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] ) { diff --git a/packages/block-library/src/query-pagination-previous/block.json b/packages/block-library/src/query-pagination-previous/block.json index 78a53867d0b7a..c3a05cc202d30 100644 --- a/packages/block-library/src/query-pagination-previous/block.json +++ b/packages/block-library/src/query-pagination-previous/block.json @@ -11,7 +11,7 @@ "type": "string" } }, - "usesContext": [ "queryId", "query" ], + "usesContext": [ "queryId", "query", "paginationArrow" ], "supports": { "reusable": false, "html": false, diff --git a/packages/block-library/src/query-pagination-previous/edit.js b/packages/block-library/src/query-pagination-previous/edit.js index 2c0bf33005de8..c695a453ce1e3 100644 --- a/packages/block-library/src/query-pagination-previous/edit.js +++ b/packages/block-library/src/query-pagination-previous/edit.js @@ -4,19 +4,41 @@ import { __ } from '@wordpress/i18n'; import { useBlockProps, PlainText } from '@wordpress/block-editor'; +const arrowMap = { + none: '', + arrow: '←', + chevron: '«', +}; + export default function QueryPaginationPreviousEdit( { attributes: { label }, setAttributes, + context: { paginationArrow }, } ) { + const displayArrow = arrowMap[ paginationArrow ]; return ( - <PlainText - __experimentalVersion={ 2 } - tagName="a" - aria-label={ __( 'Previous page link' ) } - placeholder={ __( 'Previous Page' ) } - value={ label } - onChange={ ( newLabel ) => setAttributes( { label: newLabel } ) } + <a + href="#pagination-previous-pseudo-link" + onClick={ ( event ) => event.preventDefault() } { ...useBlockProps() } - /> + > + { displayArrow && ( + <span + className={ `wp-block-query-pagination-previous-arrow is-arrow-${ paginationArrow }` } + > + { displayArrow } + </span> + ) } + <PlainText + __experimentalVersion={ 2 } + tagName="span" + aria-label={ __( 'Previous page link' ) } + placeholder={ __( 'Previous Page' ) } + value={ label } + onChange={ ( newLabel ) => + setAttributes( { label: newLabel } ) + } + /> + </a> ); } diff --git a/packages/block-library/src/query-pagination-previous/index.php b/packages/block-library/src/query-pagination-previous/index.php index ac319d0be4dbf..47506496722d8 100644 --- a/packages/block-library/src/query-pagination-previous/index.php +++ b/packages/block-library/src/query-pagination-previous/index.php @@ -21,7 +21,11 @@ function render_block_core_query_pagination_previous( $attributes, $content, $bl $wrapper_attributes = get_block_wrapper_attributes(); $default_label = __( 'Previous Page' ); $label = isset( $attributes['label'] ) && ! empty( $attributes['label'] ) ? $attributes['label'] : $default_label; - $content = ''; + $pagination_arrow = get_query_pagination_arrow( $block, false ); + if ( $pagination_arrow ) { + $label = $pagination_arrow . $label; + } + $content = ''; // Check if the pagination is for Query that inherits the global context // and handle appropriately. if ( isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] ) { diff --git a/packages/block-library/src/query-pagination/block.json b/packages/block-library/src/query-pagination/block.json index c1de24977f37f..45b7a42bffbad 100644 --- a/packages/block-library/src/query-pagination/block.json +++ b/packages/block-library/src/query-pagination/block.json @@ -6,7 +6,16 @@ "parent": [ "core/query" ], "description": "Displays a paginated navigation to next/previous set of posts, when applicable.", "textdomain": "default", + "attributes": { + "paginationArrow": { + "type": "string", + "default": "none" + } + }, "usesContext": [ "queryId", "query" ], + "providesContext": { + "paginationArrow": "paginationArrow" + }, "supports": { "align": true, "reusable": false, diff --git a/packages/block-library/src/query-pagination/edit.js b/packages/block-library/src/query-pagination/edit.js index 47ac55f30693a..c3f4f53f5f2b3 100644 --- a/packages/block-library/src/query-pagination/edit.js +++ b/packages/block-library/src/query-pagination/edit.js @@ -1,10 +1,20 @@ /** * WordPress dependencies */ +import { __ } from '@wordpress/i18n'; import { + InspectorControls, useBlockProps, __experimentalUseInnerBlocksProps as useInnerBlocksProps, + store as blockEditorStore, } from '@wordpress/block-editor'; +import { useSelect } from '@wordpress/data'; +import { PanelBody } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { QueryPaginationArrowControls } from './query-pagination-arrow-controls'; const TEMPLATE = [ [ 'core/query-pagination-previous' ], @@ -12,7 +22,25 @@ const TEMPLATE = [ [ 'core/query-pagination-next' ], ]; -export default function QueryPaginationEdit() { +export default function QueryPaginationEdit( { + attributes: { paginationArrow }, + setAttributes, + clientId, +} ) { + const hasNextPreviousBlocks = useSelect( ( select ) => { + const { getBlocks } = select( blockEditorStore ); + const innerBlocks = getBlocks( clientId ); + /** + * Show the `paginationArrow` control only if a + * `QueryPaginationNext/Previous` block exists. + */ + return innerBlocks?.find( ( innerBlock ) => { + return [ + 'core/query-pagination-next', + 'core/query-pagination-previous', + ].includes( innerBlock.name ); + } ); + }, [] ); const blockProps = useBlockProps(); const innerBlocksProps = useInnerBlocksProps( blockProps, { template: TEMPLATE, @@ -23,5 +51,21 @@ export default function QueryPaginationEdit() { ], orientation: 'horizontal', } ); - return <div { ...innerBlocksProps } />; + return ( + <> + { hasNextPreviousBlocks && ( + <InspectorControls> + <PanelBody title={ __( 'Settings' ) }> + <QueryPaginationArrowControls + value={ paginationArrow } + onChange={ ( value ) => { + setAttributes( { paginationArrow: value } ); + } } + /> + </PanelBody> + </InspectorControls> + ) } + <div { ...innerBlocksProps } /> + </> + ); } diff --git a/packages/block-library/src/query-pagination/query-pagination-arrow-controls.js b/packages/block-library/src/query-pagination/query-pagination-arrow-controls.js new file mode 100644 index 0000000000000..28ae36ed41572 --- /dev/null +++ b/packages/block-library/src/query-pagination/query-pagination-arrow-controls.js @@ -0,0 +1,44 @@ +/** + * WordPress dependencies + */ +import { __, _x } from '@wordpress/i18n'; +import { + __experimentalToggleGroupControl as ToggleGroupControl, + __experimentalToggleGroupControlOption as ToggleGroupControlOption, +} from '@wordpress/components'; + +export function QueryPaginationArrowControls( { value, onChange } ) { + return ( + <ToggleGroupControl + label={ __( 'Arrow' ) } + value={ value } + onChange={ onChange } + help={ __( + 'A decorative arrow appended to the next and previous page link.' + ) } + isBlock + > + <ToggleGroupControlOption + value="none" + label={ _x( + 'None', + 'Arrow option for Query Pagination Next/Previous blocks' + ) } + /> + <ToggleGroupControlOption + value="arrow" + label={ _x( + 'Arrow', + 'Arrow option for Query Pagination Next/Previous blocks' + ) } + /> + <ToggleGroupControlOption + value="chevron" + label={ _x( + 'Chevron', + 'Arrow option for Query Pagination Next/Previous blocks' + ) } + /> + </ToggleGroupControl> + ); +} diff --git a/packages/block-library/src/query-pagination/style.scss b/packages/block-library/src/query-pagination/style.scss index e140863a7d981..5a4a950757cd7 100644 --- a/packages/block-library/src/query-pagination/style.scss +++ b/packages/block-library/src/query-pagination/style.scss @@ -18,4 +18,22 @@ $pagination-margin: 0.5em; margin-right: 0; } } + .wp-block-query-pagination-previous-arrow { + margin-right: 1ch; + display: inline-block; // Needed so that the transform works. + // chevron(`»`) symbol doesn't need the mirroring by us. + &:not(.is-arrow-chevron) { + // Flip for RTL. + transform: scaleX(1) #{"/*rtl:scaleX(-1);*/"}; // This points the arrow right for LTR and left for RTL. + } + } + .wp-block-query-pagination-next-arrow { + margin-left: 1ch; + display: inline-block; // Needed so that the transform works. + // chevron(`»`) symbol doesn't need the mirroring by us. + &:not(.is-arrow-chevron) { + // Flip for RTL. + transform: scaleX(1) #{"/*rtl:scaleX(-1);*/"}; // This points the arrow right for LTR and left for RTL. + } + } } diff --git a/test/integration/fixtures/blocks/core__query-pagination.json b/test/integration/fixtures/blocks/core__query-pagination.json index a5ade7819c893..9a5c156770fbf 100644 --- a/test/integration/fixtures/blocks/core__query-pagination.json +++ b/test/integration/fixtures/blocks/core__query-pagination.json @@ -3,7 +3,9 @@ "clientId": "_clientId_0", "name": "core/query-pagination", "isValid": true, - "attributes": {}, + "attributes": { + "paginationArrow": "none" + }, "innerBlocks": [], "originalContent": "<div class=\"wp-block-query-pagination\"></div>" }