From 94f89b7cc7ad9a4897608e1f44a7f0bce2b49b2a Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Tue, 16 Nov 2021 13:34:49 +0000 Subject: [PATCH 1/2] Ensure array query parameters do not contain empty items In some cases query args like `post__in` that are expected to be array might contain invalid data such as an empty string. An array like `[ '' ]` will not appear as empty when checked with `empty( [ '' ] )` so this update ensures the arrays only contain real values. Database IDs all start from 1 so removing `0` is ok here. This issue was observed with Yoast SEO adding subqueries for indexables to populate `post__in` parameters, however the index was incomplete. Can also happens in non-production environments where indexables aren't saved to the database. --- includes/classes/Indexable/Post/Post.php | 28 +++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/includes/classes/Indexable/Post/Post.php b/includes/classes/Indexable/Post/Post.php index ac973236cb..6af40fe1e5 100644 --- a/includes/classes/Indexable/Post/Post.php +++ b/includes/classes/Indexable/Post/Post.php @@ -887,6 +887,32 @@ public function format_args( $args, $wp_query ) { ), ); $use_filters = false; + + // Sanitize array query args. Elasticsearch will error if a terms query contains empty items like an + // empty string. + $keys_to_sanitize = [ + 'author__in', + 'author__not_in', + 'category__and', + 'category__in', + 'category__not_in', + 'tag__and', + 'tag__in', + 'tag__not_in', + 'tag_slug__and', + 'tag_slug__in', + 'post_parent__in', + 'post_parent__not_in', + 'post__in', + 'post__not_in', + 'post_name__in', + ]; + foreach ( $keys_to_sanitize as $key ) { + if ( ! isset( $args[ $key ] ) ) { + continue; + } + $args[ $key ] = array_filter( (array) $args[ $key ] ); + } /** * Tax Query support @@ -1072,7 +1098,7 @@ function( $tax_query ) use ( $args ) { * * @since 3.6.0 */ - if ( ! empty( $args['post_name__in'] ) ) { + if ( ! empty( array_filter( (array) $args['post_name__in'] ) ) ) { $filter['bool']['must'][]['bool']['must'] = array( 'terms' => array( 'post_name.raw' => array_values( (array) $args['post_name__in'] ), From 369ab12c0947f1855e6c2c1c67544ee6432bc343 Mon Sep 17 00:00:00 2001 From: Robert O'Rourke Date: Fri, 19 Nov 2021 16:41:49 +0000 Subject: [PATCH 2/2] Remove inline array_filter This was an initial test of the approach and should have been removed. --- includes/classes/Indexable/Post/Post.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/classes/Indexable/Post/Post.php b/includes/classes/Indexable/Post/Post.php index 6af40fe1e5..f6b99ccc74 100644 --- a/includes/classes/Indexable/Post/Post.php +++ b/includes/classes/Indexable/Post/Post.php @@ -887,7 +887,7 @@ public function format_args( $args, $wp_query ) { ), ); $use_filters = false; - + // Sanitize array query args. Elasticsearch will error if a terms query contains empty items like an // empty string. $keys_to_sanitize = [ @@ -1098,7 +1098,7 @@ function( $tax_query ) use ( $args ) { * * @since 3.6.0 */ - if ( ! empty( array_filter( (array) $args['post_name__in'] ) ) ) { + if ( ! empty( $args['post_name__in'] ) ) { $filter['bool']['must'][]['bool']['must'] = array( 'terms' => array( 'post_name.raw' => array_values( (array) $args['post_name__in'] ),