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 |
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 |
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 |