: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @param array $clause Query clause.
* @param array $parent_query Parent query of $clause.
* @return string|false Table alias if found, otherwise false.
protected function find_compatible_table_alias( $clause, $parent_query ) {
// Confidence check. Only IN queries use the JOIN syntax.
if ( ! isset( $clause['operator'] ) || 'IN' !== $clause['operator'] ) {
// Since we're only checking IN queries, we're only concerned with OR relations.
if ( ! isset( $parent_query['relation'] ) || 'OR' !== $parent_query['relation'] ) {
$compatible_operators = array( 'IN' );
foreach ( $parent_query as $sibling ) {
if ( ! is_array( $sibling ) || ! $this->is_first_order_clause( $sibling ) ) {
if ( empty( $sibling['alias'] ) || empty( $sibling['operator'] ) ) {
// The sibling must both have compatible operator to share its alias.
if ( in_array( strtoupper( $sibling['operator'] ), $compatible_operators, true ) ) {
$alias = preg_replace( '/\W/', '_', $sibling['alias'] );
* Validates a single query.
* @param array $query The single query. Passed by reference.
private function clean_query( &$query ) {
if ( empty( $query['taxonomy'] ) ) {
if ( 'term_taxonomy_id' !== $query['field'] ) {
$query = new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
// So long as there are shared terms, 'include_children' requires that a taxonomy is set.
$query['include_children'] = false;
} elseif ( ! taxonomy_exists( $query['taxonomy'] ) ) {
$query = new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
if ( 'slug' === $query['field'] || 'name' === $query['field'] ) {
$query['terms'] = array_unique( (array) $query['terms'] );
$query['terms'] = wp_parse_id_list( $query['terms'] );
if ( is_taxonomy_hierarchical( $query['taxonomy'] ) && $query['include_children'] ) {
$this->transform_query( $query, 'term_id' );
if ( is_wp_error( $query ) ) {
foreach ( $query['terms'] as $term ) {
$children = array_merge( $children, get_term_children( $term, $query['taxonomy'] ) );
$query['terms'] = $children;
$this->transform_query( $query, 'term_taxonomy_id' );
* Transforms a single query, from one field to another.
* Operates on the `$query` object by reference. In the case of error,
* `$query` is converted to a WP_Error object.
* @param array $query The single query. Passed by reference.
* @param string $resulting_field The resulting field. Accepts 'slug', 'name', 'term_taxonomy_id',
* or 'term_id'. Default 'term_id'.
public function transform_query( &$query, $resulting_field ) {
if ( empty( $query['terms'] ) ) {
if ( $query['field'] === $resulting_field ) {
$resulting_field = sanitize_key( $resulting_field );
// Empty 'terms' always results in a null transformation.
$terms = array_filter( $query['terms'] );
$query['terms'] = array();
$query['field'] = $resulting_field;
'taxonomy' => $query['taxonomy'],
'update_term_meta_cache' => false,
// Term query parameter name depends on the 'field' being searched on.
switch ( $query['field'] ) {
$args['term_taxonomy_id'] = $terms;
$args['include'] = wp_parse_id_list( $terms );
if ( ! is_taxonomy_hierarchical( $query['taxonomy'] ) ) {
$args['number'] = count( $terms );
$term_query = new WP_Term_Query();
$term_list = $term_query->query( $args );
if ( is_wp_error( $term_list ) ) {
if ( 'AND' === $query['operator'] && count( $term_list ) < count( $query['terms'] ) ) {
$query = new WP_Error( 'inexistent_terms', __( 'Inexistent terms.' ) );
$query['terms'] = wp_list_pluck( $term_list, $resulting_field );
$query['field'] = $resulting_field;