From 18aa9cc0dca3f15b82e5e7ff990da79a3ffa0c6f Mon Sep 17 00:00:00 2001 From: Ryan Welcher Date: Sun, 6 Jul 2025 21:42:46 -0400 Subject: [PATCH 1/9] Add static method to retrieve the list of know params that can now be filtered using the aql_allowed_controls filter. --- includes/Query_Params_Generator.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/includes/Query_Params_Generator.php b/includes/Query_Params_Generator.php index 298c226..278658c 100644 --- a/includes/Query_Params_Generator.php +++ b/includes/Query_Params_Generator.php @@ -68,7 +68,6 @@ public function __construct( $default_params, $custom_params ) { $this->custom_params = is_array( $custom_params ) ? $custom_params : array(); } - /** * Checks to see if the item that is passed is a post ID. * @@ -107,11 +106,18 @@ public function get_custom_param( string $name ) { return false; } + /** + * Static function to return the list of filtered params. + */ + public static function get_known_params() { + return apply_filters( 'aql_allowed_controls', self::KNOWN_PARAMS ); + } + /** * Process all params at once. */ public function process_all(): void { - foreach ( self::KNOWN_PARAMS as $param_name ) { + foreach ( self::get_known_params() as $param_name ) { if ( $this->has_custom_param( $param_name ) ) { call_user_func( array( $this, 'process_' . $param_name ) ); } From 91fbda6c1e8ffada49beee530d4829078070a24f Mon Sep 17 00:00:00 2001 From: Ryan Welcher Date: Sun, 6 Jul 2025 21:43:28 -0400 Subject: [PATCH 2/9] Add the list of allowed controls to the enqueued script using via an inline script. --- includes/enqueues.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/includes/enqueues.php b/includes/enqueues.php index c5ebbcf..0731487 100644 --- a/includes/enqueues.php +++ b/includes/enqueues.php @@ -7,7 +7,7 @@ namespace AdvancedQueryLoop; -use function AdvancedQueryLoop\Utils\{ is_gutenberg_plugin_version_or_higher,is_core_version_or_higher }; +use function AdvancedQueryLoop\Utils\{ is_gutenberg_plugin_version_or_higher, is_core_version_or_higher }; // Bail on unit tests. @@ -35,9 +35,15 @@ function () { ); // Allow for translation. wp_set_script_translations( 'advanced-query-loop', 'advanced-query-loop' ); + + // Add inline script. + wp_add_inline_script( + 'advanced-query-loop', + 'aql.controls = ' . json_encode( Query_Params_Generator::get_known_params() ) . ';' + ); } - // Per Page, Offset, and Max count controls where merged into GB 19. + // Per Page, Offset, and Max count controls were merged into GB 19. if ( ! is_gutenberg_plugin_version_or_higher( '19' ) && ! is_core_version_or_higher( '6.7' ) ) { // Enqueue the legacy controls. $pre_gb_19_assets_file = BUILD_DIR_PATH . 'legacy-pre-gb-19.asset.php'; From 42bb2be88a20980a4ae7072e203fcf1ddaf89887 Mon Sep 17 00:00:00 2001 From: Ryan Welcher Date: Sun, 6 Jul 2025 21:44:07 -0400 Subject: [PATCH 3/9] Conditionally render the controls based on the aql_allowed_controls filter. --- src/variations/controls.js | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/variations/controls.js b/src/variations/controls.js index 582e24d..1203492 100644 --- a/src/variations/controls.js +++ b/src/variations/controls.js @@ -46,8 +46,9 @@ const isAdvancedQueryLoop = ( props ) => { const withAdvancedQueryControls = ( BlockEdit ) => ( props ) => { // If the is the correct variation, add the custom controls. if ( isAdvancedQueryLoop( props ) ) { - // If the inherit prop is false or undefined, add all the controls. + const { controls } = window?.aql; const { attributes } = props; + // If the inherit prop is false or undefined, add all the controls. if ( ! attributes.query.inherit ) { return ( <> @@ -62,15 +63,31 @@ const withAdvancedQueryControls = ( BlockEdit ) => ( props ) => { - - - + { controls?.multiple_posts && ( + + ) } + { controls?.tax_query && ( + + ) } + { controls?.meta_query && ( + + ) } - - - - - + { controls?.exclude_current && ( + + ) } + { controls?.include_posts && ( + + ) } + { controls?.post_parent && ( + + ) } + { controls?.date_query && ( + + ) } + { controls?.disable_pagination && ( + + ) } From 747355ed79f7ec884c7b0cf2c7bc4e8059492c8e Mon Sep 17 00:00:00 2001 From: Ryan Welcher Date: Sun, 6 Jul 2025 21:51:20 -0400 Subject: [PATCH 4/9] Namespaces be wildin' --- includes/Query_Params_Generator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Query_Params_Generator.php b/includes/Query_Params_Generator.php index 278658c..7df374b 100644 --- a/includes/Query_Params_Generator.php +++ b/includes/Query_Params_Generator.php @@ -110,7 +110,7 @@ public function get_custom_param( string $name ) { * Static function to return the list of filtered params. */ public static function get_known_params() { - return apply_filters( 'aql_allowed_controls', self::KNOWN_PARAMS ); + return \apply_filters( 'aql_allowed_controls', self::KNOWN_PARAMS ); } /** From ea08ade80a62eaca913973d716ab153237c30837 Mon Sep 17 00:00:00 2001 From: Ryan Welcher Date: Sun, 6 Jul 2025 22:07:04 -0400 Subject: [PATCH 5/9] Mock apply_filters. --- phpunit.xml | 2 +- tests/unit/bootstrap.php | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/unit/bootstrap.php diff --git a/phpunit.xml b/phpunit.xml index 07ee568..6e07158 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,7 +1,7 @@ Date: Tue, 8 Jul 2025 15:52:02 -0400 Subject: [PATCH 6/9] Move the controls and params into a single array where the key is the control and the value is the param that is processed by the control. This provides the ability to turn of different controls that process the same param. i.e the date query ones. --- includes/Query_Params_Generator.php | 46 ++++++++++++++++++----------- includes/enqueues.php | 3 +- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/includes/Query_Params_Generator.php b/includes/Query_Params_Generator.php index 7df374b..36f700a 100644 --- a/includes/Query_Params_Generator.php +++ b/includes/Query_Params_Generator.php @@ -21,21 +21,23 @@ class Query_Params_Generator { use Traits\Tax_Query; use Traits\Post_Parent; - /** - * The list of all custom params + * The list of allowed controls and their associated params in the query. */ - const KNOWN_PARAMS = array( - 'multiple_posts', - 'exclude_current', - 'include_posts', - 'meta_query', - 'date_query', - 'disable_pagination', - 'tax_query', - 'post_parent', + const ALLOWED_CONTROLS = array( + 'additional_post_types' => 'multiple_posts', + 'taxonomy_query_builder' => 'tax_query', + 'post_meta_query' => 'meta_query', + 'post_order' => 'post_order', + 'exclude_current_post' => 'exclude_current', + 'include_posts' => 'include_posts', + 'child_items_only' => 'child_items_only', + 'date_query_dynamic_range' => 'date_query', + 'date_query_relationship' => 'date_query', + 'pagination' => 'disable_pagination', ); + /** * Default values from the default block. * @@ -105,19 +107,30 @@ public function get_custom_param( string $name ) { } return false; } - /** - * Static function to return the list of filtered params. + * Static function to return the list of allowed controls and their associated params in the query. + * + * @return array */ - public static function get_known_params() { - return \apply_filters( 'aql_allowed_controls', self::KNOWN_PARAMS ); + public static function get_allowed_controls() { + return \apply_filters( 'aql_allowed_controls', array_keys( self::ALLOWED_CONTROLS ) ); + } + + protected function get_params_to_process() { + $params = array(); + foreach ( self::get_allowed_controls() as $control ) { + $params[] = self::ALLOWED_CONTROLS[ $control ]; + } + return $params; } /** * Process all params at once. */ public function process_all(): void { - foreach ( self::get_known_params() as $param_name ) { + // Get the params from the allowed controls and remove any duplicates. + $params = array_unique( $this->get_params_to_process() ); + foreach ( $params as $param_name ) { if ( $this->has_custom_param( $param_name ) ) { call_user_func( array( $this, 'process_' . $param_name ) ); } @@ -130,5 +143,4 @@ public function process_all(): void { public function get_query_args(): array { return $this->custom_args; } - } diff --git a/includes/enqueues.php b/includes/enqueues.php index 0731487..430e557 100644 --- a/includes/enqueues.php +++ b/includes/enqueues.php @@ -35,11 +35,10 @@ function () { ); // Allow for translation. wp_set_script_translations( 'advanced-query-loop', 'advanced-query-loop' ); - // Add inline script. wp_add_inline_script( 'advanced-query-loop', - 'aql.controls = ' . json_encode( Query_Params_Generator::get_known_params() ) . ';' + 'aql.allowedControls = "' . implode( ',', Query_Params_Generator::get_allowed_controls() ) . '";' ); } From 4908bf272633b41460b67e6782928ba44ba6cd46 Mon Sep 17 00:00:00 2001 From: Ryan Welcher Date: Tue, 8 Jul 2025 15:54:07 -0400 Subject: [PATCH 7/9] Retrieve the alq.allowedControls variable, process it into an array and pass it as part of the props to each component. Each component handles rendering itself based on the controls availability. --- src/components/child-items-toggle.js | 11 +- src/components/multiple-post-select.js | 23 +- src/components/pagination-toggle.js | 10 +- src/components/post-date-query-controls.js | 256 +++++++++++---------- src/components/post-exclude-controls.js | 18 +- src/components/post-include-controls.js | 11 +- src/components/post-meta-query-controls.js | 15 +- src/components/post-order-controls.js | 12 +- src/components/taxonomy-query-control.js | 11 +- src/variations/controls.js | 52 ++--- 10 files changed, 251 insertions(+), 168 deletions(-) diff --git a/src/components/child-items-toggle.js b/src/components/child-items-toggle.js index 025ad41..7732ab4 100644 --- a/src/components/child-items-toggle.js +++ b/src/components/child-items-toggle.js @@ -7,7 +7,11 @@ import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; import { store as editorStore } from '@wordpress/editor'; -export const ChildItemsToggle = ( { attributes, setAttributes } ) => { +export const ChildItemsToggle = ( { + attributes, + setAttributes, + allowedControls, +} ) => { const { query: { post_parent: postParent } = {} } = attributes; const { isHierarchial, postTypeName, postID } = useSelect( ( select ) => { @@ -22,6 +26,11 @@ export const ChildItemsToggle = ( { attributes, setAttributes } ) => { }; }, [] ); + // If the control is not allowed, return null. + if ( ! allowedControls.includes( 'child_items_only' ) ) { + return null; + } + return ( { +export const MultiplePostSelect = ( { + attributes, + setAttributes, + allowedControls, +} ) => { const { query: { multiple_posts: multiplePosts = [], postType } = {} } = attributes; - const postTypes = useSelect( ( select ) => - select( coreStore ) - .getPostTypes( { per_page: 50 } ) - ?.filter( ( { viewable } ) => viewable ) - ?.map( ( { slug } ) => slug ) + const postTypes = useSelect( + ( select ) => + select( coreStore ) + .getPostTypes( { per_page: 50 } ) + ?.filter( ( { viewable } ) => viewable ) + ?.map( ( { slug } ) => slug ), + [] ); + // If the control is not allowed, return null. + if ( ! allowedControls.includes( 'additional_post_types' ) ) { + return null; + } + if ( ! postTypes ) { return
{ __( 'Loading…', 'advanced-query-loop' ) }
; } diff --git a/src/components/pagination-toggle.js b/src/components/pagination-toggle.js index 054151c..e6704f7 100644 --- a/src/components/pagination-toggle.js +++ b/src/components/pagination-toggle.js @@ -4,9 +4,17 @@ import { ToggleControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -export const PaginationToggle = ( { attributes, setAttributes } ) => { +export const PaginationToggle = ( { + attributes, + setAttributes, + allowedControls, +} ) => { const { query: { disable_pagination: disablePagination } = {} } = attributes; + // If the control is not allowed, return null. + if ( ! allowedControls.includes( 'pagination' ) ) { + return null; + } return ( { +export const PostDateQueryControls = ( { + attributes, + setAttributes, + allowedControls, +} ) => { const { query: { date_query: { @@ -24,143 +28,155 @@ export const PostDateQueryControls = ( { attributes, setAttributes } ) => { return ( <>

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

- { - setAttributes( { - query: { - ...attributes.query, - date_query: { - ...attributes.query.date_query, - range: newRange, - }, - }, - } ); - } } - __nextHasNoMarginBottom - /> - { range !== '' && ( - { + value={ range } + disabled={ relationFromQuery !== '' } + options={ [ + { + label: __( 'None', 'advanced-query-loop' ), + value: '', + }, + { + label: __( 'Last month', 'advanced-query-loop' ), + value: 'last-month', + }, + { + label: __( 'Last 3 months', 'advanced-query-loop' ), + value: 'three-months', + }, + { + label: __( 'Last 6 months', 'advanced-query-loop' ), + value: 'six-months', + }, + { + label: __( + 'Last 12 months', + 'advanced-query-loop' + ), + value: 'twelve-months', + }, + ] } + onChange={ ( newRange ) => { setAttributes( { query: { ...attributes.query, date_query: { ...attributes.query.date_query, - current_date_in_range: - newCurrentDateInRange, + range: newRange, }, }, } ); } } + __nextHasNoMarginBottom /> ) } - - { - setAttributes( { - query: { - ...attributes.query, - date_query: - relation !== '' - ? { - ...attributes.query.date_query, - relation, - } - : '', + ) } + disabled={ range === '' } + checked={ currentDateInRange } + onChange={ ( newCurrentDateInRange ) => { + setAttributes( { + query: { + ...attributes.query, + date_query: { + ...attributes.query.date_query, + current_date_in_range: + newCurrentDateInRange, + }, + }, + } ); + } } + /> + ) } + { allowedControls.includes( 'date_query_relationship' ) && ( + + { + label: __( + 'Between specific dates', + 'advanced-query-loop' + ), + value: 'between', + }, + ] } + onChange={ ( relation ) => { + setAttributes( { + query: { + ...attributes.query, + date_query: + relation !== '' + ? { + ...attributes.query.date_query, + relation, + } + : '', + }, + } ); + } } + __nextHasNoMarginBottom + /> + ) } { relationFromQuery !== '' && - ! relationFromQuery.includes( 'current' ) && ( + ! relationFromQuery.includes( 'current' ) && + allowedControls.includes( 'date_query_relationship' ) && ( <> { relationFromQuery === 'between' && (

diff --git a/src/components/post-exclude-controls.js b/src/components/post-exclude-controls.js index ff82341..f1db202 100644 --- a/src/components/post-exclude-controls.js +++ b/src/components/post-exclude-controls.js @@ -9,13 +9,18 @@ import { __ } from '@wordpress/i18n'; /** * A component that lets you pick posts to be excluded from the query * - * @param {Object} props Component props - * @param {Object} props.attributes Block attributes - * @param {Function} props.setAttributes Block attributes setter + * @param {Object} props Component props + * @param {Object} props.attributes Block attributes + * @param {Function} props.setAttributes Block attributes setter + * @param {Array} props.allowedControls Allowed controls * * @return {Element} PostExcludeControls */ -export const PostExcludeControls = ( { attributes, setAttributes } ) => { +export const PostExcludeControls = ( { + attributes, + setAttributes, + allowedControls, +} ) => { const { query: { exclude_current: excludeCurrent } = {} } = attributes; const { record: siteOptions } = useEntityRecord( 'root', 'site' ); const { currentPost, isAdmin } = useSelect( ( select ) => { @@ -28,6 +33,11 @@ export const PostExcludeControls = ( { attributes, setAttributes } ) => { }; }, [] ); + // If the control is not allowed, return null. + if ( ! allowedControls.includes( 'exclude_current_post' ) ) { + return null; + } + if ( ! currentPost ) { return
{ __( 'Loading…', 'advanced-query-loop' ) }
; } diff --git a/src/components/post-include-controls.js b/src/components/post-include-controls.js index 3a2a07a..2074523 100644 --- a/src/components/post-include-controls.js +++ b/src/components/post-include-controls.js @@ -13,7 +13,11 @@ import { __ } from '@wordpress/i18n'; *@return {Element} PostIncludeControls */ -export const PostIncludeControls = ( { attributes, setAttributes } ) => { +export const PostIncludeControls = ( { + attributes, + setAttributes, + allowedControls, +} ) => { const { query: { include_posts: includePosts = [], @@ -69,6 +73,11 @@ export const PostIncludeControls = ( { attributes, setAttributes } ) => { } }, [ multiplePosts ] ); + // If the control is not allowed, return null.`` + if ( ! allowedControls.includes( 'include_posts' ) ) { + return null; + } + /** * Retrieves the ID of a post based on its title. * diff --git a/src/components/post-meta-query-controls.js b/src/components/post-meta-query-controls.js index 6960303..06e2850 100644 --- a/src/components/post-meta-query-controls.js +++ b/src/components/post-meta-query-controls.js @@ -30,7 +30,11 @@ const combineMetaKeys = ( records ) => { }; // A component to render a select control for the post meta query. -export const PostMetaQueryControls = ( { attributes, setAttributes } ) => { +export const PostMetaQueryControls = ( { + attributes, + setAttributes, + allowedControls, +} ) => { const { query: { postType, @@ -44,8 +48,6 @@ export const PostMetaQueryControls = ( { attributes, setAttributes } ) => { const [ selectedPostType ] = useState( postType ); - const registeredMeta = combineMetaKeys( records ); - useEffect( () => { // If the post type changes, reset the meta query. if ( postType !== selectedPostType ) { @@ -59,6 +61,13 @@ export const PostMetaQueryControls = ( { attributes, setAttributes } ) => { } }, [ postType ] ); + // If the control is not allowed, return null. + if ( ! allowedControls.includes( 'post_meta_query' ) ) { + return null; + } + + const registeredMeta = combineMetaKeys( records ); + return ( <>

{ __( 'Post Meta Query', 'advanced-query-loop' ) }

diff --git a/src/components/post-order-controls.js b/src/components/post-order-controls.js index f7eee69..c7e3b91 100644 --- a/src/components/post-order-controls.js +++ b/src/components/post-order-controls.js @@ -61,8 +61,18 @@ export const sortOptions = [ * @param {*} param0 * @return {Element} PostCountControls */ -export const PostOrderControls = ( { attributes, setAttributes } ) => { +export const PostOrderControls = ( { + attributes, + setAttributes, + allowedControls, +} ) => { const { query: { order, orderBy } = {} } = attributes; + + // If the control is not allowed, return null. + if ( ! allowedControls.includes( 'post_order' ) ) { + return null; + } + return ( <> { +export const TaxonomyQueryControl = ( { + attributes, + setAttributes, + allowedControls, +} ) => { const { query: { postType, @@ -45,6 +49,11 @@ export const TaxonomyQueryControl = ( { attributes, setAttributes } ) => { ) ); + // If the control is not allowed, return null. + if ( ! allowedControls.includes( 'taxonomy_query_builder' ) ) { + return null; + } + return ( <> { const withAdvancedQueryControls = ( BlockEdit ) => ( props ) => { // If the is the correct variation, add the custom controls. if ( isAdvancedQueryLoop( props ) ) { - const { controls } = window?.aql; + const { allowedControls } = window?.aql; const { attributes } = props; + const allowedControlsArray = allowedControls.split( ',' ); + const propsWithControls = { + ...props, + allowedControls: allowedControlsArray, + }; // If the inherit prop is false or undefined, add all the controls. if ( ! attributes.query.inherit ) { return ( @@ -61,34 +66,21 @@ const withAdvancedQueryControls = ( BlockEdit ) => ( props ) => { ) } > + + + + + + + + + + + - { controls?.multiple_posts && ( - - ) } - { controls?.tax_query && ( - - ) } - { controls?.meta_query && ( - - ) } - - { controls?.exclude_current && ( - - ) } - { controls?.include_posts && ( - - ) } - { controls?.post_parent && ( - - ) } - { controls?.date_query && ( - - ) } - { controls?.disable_pagination && ( - - ) } - @@ -105,9 +97,9 @@ const withAdvancedQueryControls = ( BlockEdit ) => ( props ) => { 'advanced-query-loop' ) } > - + From f40f2eb2b035d6de6fe09f4c799feedf21cc138d Mon Sep 17 00:00:00 2001 From: Ryan Welcher Date: Tue, 8 Jul 2025 16:00:46 -0400 Subject: [PATCH 8/9] Update readme. --- readme.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/readme.md b/readme.md index 1bc7de6..b17dd28 100644 --- a/readme.md +++ b/readme.md @@ -61,6 +61,42 @@ Sort in ascending or descending order by: Improve the performance of the query by disabling pagination. This is done automatically when there is now Pagination block in teh Post Template. +## Filtering the available controls + +It is possible to remove controls from AQL using the `aql_allowed_controls` filter: + +```php +add_filter( + 'aql_allowed_controls', + function( $controls ) { + // Exclude the additional_post_types and taxonomy_query_builder controls. + $to_exclude = array( 'additional_post_types', 'taxonomy_query_builder' ); + $filtered_controls = array_filter( + $controls, + function( $control ) use ( $to_exclude ) { + if ( ! in_array( $control, $to_exclude, true ) ) { + return $control; + } + }, + ); + return $filtered_controls; + } +); +``` + +### List of control identifiers + +- `'additional_post_types'` +- `'taxonomy_query_builder'` +- `'post_meta_query'` +- `'post_order'` +- `'exclude_current_post'` +- `'include_posts'` +- `'child_items_only'` +- `'date_query_dynamic_range'` +- `'date_query_relationship'` +- `'pagination'` + ## Extending AQL Detailed instructions on how to extend AQL as well as an example are available [here](./extending-aql.md) From fe528dbc41a0f5f6f55362d47983592d04516296 Mon Sep 17 00:00:00 2001 From: Ryan Welcher Date: Tue, 8 Jul 2025 16:13:36 -0400 Subject: [PATCH 9/9] Better filter explanation. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index b17dd28..9129bf6 100644 --- a/readme.md +++ b/readme.md @@ -63,7 +63,7 @@ Improve the performance of the query by disabling pagination. This is done autom ## Filtering the available controls -It is possible to remove controls from AQL using the `aql_allowed_controls` filter: +It is possible to remove controls from AQL using the `aql_allowed_controls` filter. The filter receives a single parameter containing an array of allowed controls. This can be modified to remove the control from the UI and stop processing the associated query param. ```php add_filter(