wp/wp-includes/class-wp-tax-query.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
    17  * their results by object metadata, by generating `JOIN` and `WHERE` subclauses to be
    17  * their results by object metadata, by generating `JOIN` and `WHERE` subclauses to be
    18  * attached to the primary SQL query string.
    18  * attached to the primary SQL query string.
    19  *
    19  *
    20  * @since 3.1.0
    20  * @since 3.1.0
    21  */
    21  */
       
    22 #[AllowDynamicProperties]
    22 class WP_Tax_Query {
    23 class WP_Tax_Query {
    23 
    24 
    24 	/**
    25 	/**
    25 	 * Array of taxonomy queries.
    26 	 * Array of taxonomy queries.
    26 	 *
    27 	 *
   120 
   121 
   121 		$this->queries = $this->sanitize_query( $tax_query );
   122 		$this->queries = $this->sanitize_query( $tax_query );
   122 	}
   123 	}
   123 
   124 
   124 	/**
   125 	/**
   125 	 * Ensure the 'tax_query' argument passed to the class constructor is well-formed.
   126 	 * Ensures the 'tax_query' argument passed to the class constructor is well-formed.
   126 	 *
   127 	 *
   127 	 * Ensures that each query-level clause has a 'relation' key, and that
   128 	 * Ensures that each query-level clause has a 'relation' key, and that
   128 	 * each first-order clause contains all the necessary keys from `$defaults`.
   129 	 * each first-order clause contains all the necessary keys from `$defaults`.
   129 	 *
   130 	 *
   130 	 * @since 4.1.0
   131 	 * @since 4.1.0
   194 
   195 
   195 		return $cleaned_query;
   196 		return $cleaned_query;
   196 	}
   197 	}
   197 
   198 
   198 	/**
   199 	/**
   199 	 * Sanitize a 'relation' operator.
   200 	 * Sanitizes a 'relation' operator.
   200 	 *
   201 	 *
   201 	 * @since 4.1.0
   202 	 * @since 4.1.0
   202 	 *
   203 	 *
   203 	 * @param string $relation Raw relation key from the query argument.
   204 	 * @param string $relation Raw relation key from the query argument.
   204 	 * @return string Sanitized relation ('AND' or 'OR').
   205 	 * @return string Sanitized relation. Either 'AND' or 'OR'.
   205 	 */
   206 	 */
   206 	public function sanitize_relation( $relation ) {
   207 	public function sanitize_relation( $relation ) {
   207 		if ( 'OR' === strtoupper( $relation ) ) {
   208 		if ( 'OR' === strtoupper( $relation ) ) {
   208 			return 'OR';
   209 			return 'OR';
   209 		} else {
   210 		} else {
   210 			return 'AND';
   211 			return 'AND';
   211 		}
   212 		}
   212 	}
   213 	}
   213 
   214 
   214 	/**
   215 	/**
   215 	 * Determine whether a clause is first-order.
   216 	 * Determines whether a clause is first-order.
   216 	 *
   217 	 *
   217 	 * A "first-order" clause is one that contains any of the first-order
   218 	 * A "first-order" clause is one that contains any of the first-order
   218 	 * clause keys ('terms', 'taxonomy', 'include_children', 'field',
   219 	 * clause keys ('terms', 'taxonomy', 'include_children', 'field',
   219 	 * 'operator'). An empty clause also counts as a first-order clause,
   220 	 * 'operator'). An empty clause also counts as a first-order clause,
   220 	 * for backward compatibility. Any clause that doesn't meet this is
   221 	 * for backward compatibility. Any clause that doesn't meet this is
   249 
   250 
   250 		return $this->get_sql_clauses();
   251 		return $this->get_sql_clauses();
   251 	}
   252 	}
   252 
   253 
   253 	/**
   254 	/**
   254 	 * Generate SQL clauses to be appended to a main query.
   255 	 * Generates SQL clauses to be appended to a main query.
   255 	 *
   256 	 *
   256 	 * Called by the public WP_Tax_Query::get_sql(), this method
   257 	 * Called by the public WP_Tax_Query::get_sql(), this method
   257 	 * is abstracted out to maintain parity with the other Query classes.
   258 	 * is abstracted out to maintain parity with the other Query classes.
   258 	 *
   259 	 *
   259 	 * @since 4.1.0
   260 	 * @since 4.1.0
   279 
   280 
   280 		return $sql;
   281 		return $sql;
   281 	}
   282 	}
   282 
   283 
   283 	/**
   284 	/**
   284 	 * Generate SQL clauses for a single query array.
   285 	 * Generates SQL clauses for a single query array.
   285 	 *
   286 	 *
   286 	 * If nested subqueries are found, this method recurses the tree to
   287 	 * If nested subqueries are found, this method recurses the tree to
   287 	 * produce the properly nested SQL.
   288 	 * produce the properly nested SQL.
   288 	 *
   289 	 *
   289 	 * @since 4.1.0
   290 	 * @since 4.1.0
   363 
   364 
   364 		return $sql;
   365 		return $sql;
   365 	}
   366 	}
   366 
   367 
   367 	/**
   368 	/**
   368 	 * Generate SQL JOIN and WHERE clauses for a "first-order" query clause.
   369 	 * Generates SQL JOIN and WHERE clauses for a "first-order" query clause.
   369 	 *
   370 	 *
   370 	 * @since 4.1.0
   371 	 * @since 4.1.0
   371 	 *
   372 	 *
   372 	 * @global wpdb $wpdb The WordPress database abstraction object.
   373 	 * @global wpdb $wpdb The WordPress database abstraction object.
   373 	 *
   374 	 *
   374 	 * @param array $clause       Query clause (passed by reference).
   375 	 * @param array $clause       Query clause (passed by reference).
   375 	 * @param array $parent_query Parent query array.
   376 	 * @param array $parent_query Parent query array.
   376 	 * @return string[] {
   377 	 * @return array {
   377 	 *     Array containing JOIN and WHERE SQL clauses to append to a first-order query.
   378 	 *     Array containing JOIN and WHERE SQL clauses to append to a first-order query.
   378 	 *
   379 	 *
   379 	 *     @type string $join  SQL fragment to append to the main JOIN clause.
   380 	 *     @type string[] $join  Array of SQL fragments to append to the main JOIN clause.
   380 	 *     @type string $where SQL fragment to append to the main WHERE clause.
   381 	 *     @type string[] $where Array of SQL fragments to append to the main WHERE clause.
   381 	 * }
   382 	 * }
   382 	 */
   383 	 */
   383 	public function get_sql_for_clause( &$clause, $parent_query ) {
   384 	public function get_sql_for_clause( &$clause, $parent_query ) {
   384 		global $wpdb;
   385 		global $wpdb;
   385 
   386 
   463 
   464 
   464 		} elseif ( 'NOT EXISTS' === $operator || 'EXISTS' === $operator ) {
   465 		} elseif ( 'NOT EXISTS' === $operator || 'EXISTS' === $operator ) {
   465 
   466 
   466 			$where = $wpdb->prepare(
   467 			$where = $wpdb->prepare(
   467 				"$operator (
   468 				"$operator (
   468 				SELECT 1
   469 					SELECT 1
   469 				FROM $wpdb->term_relationships
   470 					FROM $wpdb->term_relationships
   470 				INNER JOIN $wpdb->term_taxonomy
   471 					INNER JOIN $wpdb->term_taxonomy
   471 				ON $wpdb->term_taxonomy.term_taxonomy_id = $wpdb->term_relationships.term_taxonomy_id
   472 					ON $wpdb->term_taxonomy.term_taxonomy_id = $wpdb->term_relationships.term_taxonomy_id
   472 				WHERE $wpdb->term_taxonomy.taxonomy = %s
   473 					WHERE $wpdb->term_taxonomy.taxonomy = %s
   473 				AND $wpdb->term_relationships.object_id = $this->primary_table.$this->primary_id_column
   474 					AND $wpdb->term_relationships.object_id = $this->primary_table.$this->primary_id_column
   474 			)",
   475 				)",
   475 				$clause['taxonomy']
   476 				$clause['taxonomy']
   476 			);
   477 			);
   477 
   478 
   478 		}
   479 		}
   479 
   480 
   481 		$sql['where'][] = $where;
   482 		$sql['where'][] = $where;
   482 		return $sql;
   483 		return $sql;
   483 	}
   484 	}
   484 
   485 
   485 	/**
   486 	/**
   486 	 * Identify an existing table alias that is compatible with the current query clause.
   487 	 * Identifies an existing table alias that is compatible with the current query clause.
   487 	 *
   488 	 *
   488 	 * We avoid unnecessary table joins by allowing each clause to look for
   489 	 * We avoid unnecessary table joins by allowing each clause to look for
   489 	 * an existing table alias that is compatible with the query that it
   490 	 * an existing table alias that is compatible with the query that it
   490 	 * needs to perform.
   491 	 * needs to perform.
   491 	 *
   492 	 *
   502 	 * @return string|false Table alias if found, otherwise false.
   503 	 * @return string|false Table alias if found, otherwise false.
   503 	 */
   504 	 */
   504 	protected function find_compatible_table_alias( $clause, $parent_query ) {
   505 	protected function find_compatible_table_alias( $clause, $parent_query ) {
   505 		$alias = false;
   506 		$alias = false;
   506 
   507 
   507 		// Sanity check. Only IN queries use the JOIN syntax.
   508 		// Confidence check. Only IN queries use the JOIN syntax.
   508 		if ( ! isset( $clause['operator'] ) || 'IN' !== $clause['operator'] ) {
   509 		if ( ! isset( $clause['operator'] ) || 'IN' !== $clause['operator'] ) {
   509 			return $alias;
   510 			return $alias;
   510 		}
   511 		}
   511 
   512 
   512 		// Since we're only checking IN queries, we're only concerned with OR relations.
   513 		// Since we're only checking IN queries, we're only concerned with OR relations.
   586 	 * Operates on the `$query` object by reference. In the case of error,
   587 	 * Operates on the `$query` object by reference. In the case of error,
   587 	 * `$query` is converted to a WP_Error object.
   588 	 * `$query` is converted to a WP_Error object.
   588 	 *
   589 	 *
   589 	 * @since 3.2.0
   590 	 * @since 3.2.0
   590 	 *
   591 	 *
   591 	 * @global wpdb $wpdb The WordPress database abstraction object.
       
   592 	 *
       
   593 	 * @param array  $query           The single query. Passed by reference.
   592 	 * @param array  $query           The single query. Passed by reference.
   594 	 * @param string $resulting_field The resulting field. Accepts 'slug', 'name', 'term_taxonomy_id',
   593 	 * @param string $resulting_field The resulting field. Accepts 'slug', 'name', 'term_taxonomy_id',
   595 	 *                                or 'term_id'. Default 'term_id'.
   594 	 *                                or 'term_id'. Default 'term_id'.
   596 	 */
   595 	 */
   597 	public function transform_query( &$query, $resulting_field ) {
   596 	public function transform_query( &$query, $resulting_field ) {
   598 		if ( empty( $query['terms'] ) ) {
   597 		if ( empty( $query['terms'] ) ) {
   599 			return;
   598 			return;
   600 		}
   599 		}
   601 
   600 
   602 		if ( $query['field'] == $resulting_field ) {
   601 		if ( $query['field'] === $resulting_field ) {
   603 			return;
   602 			return;
   604 		}
   603 		}
   605 
   604 
   606 		$resulting_field = sanitize_key( $resulting_field );
   605 		$resulting_field = sanitize_key( $resulting_field );
   607 
   606