]> scripts.mit.edu Git - autoinstalls/wordpress.git/blobdiff - wp-includes/meta.php
WordPress 4.3
[autoinstalls/wordpress.git] / wp-includes / meta.php
index 1637413d7897758f77be6b6d7b00c86dfd9dc77b..a0700b07b4d4938be3726316d626c309723fc767 100644 (file)
  *
  * @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 ) )