web/wp-includes/meta.php
changeset 194 32102edaa81b
parent 136 bde1974c263b
child 204 09a1c134465b
equal deleted inserted replaced
193:2f6f6f7551ca 194:32102edaa81b
     1 <?php
     1 <?php
     2 /**
     2 /**
     3  * Meta API
     3  * Metadata API
     4  *
     4  *
     5  * Functions for retrieving and manipulating metadata
     5  * Functions for retrieving and manipulating metadata of various WordPress object types. Metadata
       
     6  * for an object is a represented by a simple key-value pair. Objects may contain multiple
       
     7  * metadata entries that share the same key and differ only in their value.
     6  *
     8  *
     7  * @package WordPress
     9  * @package WordPress
     8  * @subpackage Meta
    10  * @subpackage Meta
     9  * @since 2.9.0
    11  * @since 2.9.0
    10  */
    12  */
    11 
    13 
       
    14 /**
       
    15  * Add metadata for the specified object.
       
    16  *
       
    17  * @since 2.9.0
       
    18  * @uses $wpdb WordPress database object for queries.
       
    19  * @uses do_action() Calls 'added_{$meta_type}_meta' with meta_id of added metadata entry,
       
    20  * 		object ID, meta key, and meta value
       
    21  *
       
    22  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
       
    23  * @param int $object_id ID of the object metadata is for
       
    24  * @param string $meta_key Metadata key
       
    25  * @param string $meta_value Metadata value
       
    26  * @param bool $unique Optional, default is false. Whether the specified metadata key should be
       
    27  * 		unique for the object. If true, and the object already has a value for the specified
       
    28  * 		metadata key, no change will be made
       
    29  * @return bool The meta ID on successful update, false on failure.
       
    30  */
    12 function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) {
    31 function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) {
    13 	if ( !$meta_type || !$meta_key )
    32 	if ( !$meta_type || !$meta_key )
    14 		return false;
    33 		return false;
    15 
    34 
       
    35 	if ( !$object_id = absint($object_id) )
       
    36 		return false;
       
    37 
    16 	if ( ! $table = _get_meta_table($meta_type) )
    38 	if ( ! $table = _get_meta_table($meta_type) )
    17 		return false;
    39 		return false;
    18 
    40 
    19 	global $wpdb;
    41 	global $wpdb;
    20 
    42 
    21 	$column = esc_sql($meta_type . '_id');
    43 	$column = esc_sql($meta_type . '_id');
    22 
    44 
    23 	// expected_slashed ($meta_key)
    45 	// expected_slashed ($meta_key)
    24 	$meta_key = stripslashes($meta_key);
    46 	$meta_key = stripslashes($meta_key);
       
    47 	$meta_value = stripslashes_deep($meta_value);
       
    48 	$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
       
    49 
       
    50 	$check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique );
       
    51 	if ( null !== $check )
       
    52 		return $check;
    25 
    53 
    26 	if ( $unique && $wpdb->get_var( $wpdb->prepare(
    54 	if ( $unique && $wpdb->get_var( $wpdb->prepare(
    27 		"SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d",
    55 		"SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d",
    28 		$meta_key, $object_id ) ) )
    56 		$meta_key, $object_id ) ) )
    29 		return false;
    57 		return false;
    30 
    58 
    31 	$meta_value = maybe_serialize( stripslashes_deep($meta_value) );
    59 	$_meta_value = $meta_value;
    32 
    60 	$meta_value = maybe_serialize( $meta_value );
    33 	$wpdb->insert( $table, array(
    61 
       
    62 	do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value );
       
    63 
       
    64 	$result = $wpdb->insert( $table, array(
    34 		$column => $object_id,
    65 		$column => $object_id,
    35 		'meta_key' => $meta_key,
    66 		'meta_key' => $meta_key,
    36 		'meta_value' => $meta_value
    67 		'meta_value' => $meta_value
    37 	) );
    68 	) );
    38 
    69 
       
    70 	if ( ! $result )
       
    71 		return false;
       
    72 
       
    73 	$mid = (int) $wpdb->insert_id;
       
    74 
    39 	wp_cache_delete($object_id, $meta_type . '_meta');
    75 	wp_cache_delete($object_id, $meta_type . '_meta');
    40 
    76 
    41 	do_action( "added_{$meta_type}_meta", $wpdb->insert_id, $object_id, $meta_key, $meta_value );
    77 	do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value );
    42 
    78 
    43 	return true;
    79 	return $mid;
    44 }
    80 }
    45 
    81 
       
    82 /**
       
    83  * Update metadata for the specified object. If no value already exists for the specified object
       
    84  * ID and metadata key, the metadata will be added.
       
    85  *
       
    86  * @since 2.9.0
       
    87  * @uses $wpdb WordPress database object for queries.
       
    88  * @uses do_action() Calls 'update_{$meta_type}_meta' before updating metadata with meta_id of
       
    89  * 		metadata entry to update, object ID, meta key, and meta value
       
    90  * @uses do_action() Calls 'updated_{$meta_type}_meta' after updating metadata with meta_id of
       
    91  * 		updated metadata entry, object ID, meta key, and meta value
       
    92  *
       
    93  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
       
    94  * @param int $object_id ID of the object metadata is for
       
    95  * @param string $meta_key Metadata key
       
    96  * @param string $meta_value Metadata value
       
    97  * @param string $prev_value Optional. If specified, only update existing metadata entries with
       
    98  * 		the specified value. Otherwise, update all entries.
       
    99  * @return bool True on successful update, false on failure.
       
   100  */
    46 function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') {
   101 function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') {
    47 	if ( !$meta_type || !$meta_key )
   102 	if ( !$meta_type || !$meta_key )
    48 		return false;
   103 		return false;
    49 
   104 
       
   105 	if ( !$object_id = absint($object_id) )
       
   106 		return false;
       
   107 
    50 	if ( ! $table = _get_meta_table($meta_type) )
   108 	if ( ! $table = _get_meta_table($meta_type) )
    51 		return false;
   109 		return false;
    52 
   110 
    53 	global $wpdb;
   111 	global $wpdb;
    54 
   112 
    55 	$column = esc_sql($meta_type . '_id');
   113 	$column = esc_sql($meta_type . '_id');
    56 	$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
   114 	$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
    57 
   115 
    58 	// expected_slashed ($meta_key)
   116 	// expected_slashed ($meta_key)
    59 	$meta_key = stripslashes($meta_key);
   117 	$meta_key = stripslashes($meta_key);
       
   118 	$passed_value = $meta_value;
       
   119 	$meta_value = stripslashes_deep($meta_value);
       
   120 	$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
       
   121 
       
   122 	$check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value );
       
   123 	if ( null !== $check )
       
   124 		return (bool) $check;
    60 
   125 
    61 	if ( ! $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) ) )
   126 	if ( ! $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) ) )
    62 		return add_metadata($meta_type, $object_id, $meta_key, $meta_value);
   127 		return add_metadata($meta_type, $object_id, $meta_key, $passed_value);
    63 
   128 
    64 	$meta_value = maybe_serialize( stripslashes_deep($meta_value) );
   129 	// Compare existing value to new value if no prev value given and the key exists only once.
       
   130 	if ( empty($prev_value) ) {
       
   131 		$old_value = get_metadata($meta_type, $object_id, $meta_key);
       
   132 		if ( count($old_value) == 1 ) {
       
   133 			if ( $old_value[0] === $meta_value )
       
   134 				return false;
       
   135 		}
       
   136 	}
       
   137 
       
   138 	$_meta_value = $meta_value;
       
   139 	$meta_value = maybe_serialize( $meta_value );
    65 
   140 
    66 	$data  = compact( 'meta_value' );
   141 	$data  = compact( 'meta_value' );
    67 	$where = array( $column => $object_id, 'meta_key' => $meta_key );
   142 	$where = array( $column => $object_id, 'meta_key' => $meta_key );
    68 
   143 
    69 	if ( !empty( $prev_value ) ) {
   144 	if ( !empty( $prev_value ) ) {
    70 		$prev_value = maybe_serialize($prev_value);
   145 		$prev_value = maybe_serialize($prev_value);
    71 		$where['meta_value'] = $prev_value;
   146 		$where['meta_value'] = $prev_value;
    72 	}
   147 	}
    73 
   148 
    74 	do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $meta_value );
   149 	do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
       
   150 
       
   151 	if ( 'post' == $meta_type )
       
   152 		do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
    75 
   153 
    76 	$wpdb->update( $table, $data, $where );
   154 	$wpdb->update( $table, $data, $where );
       
   155 
    77 	wp_cache_delete($object_id, $meta_type . '_meta');
   156 	wp_cache_delete($object_id, $meta_type . '_meta');
    78 
   157 
    79 	do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $meta_value );
   158 	do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
       
   159 
       
   160 	if ( 'post' == $meta_type )
       
   161 		do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
    80 
   162 
    81 	return true;
   163 	return true;
    82 }
   164 }
    83 
   165 
       
   166 /**
       
   167  * Delete metadata for the specified object.
       
   168  *
       
   169  * @since 2.9.0
       
   170  * @uses $wpdb WordPress database object for queries.
       
   171  * @uses do_action() Calls 'deleted_{$meta_type}_meta' after deleting with meta_id of
       
   172  * 		deleted metadata entries, object ID, meta key, and meta value
       
   173  *
       
   174  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
       
   175  * @param int $object_id ID of the object metadata is for
       
   176  * @param string $meta_key Metadata key
       
   177  * @param string $meta_value Optional. Metadata value. If specified, only delete metadata entries
       
   178  * 		with this value. Otherwise, delete all entries with the specified meta_key.
       
   179  * @param bool $delete_all Optional, default is false. If true, delete matching metadata entries
       
   180  * 		for all objects, ignoring the specified object_id. Otherwise, only delete matching
       
   181  * 		metadata entries for the specified object_id.
       
   182  * @return bool True on successful delete, false on failure.
       
   183  */
    84 function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) {
   184 function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) {
    85 	if ( !$meta_type || !$meta_key || (!$delete_all && ! (int)$object_id) )
   185 	if ( !$meta_type || !$meta_key )
       
   186 		return false;
       
   187 
       
   188 	if ( (!$object_id = absint($object_id)) && !$delete_all )
    86 		return false;
   189 		return false;
    87 
   190 
    88 	if ( ! $table = _get_meta_table($meta_type) )
   191 	if ( ! $table = _get_meta_table($meta_type) )
    89 		return false;
   192 		return false;
    90 
   193 
    92 
   195 
    93 	$type_column = esc_sql($meta_type . '_id');
   196 	$type_column = esc_sql($meta_type . '_id');
    94 	$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
   197 	$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
    95 	// expected_slashed ($meta_key)
   198 	// expected_slashed ($meta_key)
    96 	$meta_key = stripslashes($meta_key);
   199 	$meta_key = stripslashes($meta_key);
    97 	$meta_value = maybe_serialize( stripslashes_deep($meta_value) );
   200 	$meta_value = stripslashes_deep($meta_value);
       
   201 
       
   202 	$check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all );
       
   203 	if ( null !== $check )
       
   204 		return (bool) $check;
       
   205 
       
   206 	$_meta_value = $meta_value;
       
   207 	$meta_value = maybe_serialize( $meta_value );
    98 
   208 
    99 	$query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key );
   209 	$query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key );
   100 
   210 
   101 	if ( !$delete_all )
   211 	if ( !$delete_all )
   102 		$query .= $wpdb->prepare(" AND $type_column = %d", $object_id );
   212 		$query .= $wpdb->prepare(" AND $type_column = %d", $object_id );
   106 
   216 
   107 	$meta_ids = $wpdb->get_col( $query );
   217 	$meta_ids = $wpdb->get_col( $query );
   108 	if ( !count( $meta_ids ) )
   218 	if ( !count( $meta_ids ) )
   109 		return false;
   219 		return false;
   110 
   220 
       
   221 	if ( $delete_all )
       
   222 		$object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) );
       
   223 
       
   224 	do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
       
   225 
       
   226 	// Old-style action.
       
   227 	if ( 'post' == $meta_type )
       
   228 		do_action( 'delete_postmeta', $meta_ids );
       
   229 
   111 	$query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . " )";
   230 	$query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . " )";
   112 
   231 
   113 	$count = $wpdb->query($query);
   232 	$count = $wpdb->query($query);
   114 
   233 
   115 	if ( !$count )
   234 	if ( !$count )
   116 		return false;
   235 		return false;
   117 
   236 
   118 	wp_cache_delete($object_id, $meta_type . '_meta');
   237 	if ( $delete_all ) {
   119 
   238 		foreach ( (array) $object_ids as $o_id ) {
   120 	do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $meta_value );
   239 			wp_cache_delete($o_id, $meta_type . '_meta');
       
   240 		}
       
   241 	} else {
       
   242 		wp_cache_delete($object_id, $meta_type . '_meta');
       
   243 	}
       
   244 
       
   245 	do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
       
   246 
       
   247 	// Old-style action.
       
   248 	if ( 'post' == $meta_type )
       
   249 		do_action( 'deleted_postmeta', $meta_ids );
   121 
   250 
   122 	return true;
   251 	return true;
   123 }
   252 }
   124 
   253 
       
   254 /**
       
   255  * Retrieve metadata for the specified object.
       
   256  *
       
   257  * @since 2.9.0
       
   258  *
       
   259  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
       
   260  * @param int $object_id ID of the object metadata is for
       
   261  * @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for
       
   262  * 		the specified object.
       
   263  * @param bool $single Optional, default is false. If true, return only the first value of the
       
   264  * 		specified meta_key. This parameter has no effect if meta_key is not specified.
       
   265  * @return string|array Single metadata value, or array of values
       
   266  */
   125 function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) {
   267 function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) {
   126 	if ( !$meta_type )
   268 	if ( !$meta_type )
   127 		return false;
   269 		return false;
   128 
   270 
       
   271 	if ( !$object_id = absint($object_id) )
       
   272 		return false;
       
   273 
       
   274 	$check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single );
       
   275 	if ( null !== $check ) {
       
   276 		if ( $single && is_array( $check ) )
       
   277 			return $check[0];
       
   278 		else
       
   279 			return $check;
       
   280 	}
       
   281 
   129 	$meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
   282 	$meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
   130 
   283 
   131 	if ( !$meta_cache ) {
   284 	if ( !$meta_cache ) {
   132 		update_meta_cache($meta_type, $object_id);
   285 		$meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
   133 		$meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
   286 		$meta_cache = $meta_cache[$object_id];
   134 	}
   287 	}
   135 
   288 
   136 	if ( ! $meta_key )
   289 	if ( !$meta_key )
   137 		return $meta_cache;
   290 		return $meta_cache;
   138 
   291 
   139 	if ( isset($meta_cache[$meta_key]) ) {
   292 	if ( isset($meta_cache[$meta_key]) ) {
   140 		if ( $single ) {
   293 		if ( $single )
   141 			return maybe_unserialize( $meta_cache[$meta_key][0] );
   294 			return maybe_unserialize( $meta_cache[$meta_key][0] );
   142 		} else {
   295 		else
   143 			return array_map('maybe_unserialize', $meta_cache[$meta_key]);
   296 			return array_map('maybe_unserialize', $meta_cache[$meta_key]);
   144 		}
       
   145 	}
   297 	}
   146 
   298 
   147 	if ($single)
   299 	if ($single)
   148 		return '';
   300 		return '';
   149 	else
   301 	else
   150 		return array();
   302 		return array();
   151 }
   303 }
   152 
   304 
       
   305 /**
       
   306  * Determine if a meta key is set for a given object
       
   307  *
       
   308  * @since 3.3.0
       
   309  *
       
   310  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
       
   311  * @param int $object_id ID of the object metadata is for
       
   312  * @param string $meta_key Metadata key.
       
   313  * @return boolean true of the key is set, false if not.
       
   314  */
       
   315 function metadata_exists( $meta_type, $object_id, $meta_key ) {
       
   316 	if ( ! $meta_type )
       
   317 		return false;
       
   318 
       
   319 	if ( ! $object_id = absint( $object_id ) )
       
   320 		return false;
       
   321 
       
   322 	$check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true );
       
   323 	if ( null !== $check )
       
   324 		return true;
       
   325 
       
   326 	$meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' );
       
   327 
       
   328 	if ( !$meta_cache ) {
       
   329 		$meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
       
   330 		$meta_cache = $meta_cache[$object_id];
       
   331 	}
       
   332 
       
   333 	if ( isset( $meta_cache[ $meta_key ] ) )
       
   334 		return true;
       
   335 
       
   336 	return false;
       
   337 }
       
   338 
       
   339 /**
       
   340  * Get meta data by meta ID
       
   341  *
       
   342  * @since 3.3.0
       
   343  *
       
   344  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
       
   345  * @param int $meta_id ID for a specific meta row
       
   346  * @return object Meta object or false.
       
   347  */
       
   348 function get_metadata_by_mid( $meta_type, $meta_id ) {
       
   349 	global $wpdb;
       
   350 
       
   351 	if ( ! $meta_type )
       
   352 		return false;
       
   353 
       
   354 	if ( !$meta_id = absint( $meta_id ) )
       
   355 		return false;
       
   356 
       
   357 	if ( ! $table = _get_meta_table($meta_type) )
       
   358 		return false;
       
   359 
       
   360 	$id_column = ( 'user' == $meta_type ) ? 'umeta_id' : 'meta_id';
       
   361 
       
   362 	$meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) );
       
   363 
       
   364 	if ( empty( $meta ) )
       
   365 		return false;
       
   366 
       
   367 	if ( isset( $meta->meta_value ) )
       
   368 		$meta->meta_value = maybe_unserialize( $meta->meta_value );
       
   369 
       
   370 	return $meta;
       
   371 }
       
   372 
       
   373 /**
       
   374  * Update meta data by meta ID
       
   375  *
       
   376  * @since 3.3.0
       
   377  *
       
   378  * @uses get_metadata_by_mid() Calls get_metadata_by_mid() to fetch the meta key, value
       
   379  *		and object_id of the given meta_id.
       
   380  *
       
   381  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
       
   382  * @param int $meta_id ID for a specific meta row
       
   383  * @param string $meta_value Metadata value
       
   384  * @param string $meta_key Optional, you can provide a meta key to update it
       
   385  * @return bool True on successful update, false on failure.
       
   386  */
       
   387 function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) {
       
   388 	global $wpdb;
       
   389 
       
   390 	// Make sure everything is valid.
       
   391 	if ( ! $meta_type )
       
   392 		return false;
       
   393 
       
   394 	if ( ! $meta_id = absint( $meta_id ) )
       
   395 		return false;
       
   396 
       
   397 	if ( ! $table = _get_meta_table( $meta_type ) )
       
   398 		return false;
       
   399 
       
   400 	$column = esc_sql($meta_type . '_id');
       
   401 	$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
       
   402 
       
   403 	// Fetch the meta and go on if it's found.
       
   404 	if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
       
   405 		$original_key = $meta->meta_key;
       
   406 		$original_value = $meta->meta_value;
       
   407 		$object_id = $meta->{$column};
       
   408 
       
   409 		// If a new meta_key (last parameter) was specified, change the meta key,
       
   410 		// otherwise use the original key in the update statement.
       
   411 		if ( false === $meta_key ) {
       
   412 			$meta_key = $original_key;
       
   413 		} elseif ( ! is_string( $meta_key ) ) {
       
   414 			return false;
       
   415 		}
       
   416 
       
   417 		// Sanitize the meta
       
   418 		$_meta_value = $meta_value;
       
   419 		$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
       
   420 		$meta_value = maybe_serialize( $meta_value );
       
   421 
       
   422 		// Format the data query arguments.
       
   423 		$data = array(
       
   424 			'meta_key' => $meta_key,
       
   425 			'meta_value' => $meta_value
       
   426 		);
       
   427 
       
   428 		// Format the where query arguments.
       
   429 		$where = array();
       
   430 		$where[$id_column] = $meta_id;
       
   431 
       
   432 		do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
       
   433 
       
   434 		if ( 'post' == $meta_type )
       
   435 			do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
       
   436 
       
   437 		// Run the update query, all fields in $data are %s, $where is a %d.
       
   438 		$result = (bool) $wpdb->update( $table, $data, $where, '%s', '%d' );
       
   439 
       
   440 		// Clear the caches.
       
   441 		wp_cache_delete($object_id, $meta_type . '_meta');
       
   442 
       
   443 		do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
       
   444 
       
   445 		if ( 'post' == $meta_type )
       
   446 			do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
       
   447 
       
   448 		return $result;
       
   449 	}
       
   450 
       
   451 	// And if the meta was not found.
       
   452 	return false;
       
   453 }
       
   454 
       
   455 /**
       
   456  * Delete meta data by meta ID
       
   457  *
       
   458  * @since 3.3.0
       
   459  *
       
   460  * @uses get_metadata_by_mid() Calls get_metadata_by_mid() to fetch the meta key, value
       
   461  *		and object_id of the given meta_id.
       
   462  *
       
   463  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
       
   464  * @param int $meta_id ID for a specific meta row
       
   465  * @return bool True on successful delete, false on failure.
       
   466  */
       
   467 function delete_metadata_by_mid( $meta_type, $meta_id ) {
       
   468 	global $wpdb;
       
   469 
       
   470 	// Make sure everything is valid.
       
   471 	if ( ! $meta_type )
       
   472 		return false;
       
   473 
       
   474 	if ( ! $meta_id = absint( $meta_id ) )
       
   475 		return false;
       
   476 
       
   477 	if ( ! $table = _get_meta_table( $meta_type ) )
       
   478 		return false;
       
   479 
       
   480 	// object and id columns
       
   481 	$column = esc_sql($meta_type . '_id');
       
   482 	$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
       
   483 
       
   484 	// Fetch the meta and go on if it's found.
       
   485 	if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
       
   486 		$object_id = $meta->{$column};
       
   487 
       
   488 		do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
       
   489 
       
   490 		// Old-style action.
       
   491 		if ( 'post' == $meta_type || 'comment' == $meta_type )
       
   492 			do_action( "delete_{$meta_type}meta", $meta_id );
       
   493 
       
   494 		// Run the query, will return true if deleted, false otherwise
       
   495 		$result = (bool) $wpdb->delete( $table, array( $id_column => $meta_id ) );
       
   496 
       
   497 		// Clear the caches.
       
   498 		wp_cache_delete($object_id, $meta_type . '_meta');
       
   499 
       
   500 		do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
       
   501 
       
   502 		// Old-style action.
       
   503 		if ( 'post' == $meta_type || 'comment' == $meta_type )
       
   504 			do_action( "deleted_{$meta_type}meta", $meta_id );
       
   505 
       
   506 		return $result;
       
   507 
       
   508 	}
       
   509 
       
   510 	// Meta id was not found.
       
   511 	return false;
       
   512 }
       
   513 
       
   514 /**
       
   515  * Update the metadata cache for the specified objects.
       
   516  *
       
   517  * @since 2.9.0
       
   518  * @uses $wpdb WordPress database object for queries.
       
   519  *
       
   520  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
       
   521  * @param int|array $object_ids array or comma delimited list of object IDs to update cache for
       
   522  * @return mixed Metadata cache for the specified objects, or false on failure.
       
   523  */
   153 function update_meta_cache($meta_type, $object_ids) {
   524 function update_meta_cache($meta_type, $object_ids) {
   154 	if ( empty( $meta_type ) || empty( $object_ids ) )
   525 	if ( empty( $meta_type ) || empty( $object_ids ) )
   155 		return false;
   526 		return false;
   156 
   527 
   157 	if ( ! $table = _get_meta_table($meta_type) )
   528 	if ( ! $table = _get_meta_table($meta_type) )
   168 
   539 
   169 	$object_ids = array_map('intval', $object_ids);
   540 	$object_ids = array_map('intval', $object_ids);
   170 
   541 
   171 	$cache_key = $meta_type . '_meta';
   542 	$cache_key = $meta_type . '_meta';
   172 	$ids = array();
   543 	$ids = array();
       
   544 	$cache = array();
   173 	foreach ( $object_ids as $id ) {
   545 	foreach ( $object_ids as $id ) {
   174 		if ( false === wp_cache_get($id, $cache_key) )
   546 		$cached_object = wp_cache_get( $id, $cache_key );
       
   547 		if ( false === $cached_object )
   175 			$ids[] = $id;
   548 			$ids[] = $id;
       
   549 		else
       
   550 			$cache[$id] = $cached_object;
   176 	}
   551 	}
   177 
   552 
   178 	if ( empty( $ids ) )
   553 	if ( empty( $ids ) )
   179 		return false;
   554 		return $cache;
   180 
   555 
   181 	// Get meta info
   556 	// Get meta info
   182 	$id_list = join(',', $ids);
   557 	$id_list = join(',', $ids);
   183 	$cache = array();
       
   184 	$meta_list = $wpdb->get_results( $wpdb->prepare("SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list)",
   558 	$meta_list = $wpdb->get_results( $wpdb->prepare("SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list)",
   185 		$meta_type), ARRAY_A );
   559 		$meta_type), ARRAY_A );
   186 
   560 
   187 	if ( !empty($meta_list) ) {
   561 	if ( !empty($meta_list) ) {
   188 		foreach ( $meta_list as $metarow) {
   562 		foreach ( $meta_list as $metarow) {
   202 	}
   576 	}
   203 
   577 
   204 	foreach ( $ids as $id ) {
   578 	foreach ( $ids as $id ) {
   205 		if ( ! isset($cache[$id]) )
   579 		if ( ! isset($cache[$id]) )
   206 			$cache[$id] = array();
   580 			$cache[$id] = array();
   207 	}
   581 		wp_cache_add( $id, $cache[$id], $cache_key );
   208 
   582 	}
   209 	foreach ( array_keys($cache) as $object)
       
   210 		wp_cache_set($object, $cache[$object], $cache_key);
       
   211 
   583 
   212 	return $cache;
   584 	return $cache;
   213 }
   585 }
   214 
   586 
       
   587 /**
       
   588  * Given a meta query, generates SQL clauses to be appended to a main query
       
   589  *
       
   590  * @since 3.2.0
       
   591  *
       
   592  * @see WP_Meta_Query
       
   593  *
       
   594  * @param array $meta_query A meta query
       
   595  * @param string $type Type of meta
       
   596  * @param string $primary_table
       
   597  * @param string $primary_id_column
       
   598  * @param object $context (optional) The main query object
       
   599  * @return array( 'join' => $join_sql, 'where' => $where_sql )
       
   600  */
       
   601 function get_meta_sql( $meta_query, $type, $primary_table, $primary_id_column, $context = null ) {
       
   602 	$meta_query_obj = new WP_Meta_Query( $meta_query );
       
   603 	return $meta_query_obj->get_sql( $type, $primary_table, $primary_id_column, $context );
       
   604 }
       
   605 
       
   606 /**
       
   607  * Container class for a multiple metadata query
       
   608  *
       
   609  * @since 3.2.0
       
   610  */
       
   611 class WP_Meta_Query {
       
   612 	/**
       
   613 	* List of metadata queries. A single query is an associative array:
       
   614 	* - 'key' string The meta key
       
   615 	* - 'value' string|array The meta value
       
   616 	* - 'compare' (optional) string How to compare the key to the value.
       
   617 	*              Possible values: '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'.
       
   618 	*              Default: '='
       
   619 	* - 'type' string (optional) The type of the value.
       
   620 	*              Possible values: 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'.
       
   621 	*              Default: 'CHAR'
       
   622 	*
       
   623 	* @since 3.2.0
       
   624 	* @access public
       
   625 	* @var array
       
   626 	*/
       
   627 	public $queries = array();
       
   628 
       
   629 	/**
       
   630 	 * The relation between the queries. Can be one of 'AND' or 'OR'.
       
   631 	 *
       
   632 	 * @since 3.2.0
       
   633 	 * @access public
       
   634 	 * @var string
       
   635 	 */
       
   636 	public $relation;
       
   637 
       
   638 	/**
       
   639 	 * Constructor
       
   640 	 *
       
   641 	 * @param array $meta_query (optional) A meta query
       
   642 	 */
       
   643 	function __construct( $meta_query = false ) {
       
   644 		if ( !$meta_query )
       
   645 			return;
       
   646 
       
   647 		if ( isset( $meta_query['relation'] ) && strtoupper( $meta_query['relation'] ) == 'OR' ) {
       
   648 			$this->relation = 'OR';
       
   649 		} else {
       
   650 			$this->relation = 'AND';
       
   651 		}
       
   652 
       
   653 		$this->queries = array();
       
   654 
       
   655 		foreach ( $meta_query as $key => $query ) {
       
   656 			if ( ! is_array( $query ) )
       
   657 				continue;
       
   658 
       
   659 			$this->queries[] = $query;
       
   660 		}
       
   661 	}
       
   662 
       
   663 	/**
       
   664 	 * Constructs a meta query based on 'meta_*' query vars
       
   665 	 *
       
   666 	 * @since 3.2.0
       
   667 	 * @access public
       
   668 	 *
       
   669 	 * @param array $qv The query variables
       
   670 	 */
       
   671 	function parse_query_vars( $qv ) {
       
   672 		$meta_query = array();
       
   673 
       
   674 		// Simple query needs to be first for orderby=meta_value to work correctly
       
   675 		foreach ( array( 'key', 'compare', 'type' ) as $key ) {
       
   676 			if ( !empty( $qv[ "meta_$key" ] ) )
       
   677 				$meta_query[0][ $key ] = $qv[ "meta_$key" ];
       
   678 		}
       
   679 
       
   680 		// WP_Query sets 'meta_value' = '' by default
       
   681 		if ( isset( $qv[ 'meta_value' ] ) && '' !== $qv[ 'meta_value' ] )
       
   682 			$meta_query[0]['value'] = $qv[ 'meta_value' ];
       
   683 
       
   684 		if ( !empty( $qv['meta_query'] ) && is_array( $qv['meta_query'] ) ) {
       
   685 			$meta_query = array_merge( $meta_query, $qv['meta_query'] );
       
   686 		}
       
   687 
       
   688 		$this->__construct( $meta_query );
       
   689 	}
       
   690 
       
   691 	/**
       
   692 	 * Generates SQL clauses to be appended to a main query.
       
   693 	 *
       
   694 	 * @since 3.2.0
       
   695 	 * @access public
       
   696 	 *
       
   697 	 * @param string $type Type of meta
       
   698 	 * @param string $primary_table
       
   699 	 * @param string $primary_id_column
       
   700 	 * @param object $context (optional) The main query object
       
   701 	 * @return array( 'join' => $join_sql, 'where' => $where_sql )
       
   702 	 */
       
   703 	function get_sql( $type, $primary_table, $primary_id_column, $context = null ) {
       
   704 		global $wpdb;
       
   705 
       
   706 		if ( ! $meta_table = _get_meta_table( $type ) )
       
   707 			return false;
       
   708 
       
   709 		$meta_id_column = esc_sql( $type . '_id' );
       
   710 
       
   711 		$join = array();
       
   712 		$where = array();
       
   713 
       
   714 		foreach ( $this->queries as $k => $q ) {
       
   715 			$meta_key = isset( $q['key'] ) ? trim( $q['key'] ) : '';
       
   716 			$meta_type = isset( $q['type'] ) ? strtoupper( $q['type'] ) : 'CHAR';
       
   717 
       
   718 			if ( 'NUMERIC' == $meta_type )
       
   719 				$meta_type = 'SIGNED';
       
   720 			elseif ( ! in_array( $meta_type, array( 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED' ) ) )
       
   721 				$meta_type = 'CHAR';
       
   722 
       
   723 			$i = count( $join );
       
   724 			$alias = $i ? 'mt' . $i : $meta_table;
       
   725 
       
   726 			// Set JOIN
       
   727 			$join[$i]  = "INNER JOIN $meta_table";
       
   728 			$join[$i] .= $i ? " AS $alias" : '';
       
   729 			$join[$i] .= " ON ($primary_table.$primary_id_column = $alias.$meta_id_column)";
       
   730 
       
   731 			$where[$k] = '';
       
   732 			if ( !empty( $meta_key ) )
       
   733 				$where[$k] = $wpdb->prepare( "$alias.meta_key = %s", $meta_key );
       
   734 
       
   735 			if ( !isset( $q['value'] ) ) {
       
   736 				if ( empty( $where[$k] ) )
       
   737 					unset( $join[$i] );
       
   738 				continue;
       
   739 			}
       
   740 
       
   741 			$meta_value = $q['value'];
       
   742 
       
   743 			$meta_compare = is_array( $meta_value ) ? 'IN' : '=';
       
   744 			if ( isset( $q['compare'] ) )
       
   745 				$meta_compare = strtoupper( $q['compare'] );
       
   746 
       
   747 			if ( ! in_array( $meta_compare, array( '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) )
       
   748 				$meta_compare = '=';
       
   749 
       
   750 			if ( in_array( $meta_compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) {
       
   751 				if ( ! is_array( $meta_value ) )
       
   752 					$meta_value = preg_split( '/[,\s]+/', $meta_value );
       
   753 
       
   754 				if ( empty( $meta_value ) ) {
       
   755 					unset( $join[$i] );
       
   756 					continue;
       
   757 				}
       
   758 			} else {
       
   759 				$meta_value = trim( $meta_value );
       
   760 			}
       
   761 
       
   762 			if ( 'IN' == substr( $meta_compare, -2) ) {
       
   763 				$meta_compare_string = '(' . substr( str_repeat( ',%s', count( $meta_value ) ), 1 ) . ')';
       
   764 			} elseif ( 'BETWEEN' == substr( $meta_compare, -7) ) {
       
   765 				$meta_value = array_slice( $meta_value, 0, 2 );
       
   766 				$meta_compare_string = '%s AND %s';
       
   767 			} elseif ( 'LIKE' == substr( $meta_compare, -4 ) ) {
       
   768 				$meta_value = '%' . like_escape( $meta_value ) . '%';
       
   769 				$meta_compare_string = '%s';
       
   770 			} else {
       
   771 				$meta_compare_string = '%s';
       
   772 			}
       
   773 
       
   774 			if ( ! empty( $where[$k] ) )
       
   775 				$where[$k] .= ' AND ';
       
   776 
       
   777 			$where[$k] = ' (' . $where[$k] . $wpdb->prepare( "CAST($alias.meta_value AS {$meta_type}) {$meta_compare} {$meta_compare_string})", $meta_value );
       
   778 		}
       
   779 
       
   780 		$where = array_filter( $where );
       
   781 
       
   782 		if ( empty( $where ) )
       
   783 			$where = '';
       
   784 		else
       
   785 			$where = ' AND (' . implode( "\n{$this->relation} ", $where ) . ' )';
       
   786 
       
   787 		$join = implode( "\n", $join );
       
   788 		if ( ! empty( $join ) )
       
   789 			$join = ' ' . $join;
       
   790 
       
   791 		return apply_filters_ref_array( 'get_meta_sql', array( compact( 'join', 'where' ), $this->queries, $type, $primary_table, $primary_id_column, $context ) );
       
   792 	}
       
   793 }
       
   794 
       
   795 /**
       
   796  * Retrieve the name of the metadata table for the specified object type.
       
   797  *
       
   798  * @since 2.9.0
       
   799  * @uses $wpdb WordPress database object for queries.
       
   800  *
       
   801  * @param string $type Type of object to get metadata table for (e.g., comment, post, or user)
       
   802  * @return mixed Metadata table name, or false if no metadata table exists
       
   803  */
   215 function _get_meta_table($type) {
   804 function _get_meta_table($type) {
   216 	global $wpdb;
   805 	global $wpdb;
   217 
   806 
   218 	$table_name = $type . 'meta';
   807 	$table_name = $type . 'meta';
   219 
   808 
   220 	if ( empty($wpdb->$table_name) )
   809 	if ( empty($wpdb->$table_name) )
   221 		return false;
   810 		return false;
   222 
   811 
   223 	return $wpdb->$table_name;
   812 	return $wpdb->$table_name;
   224 }
   813 }
   225 ?>
   814 
       
   815 /**
       
   816  * Determine whether a meta key is protected
       
   817  *
       
   818  * @since 3.1.3
       
   819  *
       
   820  * @param string $meta_key Meta key
       
   821  * @return bool True if the key is protected, false otherwise.
       
   822  */
       
   823 function is_protected_meta( $meta_key, $meta_type = null ) {
       
   824 	$protected = ( '_' == $meta_key[0] );
       
   825 
       
   826 	return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
       
   827 }
       
   828 
       
   829 /**
       
   830  * Sanitize meta value
       
   831  *
       
   832  * @since 3.1.3
       
   833  *
       
   834  * @param string $meta_key Meta key
       
   835  * @param mixed $meta_value Meta value to sanitize
       
   836  * @param string $meta_type Type of meta
       
   837  * @return mixed Sanitized $meta_value
       
   838  */
       
   839 function sanitize_meta( $meta_key, $meta_value, $meta_type ) {
       
   840 	return apply_filters( "sanitize_{$meta_type}_meta_{$meta_key}", $meta_value, $meta_key, $meta_type );
       
   841 }
       
   842 
       
   843 /**
       
   844  * Register meta key
       
   845  *
       
   846  * @since 3.3.0
       
   847  *
       
   848  * @param string $meta_type Type of meta
       
   849  * @param string $meta_key Meta key
       
   850  * @param string|array $sanitize_callback A function or method to call when sanitizing the value of $meta_key.
       
   851  * @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.
       
   852  * @param array $args Arguments
       
   853  */
       
   854 function register_meta( $meta_type, $meta_key, $sanitize_callback, $auth_callback = null ) {
       
   855 	if ( is_callable( $sanitize_callback ) )
       
   856 		add_filter( "sanitize_{$meta_type}_meta_{$meta_key}", $sanitize_callback, 10, 3 );
       
   857 
       
   858 	if ( empty( $auth_callback ) ) {
       
   859 		if ( is_protected_meta( $meta_key, $meta_type ) )
       
   860 			$auth_callback = '__return_false';
       
   861 		else
       
   862 			$auth_callback = '__return_true';
       
   863 	}
       
   864 
       
   865 	if ( is_callable( $auth_callback ) )
       
   866 		add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 );
       
   867 }