array_merge overwrites $query_args['tax_query'] after it's added in aql_query_vars filter
When modifying the $query_args using the aql_query_vars filter, the array_merge in the query_loop_block_query_vars callback function overwrites the tax_query in $query_args. This causes issues when custom tax queries are added via filters, as demonstrated in the code below
function remove_pasta_recipes_from_aql_block( array $query_args, array $block_query, bool $inherited ): array {
$query_args['tax_query'] = array(
array(
'taxonomy' => 'recipe_category',
'field' => 'slug',
'terms' => 'pasta',
'operator' => 'NOT IN',
'include_children' => false,
),
);
return $query_args;
}
add_filter( 'aql_query_vars', 'remove_pasta_recipes_from_aql_block', 10, 3 );
The line for reference: https://github.com/ryanwelcher/advanced-query-loop/blob/17bf11c08bbc3756382022fc64c3c593a18b2ce8/includes/query-loop.php#L77
$default_query contains taxonomy filters set via 'Filters' in the 'Block' settings/tab.
In this example the array key tax_query replaces the previous one when array_merge is used, losing any previous taxonomies defined in $default_query.
A possible fix could be to use array_merge_recursive instead of array_merge
Thanks for opening this issues. I'll look at it and get some unit tests wrapped around this.
@robistek looking at your code again, it looks like you are actually replacing the key in the hook by assigning tax_query to an array rather than adding to it.
You should check to see that it's defined first but the code below is going to add to the existing tax_query array.
function remove_pasta_recipes_from_aql_block( array $query_args, array $block_query, bool $inherited ): array {
$query_args['tax_query'][] =
array(
'taxonomy' => 'recipe_category',
'field' => 'slug',
'terms' => 'pasta',
'operator' => 'NOT IN',
'include_children' => false,
);
return $query_args;
}
add_filter( 'aql_query_vars', 'remove_pasta_recipes_from_aql_block', 10, 3 );
Thanks for the reply and the patience, @ryanwelcher.
I have modified the code, tested it and written a more complete example.
I have updated my filter function to make it more robust - thanks for your input:
function remove_pasta_recipes_from_aql_block( array $query_args, array $block_query, bool $inherited ): array {
if ( ! $inherited ) {
$additional_query_args = array(
'taxonomy' => 'recipe_category',
'field' => 'slug',
'terms' => 'pasta',
'operator' => 'NOT IN',
'include_children' => false,
);
// Exclude posts where the taxonomy 'recipe_category' has the slug 'pasta'.
if ( isset( $query_args['tax_query'] ) && is_array( $query_args['tax_query'] ) ) {
$query_args['tax_query'][] = $additional_query_args;
} else {
$query_args['tax_query'] = array(
$additional_query_args,
);
}
}
return $query_args;
}
add_filter( 'aql_query_vars', 'remove_pasta_recipes_from_aql_block', 10, 3 );
When this filter returns $query_args in query-loop.php, $default_query and $filtered_query_args are merged.
During debugging I found out that even if $default_query has a 'tax_query' key is doesn't mean that $query_args (which is passed to the aql_query_vars filter) has a 'tax_query' key.
$default_query = array (
'post_type' => 'recipe',
'order' => 'DESC',
'orderby' => 'date',
'tax_query' =>
array (
0 =>
array (
'taxonomy' => 'recipe_ingredient',
'terms' =>
array (
0 => 123,
),
'include_children' => false,
),
),
'offset' => 0,
'posts_per_page' => 4,
'author__in' =>
array (
),
);
$filtered_query_args = array (
'post__not_in' =>
array (
0 => 1000,
),
'tax_query' =>
array (
0 =>
array (
'taxonomy' => 'recipe_category',
'field' => 'slug',
'terms' => 'pasta',
'operator' => 'NOT IN',
'include_children' => false,
),
),
);
The result of print_r( array_merge( $default_query, $filtered_query_args ) ) will be an array with the key 'recipe_ingredient' missing:
Array
(
[post_type] => sd_recipe
[order] => DESC
[orderby] => date
[tax_query] => Array
(
[0] => Array
(
[taxonomy] => recipe_category
[field] => slug
[terms] => pasta
[operator] => NOT IN
[include_children] =>
)
)
[offset] => 0
[posts_per_page] => 4
[author__in] => Array
(
)
[post__not_in] => Array
(
[0] => 1000
)
)
Am I using the aql_query_vars filter as intended?
Should I be using the $block_query parameter as a base to build a the query array before it is returned?
Thank you for the detailed follow up on this. I think I am now seeing the issue. I am in the process of adding some unit tests for this that should provide better insights. Thanks for your patience!