X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/af50974463450c98503e763a7836a50e260461a9..53f4633144ed68c8b8fb5861f992b5489894a940:/wp-includes/meta.php diff --git a/wp-includes/meta.php b/wp-includes/meta.php index 1637413d..a0700b07 100644 --- a/wp-includes/meta.php +++ b/wp-includes/meta.php @@ -18,14 +18,15 @@ * * @global wpdb $wpdb WordPress database abstraction object. * - * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) - * @param int $object_id ID of the object metadata is for - * @param string $meta_key Metadata key - * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. - * @param bool $unique Optional, default is false. Whether the specified metadata key should be - * unique for the object. If true, and the object already has a value for the specified - * metadata key, no change will be made - * @return int|bool The meta ID on success, false on failure. + * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) + * @param int $object_id ID of the object metadata is for + * @param string $meta_key Metadata key + * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. + * @param bool $unique Optional, default is false. + * Whether the specified metadata key should be unique for the object. + * If true, and the object already has a value for the specified metadata key, + * no change will be made. + * @return int|false The meta ID on success, false on failure. */ function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) { global $wpdb; @@ -132,12 +133,12 @@ function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = * * @global wpdb $wpdb WordPress database abstraction object. * - * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) - * @param int $object_id ID of the object metadata is for - * @param string $meta_key Metadata key - * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. - * @param mixed $prev_value Optional. If specified, only update existing metadata entries with - * the specified value. Otherwise, update all entries. + * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) + * @param int $object_id ID of the object metadata is for + * @param string $meta_key Metadata key + * @param mixed $meta_value Metadata value. Must be serializable if non-scalar. + * @param mixed $prev_value Optional. If specified, only update existing metadata entries with + * the specified value. Otherwise, update all entries. * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure. */ function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') { @@ -294,14 +295,17 @@ function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_v * * @global wpdb $wpdb WordPress database abstraction object. * - * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) - * @param int $object_id ID of the object metadata is for - * @param string $meta_key Metadata key - * @param mixed $meta_value Optional. Metadata value. Must be serializable if non-scalar. If specified, only delete metadata entries - * with this value. Otherwise, delete all entries with the specified meta_key. - * @param bool $delete_all Optional, default is false. If true, delete matching metadata entries - * for all objects, ignoring the specified object_id. Otherwise, only delete matching - * metadata entries for the specified object_id. + * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) + * @param int $object_id ID of the object metadata is for + * @param string $meta_key Metadata key + * @param mixed $meta_value Optional. Metadata value. Must be serializable if non-scalar. If specified, only delete + * metadata entries with this value. Otherwise, delete all entries with the specified meta_key. + * Pass `null, `false`, or an empty string to skip this check. (For backward compatibility, + * it is not possible to pass an empty string to delete those entries with an empty string + * for a value.) + * @param bool $delete_all Optional, default is false. If true, delete matching metadata entries for all objects, + * ignoring the specified object_id. Otherwise, only delete matching metadata entries for + * the specified object_id. * @return bool True on successful delete, false on failure. */ function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) { @@ -356,7 +360,7 @@ function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $d if ( !$delete_all ) $query .= $wpdb->prepare(" AND $type_column = %d", $object_id ); - if ( $meta_value ) + if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value ); $meta_ids = $wpdb->get_col( $query ); @@ -444,12 +448,13 @@ function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $d * @since 2.9.0 * * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) - * @param int $object_id ID of the object metadata is for - * @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for - * the specified object. - * @param bool $single Optional, default is false. If true, return only the first value of the - * specified meta_key. This parameter has no effect if meta_key is not specified. - * @return string|array Single metadata value, or array of values + * @param int $object_id ID of the object metadata is for + * @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for + * the specified object. + * @param bool $single Optional, default is false. + * If true, return only the first value of the specified meta_key. + * This parameter has no effect if meta_key is not specified. + * @return mixed Single metadata value, or array of values */ function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) { if ( ! $meta_type || ! is_numeric( $object_id ) ) { @@ -515,9 +520,9 @@ function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) { * @since 3.3.0 * * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) - * @param int $object_id ID of the object metadata is for - * @param string $meta_key Metadata key. - * @return boolean true of the key is set, false if not. + * @param int $object_id ID of the object metadata is for + * @param string $meta_key Metadata key. + * @return bool True of the key is set, false if not. */ function metadata_exists( $meta_type, $object_id, $meta_key ) { if ( ! $meta_type || ! is_numeric( $object_id ) ) { @@ -552,9 +557,11 @@ function metadata_exists( $meta_type, $object_id, $meta_key ) { * * @since 3.3.0 * + * @global wpdb $wpdb + * * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) - * @param int $meta_id ID for a specific meta row - * @return object Meta object or false. + * @param int $meta_id ID for a specific meta row + * @return object|false Meta object or false. */ function get_metadata_by_mid( $meta_type, $meta_id ) { global $wpdb; @@ -591,10 +598,12 @@ function get_metadata_by_mid( $meta_type, $meta_id ) { * * @since 3.3.0 * - * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) - * @param int $meta_id ID for a specific meta row + * @global wpdb $wpdb + * + * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) + * @param int $meta_id ID for a specific meta row * @param string $meta_value Metadata value - * @param string $meta_key Optional, you can provide a meta key to update it + * @param string $meta_key Optional, you can provide a meta key to update it * @return bool True on successful update, false on failure. */ function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) { @@ -682,8 +691,10 @@ function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = * * @since 3.3.0 * + * @global wpdb $wpdb + * * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) - * @param int $meta_id ID for a specific meta row + * @param int $meta_id ID for a specific meta row * @return bool True on successful delete, false on failure. */ function delete_metadata_by_mid( $meta_type, $meta_id ) { @@ -769,9 +780,9 @@ function delete_metadata_by_mid( $meta_type, $meta_id ) { * * @global wpdb $wpdb WordPress database abstraction object. * - * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) - * @param int|array $object_ids array or comma delimited list of object IDs to update cache for - * @return mixed Metadata cache for the specified objects, or false on failure. + * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) + * @param int|array $object_ids Array or comma delimited list of object IDs to update cache for + * @return array|false Metadata cache for the specified objects, or false on failure. */ function update_meta_cache($meta_type, $object_ids) { global $wpdb; @@ -933,14 +944,35 @@ class WP_Meta_Query { */ protected $table_aliases = array(); + /** + * A flat list of clauses, keyed by clause 'name'. + * + * @since 4.2.0 + * @access protected + * @var array + */ + protected $clauses = array(); + + /** + * Whether the query contains any OR relations. + * + * @since 4.3.0 + * @access protected + * @var bool + */ + protected $has_or_relation = false; + /** * Constructor. * * @since 3.2.0 + * @since 4.2.0 Introduced support for naming query clauses by associative array keys. + * * @access public * * @param array $meta_query { - * Array of meta query clauses. + * Array of meta query clauses. When first-order clauses use strings as their array keys, they may be + * referenced in the 'orderby' parameter of the parent query. * * @type string $relation Optional. The MySQL keyword used to join * the clauses of the query. Accepts 'AND', or 'OR'. Default 'AND'. @@ -995,23 +1027,23 @@ class WP_Meta_Query { if ( 'relation' === $key ) { $relation = $query; - } else if ( ! is_array( $query ) ) { + } elseif ( ! is_array( $query ) ) { continue; // First-order clause. - } else if ( $this->is_first_order_clause( $query ) ) { + } elseif ( $this->is_first_order_clause( $query ) ) { if ( isset( $query['value'] ) && array() === $query['value'] ) { unset( $query['value'] ); } - $clean_queries[] = $query; + $clean_queries[ $key ] = $query; // Otherwise, it's a nested query, so we recurse. } else { $cleaned_query = $this->sanitize_query( $query ); if ( ! empty( $cleaned_query ) ) { - $clean_queries[] = $cleaned_query; + $clean_queries[ $key ] = $cleaned_query; } } } @@ -1023,13 +1055,14 @@ class WP_Meta_Query { // Sanitize the 'relation' key provided in the query. if ( isset( $relation ) && 'OR' === strtoupper( $relation ) ) { $clean_queries['relation'] = 'OR'; + $this->has_or_relation = true; /* * If there is only a single clause, call the relation 'OR'. * This value will not actually be used to join clauses, but it * simplifies the logic around combining key-only queries. */ - } else if ( 1 === count( $clean_queries ) ) { + } elseif ( 1 === count( $clean_queries ) ) { $clean_queries['relation'] = 'OR'; // Default to AND. @@ -1093,11 +1126,11 @@ class WP_Meta_Query { $primary_meta_query, $existing_meta_query, ); - } else if ( ! empty( $primary_meta_query ) ) { + } elseif ( ! empty( $primary_meta_query ) ) { $meta_query = array( $primary_meta_query, ); - } else if ( ! empty( $existing_meta_query ) ) { + } elseif ( ! empty( $existing_meta_query ) ) { $meta_query = $existing_meta_query; } @@ -1138,7 +1171,7 @@ class WP_Meta_Query { * @param string $primary_table Database table where the object being filtered is stored (eg wp_users). * @param string $primary_id_column ID column for the filtered object in $primary_table. * @param object $context Optional. The main query object. - * @return array { + * @return false|array { * Array containing JOIN and WHERE SQL clauses to append to the main query. * * @type string $join SQL fragment to append to the main JOIN clause. @@ -1146,8 +1179,6 @@ class WP_Meta_Query { * } */ public function get_sql( $type, $primary_table, $primary_id_column, $context = null ) { - global $wpdb; - if ( ! $meta_table = _get_meta_table( $type ) ) { return false; } @@ -1256,16 +1287,16 @@ class WP_Meta_Query { foreach ( $query as $key => &$clause ) { if ( 'relation' === $key ) { $relation = $query['relation']; - } else if ( is_array( $clause ) ) { + } elseif ( is_array( $clause ) ) { // This is a first-order clause. if ( $this->is_first_order_clause( $clause ) ) { - $clause_sql = $this->get_sql_for_clause( $clause, $query ); + $clause_sql = $this->get_sql_for_clause( $clause, $query, $key ); $where_count = count( $clause_sql['where'] ); if ( ! $where_count ) { $sql_chunks['where'][] = ''; - } else if ( 1 === $where_count ) { + } elseif ( 1 === $where_count ) { $sql_chunks['where'][] = $clause_sql['where'][0]; } else { $sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )'; @@ -1311,8 +1342,12 @@ class WP_Meta_Query { * @since 4.1.0 * @access public * - * @param array $clause Query clause, passed by reference. - * @param array $parent_query Parent query array. + * @global wpdb $wpdb + * + * @param array $clause Query clause, passed by reference. + * @param array $parent_query Parent query array. + * @param string $clause_key Optional. The array key used to name the clause in the original `$meta_query` + * parameters. If not provided, a key will be generated automatically. * @return array { * Array containing JOIN and WHERE SQL clauses to append to a first-order query. * @@ -1320,7 +1355,7 @@ class WP_Meta_Query { * @type string $where SQL fragment to append to the main WHERE clause. * } */ - public function get_sql_for_clause( &$clause, $parent_query ) { + public function get_sql_for_clause( &$clause, $parent_query, $clause_key = '' ) { global $wpdb; $sql_chunks = array( @@ -1376,6 +1411,27 @@ class WP_Meta_Query { // Save the alias to this clause, for future siblings to find. $clause['alias'] = $alias; + // Determine the data type. + $_meta_type = isset( $clause['type'] ) ? $clause['type'] : ''; + $meta_type = $this->get_cast_for_type( $_meta_type ); + $clause['cast'] = $meta_type; + + // Fallback for clause keys is the table alias. + if ( ! $clause_key ) { + $clause_key = $clause['alias']; + } + + // Ensure unique clause keys, so none are overwritten. + $iterator = 1; + $clause_key_base = $clause_key; + while ( isset( $this->clauses[ $clause_key ] ) ) { + $clause_key = $clause_key_base . '-' . $iterator; + $iterator++; + } + + // Store the clause in our flat array. + $this->clauses[ $clause_key ] =& $clause; + // Next, build the WHERE clause. // meta_key. @@ -1390,7 +1446,6 @@ class WP_Meta_Query { // meta_value. if ( array_key_exists( 'value', $clause ) ) { $meta_value = $clause['value']; - $meta_type = $this->get_cast_for_type( isset( $clause['type'] ) ? $clause['type'] : '' ); if ( in_array( $meta_compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) { if ( ! is_array( $meta_value ) ) { @@ -1452,6 +1507,21 @@ class WP_Meta_Query { return $sql_chunks; } + /** + * Get a flattened list of sanitized meta clauses. + * + * This array should be used for clause lookup, as when the table alias and CAST type must be determined for + * a value of 'orderby' corresponding to a meta clause. + * + * @since 4.2.0 + * @access public + * + * @return array Meta clauses. + */ + public function get_clauses() { + return $this->clauses; + } + /** * Identify an existing table alias that is compatible with the current * query clause. @@ -1494,7 +1564,7 @@ class WP_Meta_Query { $compatible_compares = array( '=', 'IN', 'BETWEEN', 'LIKE', 'REGEXP', 'RLIKE', '>', '>=', '<', '<=' ); // Clauses joined by AND with "negative" operators share a join only if they also share a key. - } else if ( isset( $sibling['key'] ) && isset( $clause['key'] ) && $sibling['key'] === $clause['key'] ) { + } elseif ( isset( $sibling['key'] ) && isset( $clause['key'] ) && $sibling['key'] === $clause['key'] ) { $compatible_compares = array( '!=', 'NOT IN', 'NOT LIKE' ); } @@ -1518,6 +1588,21 @@ class WP_Meta_Query { */ return apply_filters( 'meta_query_find_compatible_table_alias', $alias, $clause, $parent_query, $this ) ; } + + /** + * Checks whether the current query has any OR relations. + * + * In some cases, the presence of an OR relation somewhere in the query will require + * the use of a `DISTINCT` or `GROUP BY` keyword in the `SELECT` clause. The current + * method can be used in these cases to determine whether such a clause is necessary. + * + * @since 4.3.0 + * + * @return bool True if the query contains any `OR` relations, otherwise false. + */ + public function has_or_relation() { + return $this->has_or_relation; + } } /** @@ -1528,7 +1613,7 @@ class WP_Meta_Query { * @global wpdb $wpdb WordPress database abstraction object. * * @param string $type Type of object to get metadata table for (e.g., comment, post, or user) - * @return mixed Metadata table name, or false if no metadata table exists + * @return string|false Metadata table name, or false if no metadata table exists */ function _get_meta_table($type) { global $wpdb; @@ -1570,9 +1655,9 @@ function is_protected_meta( $meta_key, $meta_type = null ) { * * @since 3.1.3 * - * @param string $meta_key Meta key - * @param mixed $meta_value Meta value to sanitize - * @param string $meta_type Type of meta + * @param string $meta_key Meta key + * @param mixed $meta_value Meta value to sanitize + * @param string $meta_type Type of meta * @return mixed Sanitized $meta_value */ function sanitize_meta( $meta_key, $meta_value, $meta_type ) { @@ -1599,10 +1684,10 @@ function sanitize_meta( $meta_key, $meta_value, $meta_type ) { * * @since 3.3.0 * - * @param string $meta_type Type of meta - * @param string $meta_key Meta key + * @param string $meta_type Type of meta + * @param string $meta_key Meta key * @param string|array $sanitize_callback A function or method to call when sanitizing the value of $meta_key. - * @param string|array $auth_callback Optional. A function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks. + * @param string|array $auth_callback Optional. A function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks. */ function register_meta( $meta_type, $meta_key, $sanitize_callback, $auth_callback = null ) { if ( is_callable( $sanitize_callback ) )