From 0dced4fa59adb204000eb9c50bb724cbbafeb5b1 Mon Sep 17 00:00:00 2001 From: Carsten Bach Date: Tue, 19 Nov 2024 11:33:43 +0100 Subject: [PATCH] Introduce files from https://github.com/carstingaxion/additional-advanced-query-loops/tree/gatherpress-query-loop (https://github.com/GatherPress/gatherpress/issues/599) --- .../core/classes/blocks/class-event-query.php | 336 ++++++++++++++++++ .../components/event-count-controls.js | 33 ++ .../components/event-exclude-controls.js | 40 +++ .../event-include-unfinished-controls.js | 36 ++ .../components/event-list-type-controls.js | 46 +++ .../components/event-offset-controls.js | 26 ++ .../components/event-order-controls.js | 95 +++++ .../components/post-date-query-controls.js | 117 ++++++ src/variations/event-query/controls.js | 156 ++++++++ src/variations/event-query/index.js | 234 ++++++++++++ src/variations/event-query/pagination.js | 49 +++ .../slots/gpql-controls-inherited-query.js | 15 + .../event-query/slots/gpql-controls.js | 21 ++ src/variations/event-query/templates.js | 65 ++++ 14 files changed, 1269 insertions(+) create mode 100644 includes/core/classes/blocks/class-event-query.php create mode 100644 src/variations/event-query/components/event-count-controls.js create mode 100644 src/variations/event-query/components/event-exclude-controls.js create mode 100644 src/variations/event-query/components/event-include-unfinished-controls.js create mode 100644 src/variations/event-query/components/event-list-type-controls.js create mode 100644 src/variations/event-query/components/event-offset-controls.js create mode 100644 src/variations/event-query/components/event-order-controls.js create mode 100644 src/variations/event-query/components/post-date-query-controls.js create mode 100644 src/variations/event-query/controls.js create mode 100644 src/variations/event-query/index.js create mode 100644 src/variations/event-query/pagination.js create mode 100644 src/variations/event-query/slots/gpql-controls-inherited-query.js create mode 100644 src/variations/event-query/slots/gpql-controls.js create mode 100644 src/variations/event-query/templates.js diff --git a/includes/core/classes/blocks/class-event-query.php b/includes/core/classes/blocks/class-event-query.php new file mode 100644 index 000000000..1280ddb1d --- /dev/null +++ b/includes/core/classes/blocks/class-event-query.php @@ -0,0 +1,336 @@ +setup_hooks(); + } + + /** + * Set up hooks for various purposes. + * + * This method adds hooks for different purposes as needed. + * + * @since 1.0.0 + * + * @return void + */ + protected function setup_hooks(): void { + add_action('init', array( $this, 'init'), PHP_INT_MAX ); + } + + public function init() : void { + + // + add_filter( + 'pre_render_block', + array( $this, 'pre_render_block'), + 10, + 2 + ); + + // Updates the query vars for the Query Loop block in the block editor. + add_filter( + sprintf( 'rest_%s_query', Event::POST_TYPE ), + array( $this, 'rest_query'), + 10, + 2 + ); + + // We need more sortBy options. + add_filter( + sprintf( 'rest_%s_collection_params', Event::POST_TYPE ), + array( $this, 'rest_collection_params'), + 10, + 2 + ); + } + + + + /** + * Allows render_block() to be short-circuited, by returning a non-null value. + * + * Updates the query on the front end based on custom query attributes. + * + * @param string|null $pre_render The pre-rendered content. Default null. + * @param array $parsed_block The block being rendered. + * @return string|null The pre-rendered content. Default null. + */ + public function pre_render_block( ?string $pre_render, array $parsed_block ): ?string { + if ( isset( $parsed_block['attrs']['namespace'] ) && 'gatherpress-event-query' === $parsed_block['attrs']['namespace'] ) { + + // Hijack the global query. It's a hack, but it works. + if ( isset( $parsed_block['attrs']['query']['inherit'] ) && true === $parsed_block['attrs']['query']['inherit'] ) { + global $wp_query; + $query_args = array_merge( + $wp_query->query_vars, + array( + 'posts_per_page' => $parsed_block['attrs']['query']['perPage'], + 'order' => $parsed_block['attrs']['query']['order'], + 'orderby' => $parsed_block['attrs']['query']['orderBy'], + ) + ); + + /** + * Filter the query vars. + * + * Allows filtering query params when the query is being inherited. + * + * @since 1.5 + * + * @param array $query_args Arguments to be passed to WP_Query. + * @param array $block_query The query attribute retrieved from the block. + * @param boolean $inherited Whether the query is being inherited. + * + * @param array $filtered_query_args Final arguments list. + */ + $filtered_query_args = \apply_filters( + 'gpql_query_vars', + $query_args, + $parsed_block['attrs']['query'], + true, + ); + + $wp_query = new \WP_Query( $filtered_query_args ); + } else { + add_filter( + 'query_loop_block_query_vars', + array( $this, 'query_loop_block_query_vars'), + 10, + 2 + ); + } + } + + return $pre_render; + } + + /** + * Returns an array with Post IDs that should be excluded from the Query. + * + * @param array + * @return int[] + */ + protected function get_exclude_ids( array $attributes ): array { + $exclude_ids = array(); + + // Exclude Current Post. + if ( isset( $attributes['exclude_current'] ) && boolval( $attributes['exclude_current'] ) ) { + array_push( $exclude_ids, $attributes['exclude_current'] ); + } + + return $exclude_ids; + } + + /** + * Filters the arguments which will be passed to `WP_Query` for the Query Loop Block. + * + * @param array $query Array containing parameters for WP_Query as parsed by the block context. + * @param \WP_Block $block Block instance. + * @return array Array containing parameters for WP_Query as parsed by the block context. + */ + public function query_loop_block_query_vars( array $query, \WP_Block $block ): array { + // Retrieve the query from the passed block context. + $block_query = $block->context['query']; + + // Generate a new custom query with all potential query vars. + $query_args = array(); + + if ( count( $query_args ) ) { + die( var_dump( $block_query, $query_args ) ); + } + + // Post Related. + $query_args['post_type'] = [ Event::POST_TYPE ]; + + // Type of event list: 'upcoming' or 'past'. + // /wp-content/plugins/gatherpress/includes/core/classes/class-event-query.php + $query_args['gatherpress_events_query'] = $block_query['gatherpress_events_query']; + + // Exclude Posts. + $exclude_ids = $this->get_exclude_ids( $block_query ); + if ( ! empty( $exclude_ids ) ) { + $query_args['post__not_in'] = $exclude_ids; + } + + if ( isset( $block_query['include_unfinished'] ) ) { + $query_args['include_unfinished'] = $block_query['include_unfinished']; + } + + // Date queries. + if ( ! empty( $block_query['date_query'] ) ) { + $date_query = $block_query['date_query']; + $date_relationship = $date_query['relation']; + $date_is_inclusive = $date_query['inclusive']; + $date_primary = $date_query['date_primary']; + $date_secondary = ! empty( $date_query['date_secondary'] ) ? $date_query['date_secondary'] : ''; + + // Date format: 2022-12-27T11:14:21. + $primary_year = substr( $date_primary, 0, 4 ); + $primary_month = substr( $date_primary, 5, 2 ); + $primary_day = substr( $date_primary, 8, 2 ); + $secondary_year = substr( $date_secondary, 0, 4 ); + $secondary_month = substr( $date_secondary, 5, 2 ); + $secondary_day = substr( $date_secondary, 8, 2 ); + + if ( 'between' === $date_relationship ) { + $date_queries = array( + 'after' => array( + 'year' => $primary_year, + 'month' => $primary_month, + 'day' => $primary_day, + ), + 'before' => array( + 'year' => $secondary_year, + 'month' => $secondary_month, + 'day' => $secondary_day, + ), + ); + } else { + $date_queries = array( + $date_relationship => array( + 'year' => $primary_year, + 'month' => $primary_month, + 'day' => $primary_day, + ), + ); + } + + $date_queries['inclusive'] = $date_is_inclusive; + + // Add the date queries to the custom query. + $query_args['date_query'] = array_filter( $date_queries ); + } + + // Order By + $query_args['orderby'] = [ $block_query['orderBy'] ]; + + // Order + // can be NULL, when ASC + $query_args['order'] = \strtoupper( $block_query['order'] ?? 'ASC' ); + + /** This filter is documented in includes/query-loop.php */ + $filtered_query_args = \apply_filters( + 'gpql_query_vars', + $query_args, + $block_query, + false + ); + + // \error_log( '$block_query: ' . \var_export( [ $block_query, $query_args ], true ) ); + // \error_log( 'queries: ' . \var_export( [ $query, $filtered_query_args ], true ) ); + // \error_log( 'queries: ' . \var_export( array_merge( + // $query, + // $filtered_query_args + // ), true ) ); + + // Return the merged query. + return array_merge( + $query, + $filtered_query_args + ); + } + + /** + * Callback to handle the custom query params. Updates the block editor. + * + * Filters WP_Query arguments when querying posts via the REST API. + * + * @param array $args Array of arguments for WP_Query. + * @param \WP_REST_Request $request The REST API request object. + * @return array Array of arguments for WP_Query. + */ + public function rest_query( array $args, \WP_REST_Request $request ) : array { + // Generate a new custom query will all potential query vars. + $custom_args = array(); + + // Type of event list: 'upcoming' or 'past'. + // /wp-content/plugins/gatherpress/includes/core/classes/class-event-query.php + $custom_args['gatherpress_events_query'] = $request->get_param( 'gatherpress_events_query' ); + + // Exclusion Related. + $exclude_current = $request->get_param( 'exclude_current' ); + if ( $exclude_current ) { + $attributes = array( + 'exclude_current' => $exclude_current, + ); + $custom_args['post__not_in'] = $this->get_exclude_ids( $attributes ); + } + + // + $include_unfinished = $request->get_param( 'include_unfinished' ); + if ( $include_unfinished ) { + $custom_args['include_unfinished'] = $include_unfinished; + } + + $custom_args['orderby'] = $request->get_param( 'orderby' ); + // \error_log( '$args: ' . \var_export( $args, true ) ); + // \error_log( '$orderby: ' . \var_export( $request->get_param( 'orderby' ), true ) ); + // \error_log( '$custom_args: ' . \var_export( $custom_args, true ) ); + + /** This filter is documented in includes/query-loop.php */ + $filtered_query_args = \apply_filters( + 'gpql_query_vars', + $custom_args, + $request->get_params(), + false, + ); + + // Merge all queries. + return array_merge( + $args, + array_filter( $filtered_query_args ) + ); + } + + /** + * Filters collection parameters for the posts controller. + * + * Override the allowed items. + * + * @see https://developer.wordpress.org/reference/classes/wp_rest_posts_controller/get_collection_params/ + * + * @param array $query_params JSON Schema-formatted collection parameters. + * @param \WP_Post_Type $post_type Post type object. + * @return array JSON Schema-formatted collection parameters. + */ + public function rest_collection_params( array $query_params, \WP_Post_Type $post_type ) : array { + $query_params['orderby']['enum'][] = 'rand'; + $query_params['orderby']['enum'][] = 'datetime'; + return $query_params; + } +} diff --git a/src/variations/event-query/components/event-count-controls.js b/src/variations/event-query/components/event-count-controls.js new file mode 100644 index 000000000..ecf331ff4 --- /dev/null +++ b/src/variations/event-query/components/event-count-controls.js @@ -0,0 +1,33 @@ +/** + * WordPress dependencies + */ +import { RangeControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * EventCountControls component + * + * @param {*} param0 + * @return {Element} EventCountControls + */ +export const EventCountControls = ( { attributes, setAttributes } ) => { + const { query: { perPage, offset = 0 } = {} } = attributes; + + return ( + { + setAttributes( { + query: { + ...attributes.query, + perPage: newCount, + offset, + }, + } ); + } } + value={ perPage } + /> + ); +}; diff --git a/src/variations/event-query/components/event-exclude-controls.js b/src/variations/event-query/components/event-exclude-controls.js new file mode 100644 index 000000000..9e507b768 --- /dev/null +++ b/src/variations/event-query/components/event-exclude-controls.js @@ -0,0 +1,40 @@ +/** + * WordPress dependencies + */ +import { ToggleControl } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; + +/** + * A component that lets you exclude the current event from the query + * + * @return {Element} EventExcludeControls + */ +export const EventExcludeControls = ( { attributes, setAttributes } ) => { + const { query: { exclude_current: excludeCurrent } = {} } = attributes; + + const currentPost = useSelect( ( select ) => { + return select( 'core/editor' ).getCurrentPost(); + }, [] ); + + if ( ! currentPost ) { + return
{ __( 'Loading…', 'gatherpress' ) }
; + } + + return ( + <> + { + setAttributes( { + query: { + ...attributes.query, + exclude_current: value ? currentPost.id : 0, + }, + } ); + } } + /> + + ); +}; diff --git a/src/variations/event-query/components/event-include-unfinished-controls.js b/src/variations/event-query/components/event-include-unfinished-controls.js new file mode 100644 index 000000000..45e68d4d8 --- /dev/null +++ b/src/variations/event-query/components/event-include-unfinished-controls.js @@ -0,0 +1,36 @@ +/** + * WordPress dependencies + */ +import { ToggleControl } from '@wordpress/components'; +import { __, _x, sprintf } from '@wordpress/i18n'; + +/** + * A component that lets you include the current event from the query + * + * @return {Element} EventIncludeUnfinishedControls + */ +export const EventIncludeUnfinishedControls = ( { attributes, setAttributes } ) => { + const { query: { include_unfinished: includeUnfinished } = {} } = attributes; + + return ( + <> + { + setAttributes( { + query: { + ...attributes.query, + include_unfinished: value ? 1 : 0, + }, + } ); + } } + /> + + ); +}; diff --git a/src/variations/event-query/components/event-list-type-controls.js b/src/variations/event-query/components/event-list-type-controls.js new file mode 100644 index 000000000..523418ad4 --- /dev/null +++ b/src/variations/event-query/components/event-list-type-controls.js @@ -0,0 +1,46 @@ +/** + * WordPress dependencies + */ +import { ToggleControl } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { __, _x, sprintf } from '@wordpress/i18n'; + +/** + * A component that lets you pick posts to be excluded from the query + * + * @return {Element} EventListTypeControls + */ +export const EventListTypeControls = ( { attributes, setAttributes } ) => { + const { query: { gatherpress_events_query: eventListType = 'upcoming' } = {} } = attributes; + + const currentPost = useSelect( ( select ) => { + return select( 'core/editor' ).getCurrentPost(); + }, [] ); + + if ( ! currentPost ) { + return
{ __( 'Loading…', 'gatherpress' ) }
; + } + + return ( + <> + {/*

{ __( 'Type of event list', 'gatherpress' ) }

*/} + { + setAttributes( { + query: { + ...attributes.query, + gatherpress_events_query: value ? 'upcoming' : 'past', + }, + } ); + } } + /> + + ); +}; diff --git a/src/variations/event-query/components/event-offset-controls.js b/src/variations/event-query/components/event-offset-controls.js new file mode 100644 index 000000000..4ca8d7f46 --- /dev/null +++ b/src/variations/event-query/components/event-offset-controls.js @@ -0,0 +1,26 @@ +/** + * WordPress dependencies + */ + +import { RangeControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +export const EventOffsetControls = ( { attributes, setAttributes } ) => { + const { query: { offset = 0 } = {} } = attributes; + return ( + { + setAttributes( { + query: { + ...attributes.query, + offset: newOffset, + }, + } ); + } } + /> + ); +}; diff --git a/src/variations/event-query/components/event-order-controls.js b/src/variations/event-query/components/event-order-controls.js new file mode 100644 index 000000000..606f9d319 --- /dev/null +++ b/src/variations/event-query/components/event-order-controls.js @@ -0,0 +1,95 @@ +/** + * WordPress dependencies + */ +import { SelectControl, ToggleControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * EventOrderControls component + * + * @param {*} param0 + * @return {Element} EventCountControls + */ +export const EventOrderControls = ( { attributes, setAttributes } ) => { + const { query: { order, orderBy } = {} } = attributes; + const label = order === 'asc' ? __( 'Ascending Order', 'gatherpress' ) : __( 'Descending Order', 'gatherpress' ); + return ( + <> + { + setAttributes( { + query: { + ...attributes.query, + orderBy: newOrderBy, + }, + } ); + } } + /> + { + setAttributes( { + query: { + ...attributes.query, + order: order === 'asc' ? 'desc' : 'asc', + }, + } ); + } } + /> + + ); +}; diff --git a/src/variations/event-query/components/post-date-query-controls.js b/src/variations/event-query/components/post-date-query-controls.js new file mode 100644 index 000000000..27dba0c93 --- /dev/null +++ b/src/variations/event-query/components/post-date-query-controls.js @@ -0,0 +1,117 @@ +/** + * WordPress dependencies + */ +import { + DatePicker, + SelectControl, + CheckboxControl, +} from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +export const PostDateQueryControls = ( { attributes, setAttributes } ) => { + const { + query: { + date_query: { + relation: relationFromQuery = '', + date_primary: datePrimary = new Date(), + date_secondary: dateSecondary = new Date(), + inclusive: isInclusive = false, + } = {}, + } = {}, + } = attributes; + + return ( + <> +

{ __( 'Post Date Query', 'gatherpress-query-loop' ) }

+ { + setAttributes( { + query: { + ...attributes.query, + date_query: + relation !== '' + ? { + ...attributes.query.date_query, + relation, + } + : '', + }, + } ); + } } + /> + { relationFromQuery !== '' && ( + <> + { relationFromQuery === 'between' && ( +

{ __( 'Start date', 'gatherpress-query-loop' ) }

+ ) } + { + setAttributes( { + query: { + ...attributes.query, + date_query: { + ...attributes.query.date_query, + date_primary: newDate, + }, + }, + } ); + } } + /> + + { relationFromQuery === 'between' && ( + <> +

{ __( 'End date', 'gatherpress-query-loop' ) }

+ { + setAttributes( { + query: { + ...attributes.query, + date_query: { + ...attributes.query.date_query, + date_secondary: newDate, + }, + }, + } ); + } } + /> + + ) } + +
+ { + setAttributes( { + query: { + ...attributes.query, + date_query: { + ...attributes.query.date_query, + inclusive: newIsInclusive, + }, + }, + } ); + } } + /> + + ) } + + ); +}; diff --git a/src/variations/event-query/controls.js b/src/variations/event-query/controls.js new file mode 100644 index 000000000..aa07e43ba --- /dev/null +++ b/src/variations/event-query/controls.js @@ -0,0 +1,156 @@ +/** + * WordPress dependencies + */ +import { addFilter } from '@wordpress/hooks'; +import { InspectorControls } from '@wordpress/block-editor'; +import { PanelBody } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + + +import { useEffect } from '@wordpress/element'; +/** + * Internal dependencies + */ +import { NAME } from '.'; +import GPQLControls from './slots/gpql-controls'; +import GPQLControlsInheritedQuery from './slots/gpql-controls-inherited-query'; +import { EventCountControls } from './components/event-count-controls'; +import { EventExcludeControls } from './components/event-exclude-controls'; +import { EventListTypeControls } from './components/event-list-type-controls'; +import { EventOffsetControls } from './components/event-offset-controls'; +import { EventOrderControls } from './components/event-order-controls'; +import { EventIncludeUnfinishedControls } from './components/event-include-unfinished-controls'; + +// import { PostDateQueryControls } from './components/post-date-query-controls'; + + + +import { isEventPostType } from '../../helpers/event'; + +/** + * Determines if the active variation is this one + * + * @param {*} props + * @return {boolean} Is this the correct variation? + */ +const isGatherPressQueryLoop = ( props ) => { + const { + attributes: { namespace }, + } = props; + return namespace && namespace === NAME; +}; + +/** + * UX helper for when using a regular query block + * and "Event" gets selected as post type, + * the UI changes to everything necessary for events. + * + * By adding the relevant attributes, + * the block is transformed into the "Event Query" block variation. + * + * @param {*} props + * @returns + */ +const QueryPosttypeObserver = ( props ) => { + const { postType } = props.attributes.query; + useEffect(() => { + if ('gatherpress_event' === postType ) { + const newAttributes = { + ...props.attributes, + namespace: NAME, + query: { + ...props.attributes.query, + gatherpress_events_query: 'upcoming', + include_unfinished: 1, + order: 'asc', + orderBy: 'datetime', + inherit: false + } + }; + props.setAttributes(newAttributes); + } + // Dependency array, every time the postType is changed, + // the useEffect callback will be called. + }, [ postType ]); + return; + +} + + +/** + * Custom controls + * + * @param {*} BlockEdit + * @return {Element} BlockEdit instance + */ +const withGatherPressQueryControls = ( BlockEdit ) => ( props ) => { + // If this is something totally different, return early. + if ( ! isGatherPressQueryLoop( props ) && 'core/query' !== props.name ) { + return ; + } + // Regular core/query blocks should become this addition. + if ( ! isGatherPressQueryLoop( props ) ) { + return ( + <> + + ; + + ); + } + // If the is the correct variation, add the custom controls. + const isEventContext = isEventPostType(); + // If the inherit prop is false, add all the controls. + const { attributes } = props; + if ( attributes.query.inherit === false ) { + return ( + <> + + + + + {/* Toggle between 'upcoming' & 'past' events. */} + + + + { isEventContext && ( + + )} + + + + + {/* */} + + + + + ); + } + // Add some controls if the inherit prop is true. + return ( + <> + + + + + + + + + ); + +}; + +addFilter( 'editor.BlockEdit', 'core/query', withGatherPressQueryControls ); diff --git a/src/variations/event-query/index.js b/src/variations/event-query/index.js new file mode 100644 index 000000000..d44bc0d30 --- /dev/null +++ b/src/variations/event-query/index.js @@ -0,0 +1,234 @@ +/** + * WordPress dependencies + */ +import { registerBlockVariation } from '@wordpress/blocks'; +import { __ } from '@wordpress/i18n'; +// import { list-view } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +// Load block-variations for pagination-blocks. +import './pagination'; // @TODO: add as separate variations ! +import './controls'; + +import GPQLControls from './slots/gpql-controls'; +import GPQLControlsInheritedQuery from './slots/gpql-controls-inherited-query'; + +import { + // GPV_BLOCK, + NO_RESULTS_BLOCK, + QUERY_PAGINATION_BLOCK +} from './templates'; + +// import GPQLIcon from '../components/icon'; + + +const NAME = 'gatherpress-event-query'; + +const QUERY_ATTRIBUTES = { + namespace: NAME, + query: { + perPage: 3, + pages: 0, + offset: 0, + postType: 'gatherpress_event', + gatherpress_events_query: 'upcoming', + include_unfinished: 1, + order: 'asc', + orderBy: 'datetime', + inherit: false + } +}; + +const VARIATION_ATTRIBUTES = { + category: 'gatherpress', + keywords: [ + __('Events', 'gatherpress'), + __('Dates', 'gatherpress'), + ], + // icon: list-view, + // isActive: ['namespace', 'scope'], + // isActive: ['query.postType'], // Idea based on @patriciabt|s feedback in slack. + isActive: ['namespace', 'query.postType'], + attributes: { + ...QUERY_ATTRIBUTES + }, + allowedControls: ['inherit', 'taxQuery'], + scope: ['block'], +} + + +/** + * Docs about the Query block. + * + * General information on how to modify the query loop block, that's worth reading and learning: + * + * @see https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/extending-the-query-loop-block/#extending-the-query + * @see https://wpfieldwork.com/modify-query-loop-block-to-filter-by-custom-field/ + * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/ + * @see https://jeffreycarandang.com/restrict-wordpress-gutenberg-block-settings-based-on-post-type-user-roles-or-block-context/ + */ + +/** + * This is the main query-block variation to list events exclusively. + * A user can pick the block directly from the inserter or the left sidebar. + * + * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/ + */ +registerBlockVariation('core/query', { + ...VARIATION_ATTRIBUTES, + name: NAME, + title: __('Event Query', 'gatherpress'), + description: __('Create event queries', 'gatherpress'), + scope: ['inserter', 'transform'], + /* + * Having innerBlocks in THIS (visible) variation, essentially + * skips the setup phase of the Query Loop block with suggested patterns + * and the block is inserted with these inner blocks as its starting content. + * + * This is not what I wanted, so I disabled it. + * + * @see https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/extending-the-query-loop-block/#customize-your-variation-layout + + innerBlocks: [ + [ + 'core/post-template', + {}, + [ + [ 'gatherpress/event-date' ], + [ 'core/post-title' ], + [ 'core/post-excerpt' ] + ], + ], + [ 'core/query-pagination' ], + [ 'core/query-no-results' ], + ], */ + + example: { + attributes: { + ...QUERY_ATTRIBUTES + }, + innerBlocks: [ + { + name: 'core/post-template', + attributes: {}, + innerBlocks: [ + { + name: 'gatherpress/event-date', + }, + { + name: 'core/post-title', + }, + // { + // ...GPV_BLOCK, + // } + ], + }, + ], + }, +}); + + +/** + * One of the 'Start blank' patterns for the gatherpress query loop variation. + */ +registerBlockVariation('core/query', { + ...VARIATION_ATTRIBUTES, + name: 'gatherpress-event-query-map-date', + title: __('Map & Event-Date', 'gatherpress'), + description: __('Create gatherpress queries with Map & Date', 'gatherpress'), + innerBlocks: [ + [ + 'core/post-template', + { + metadata:{ + name:__( + 'Events Template', + 'gatherpress' + ) + } + }, + [ + ['gatherpress/venue'], + ['gatherpress/event-date'], + ], + ], + QUERY_PAGINATION_BLOCK, + NO_RESULTS_BLOCK + ], +}); + +/** + * One of the 'Start blank' patterns for the gatherpress query loop variation. + */ +registerBlockVariation('core/query', { + ...VARIATION_ATTRIBUTES, + name: 'gatherpress-event-query-date-title', + title: __('Event-Date, Title & Venue details', 'gatherpress'), + description: __('Create gatherpress queries with Event-Date & Title', 'gatherpress'), + innerBlocks: [ + [ + 'core/post-template', + { + metadata:{ + name:__( + 'Events Template', + 'gatherpress' + ) + } + }, + [ + { + name: 'gatherpress/event-date', + }, + { + name: 'core/post-title', + }, + // { + // ...GPV_BLOCK, + // }, + ], + ], + QUERY_PAGINATION_BLOCK, + NO_RESULTS_BLOCK + ], +}); + +/** + * One of the 'Start blank' patterns for the gatherpress query loop variation. + */ +registerBlockVariation('core/query', { + ...VARIATION_ATTRIBUTES, + name: 'gatherpress-event-query-date-address', + title: __('Event-Date & Venue Details', 'gatherpress'), + description: __('Create gatherpress queries with Event-Date & Venue Details', 'gatherpress'), + innerBlocks: [ + [ + 'core/post-template', + { + metadata:{ + name:__( + 'Events Template', + 'gatherpress' + ) + } + }, + [ + { + name:'gatherpress/event-date' + }, + // { + // ...GPV_BLOCK, + // }, + ], + ], + QUERY_PAGINATION_BLOCK, + NO_RESULTS_BLOCK + ], +}); + + + + +export { NAME, GPQLControls, GPQLControlsInheritedQuery }; diff --git a/src/variations/event-query/pagination.js b/src/variations/event-query/pagination.js new file mode 100644 index 000000000..941992c37 --- /dev/null +++ b/src/variations/event-query/pagination.js @@ -0,0 +1,49 @@ +/** + * WordPress dependencies + */ +import { registerBlockVariation } from '@wordpress/blocks'; +import { __ } from '@wordpress/i18n'; +// import { queryPaginationNext, queryPaginationPrevious } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +// import GPQLIcon from '../components/icon'; + +/** + * Update UI for pagination blocks to speak 'events', not 'posts'. + */ +registerBlockVariation('core/query-pagination-previous', { + category: 'gatherpress', + keywords: [ + __('Page numbers', 'default'), + __('Pagination', 'default'), + ], + // icon: GPQLIcon( queryPaginationPrevious ), + isActive: ['className'], + attributes: { + className: 'gatherpress-query-pagination-previous', + label: __('Previous Events', 'gatherpress'), + }, + // scope: ['block'], + name: 'gatherpress-query-pagination-previous', + title: __('Previous Events', 'gatherpress'), + description: __('Displays the previous events link.', 'gatherpress'), +}); +registerBlockVariation('core/query-pagination-next', { + category: 'gatherpress', + keywords: [ + __('Page numbers', 'default'), + __('Pagination', 'default'), + ], + // icon: GPQLIcon( queryPaginationNext ), + isActive: ['className'], + attributes: { + className: 'gatherpress-query-pagination-next', + label: __('Next Events', 'gatherpress'), + }, + // scope: ['block'], + name: 'gatherpress-query-pagination-next', + title: __('Next Events', 'gatherpress'), + description: __('Displays the next events link.', 'gatherpress'), +}); diff --git a/src/variations/event-query/slots/gpql-controls-inherited-query.js b/src/variations/event-query/slots/gpql-controls-inherited-query.js new file mode 100644 index 000000000..3ecf4d18c --- /dev/null +++ b/src/variations/event-query/slots/gpql-controls-inherited-query.js @@ -0,0 +1,15 @@ +/** + * WordPress dependencies + */ +import { createSlotFill } from '@wordpress/components'; + +/** + * Create our Slot and Fill components + */ +const { Fill, Slot } = createSlotFill( 'GPQLControlsInheritedQuery' ); + +const GPQLControlsInheritedQuery = ( { children } ) => { children }; + +GPQLControlsInheritedQuery.Slot = Slot; + +export default GPQLControlsInheritedQuery; diff --git a/src/variations/event-query/slots/gpql-controls.js b/src/variations/event-query/slots/gpql-controls.js new file mode 100644 index 000000000..46e83dfbf --- /dev/null +++ b/src/variations/event-query/slots/gpql-controls.js @@ -0,0 +1,21 @@ +/** + * WordPress dependencies + */ +import { createSlotFill } from '@wordpress/components'; + +/** + * Create our Slot and Fill components + */ +const { Fill, Slot } = createSlotFill( 'GPQLControls' ); + +const GPQLControls = ( { children } ) => { children }; + +GPQLControls.Slot = ( { fillProps } ) => ( + + { ( fills ) => { + return fills.length ? fills : null; + } } + +); + +export default GPQLControls; diff --git a/src/variations/event-query/templates.js b/src/variations/event-query/templates.js new file mode 100644 index 000000000..1f768d9d0 --- /dev/null +++ b/src/variations/event-query/templates.js @@ -0,0 +1,65 @@ + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +/** + * Internal dependencies + */ +// import { GPV_CLASS_NAME } from '../helpers/namespace'; + +// export const GPV_BLOCK = { +// name: 'core/group', +// attributes: { +// className: GPV_CLASS_NAME, +// // is neccessary to make isActive work !! +// // @see https://github.com/WordPress/gutenberg/issues/41303#issuecomment-1526193087 +// layout: { type: 'flex', orientation: 'nonsense' }, // works +// }, +// innerBlocks: [ +// [ +// 'core/pattern', +// { +// slug: 'gatherpress/venue-details', +// }, +// ], +// ], +// } + +const NO_RESULTS_TEMPLATE = [ + [ + 'core/paragraph', + { + placeholder: __( + 'Add text or blocks that will display when a query returns no events.', + 'gatherpress' + ), + }, + ], +]; + +export const NO_RESULTS_BLOCK = [ + 'core/query-no-results', + { + metadata:{ + name:__( + 'No events', + 'gatherpress' + ) + } + }, + NO_RESULTS_TEMPLATE +]; + + + +const QUERY_PAGINATION_TEMPLATE = [ + [ 'core/query-pagination-previous', { label:__('Previous Events', 'gatherpress'), className: 'gatherpress-query-pagination-previous' } ], + [ 'core/query-pagination-numbers' ], + [ 'core/query-pagination-next', { label:__('Next Events', 'gatherpress'), className: 'gatherpress-query-pagination-next' } ], +]; +export const QUERY_PAGINATION_BLOCK = [ + 'core/query-pagination', + {}, + QUERY_PAGINATION_TEMPLATE +]; \ No newline at end of file