2009-09-17 16:17:33 -04:00
< ? php
/**
2015-09-22 09:30:24 -04:00
* Core Metadata API
2009-09-17 16:17:33 -04:00
*
2011-12-13 18:45:31 -05:00
* Functions for retrieving and manipulating metadata of various WordPress object types . Metadata
* for an object is a represented by a simple key - value pair . Objects may contain multiple
2010-01-19 12:08:04 -05:00
* metadata entries that share the same key and differ only in their value .
2009-09-17 16:17:33 -04:00
*
* @ package WordPress
* @ subpackage Meta
2015-11-20 02:24:30 -05:00
*/
/**
* Add metadata for the specified object .
*
* @ since 2.9 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
2018-08-08 17:45:24 -04:00
* @ param string $meta_type Type of object metadata is for ( e . g . , comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
* @ 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 .
*/
2017-11-30 18:11:00 -05:00
function add_metadata ( $meta_type , $object_id , $meta_key , $meta_value , $unique = false ) {
2015-11-20 02:24:30 -05:00
global $wpdb ;
if ( ! $meta_type || ! $meta_key || ! is_numeric ( $object_id ) ) {
return false ;
}
$object_id = absint ( $object_id );
if ( ! $object_id ) {
return false ;
}
$table = _get_meta_table ( $meta_type );
if ( ! $table ) {
return false ;
}
2018-06-27 22:43:21 -04:00
$meta_subtype = get_object_subtype ( $meta_type , $object_id );
2017-11-30 18:11:00 -05:00
$column = sanitize_key ( $meta_type . '_id' );
2015-11-20 02:24:30 -05:00
// expected_slashed ($meta_key)
2017-11-30 18:11:00 -05:00
$meta_key = wp_unslash ( $meta_key );
$meta_value = wp_unslash ( $meta_value );
2018-06-27 22:43:21 -04:00
$meta_value = sanitize_meta ( $meta_key , $meta_value , $meta_type , $meta_subtype );
2015-11-20 02:24:30 -05:00
/**
2016-05-22 14:50:28 -04:00
* Filters whether to add metadata of a specific type .
2015-11-20 02:24:30 -05:00
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
2018-08-08 17:45:24 -04:00
* object type ( comment , post , term , or user ) . Returning a non - null value
2015-11-20 02:24:30 -05:00
* will effectively short - circuit the function .
*
* @ since 3.1 . 0
*
* @ param null | bool $check Whether to allow adding metadata for the given type .
* @ param int $object_id Object ID .
* @ param string $meta_key Meta key .
* @ param mixed $meta_value Meta value . Must be serializable if non - scalar .
* @ param bool $unique Whether the specified meta key should be unique
* for the object . Optional . Default false .
*/
$check = apply_filters ( " add_ { $meta_type } _metadata " , null , $object_id , $meta_key , $meta_value , $unique );
2017-11-30 18:11:00 -05:00
if ( null !== $check ) {
2015-11-20 02:24:30 -05:00
return $check ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
2017-11-30 18:11:00 -05:00
if ( $unique && $wpdb -> get_var (
$wpdb -> prepare (
" SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d " ,
2018-08-16 21:51:36 -04:00
$meta_key ,
$object_id
2017-11-30 18:11:00 -05:00
)
) ) {
2015-11-20 02:24:30 -05:00
return false ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
$_meta_value = $meta_value ;
2017-11-30 18:11:00 -05:00
$meta_value = maybe_serialize ( $meta_value );
2015-11-20 02:24:30 -05:00
/**
* Fires immediately before meta of a specific type is added .
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
2018-08-08 17:45:24 -04:00
* object type ( comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
*
* @ since 3.1 . 0
*
2019-03-27 13:10:53 -04:00
* @ param int $object_id Object ID .
* @ param string $meta_key Meta key .
* @ param mixed $_meta_value Meta value .
2015-11-20 02:24:30 -05:00
*/
do_action ( " add_ { $meta_type } _meta " , $object_id , $meta_key , $_meta_value );
2017-11-30 18:11:00 -05:00
$result = $wpdb -> insert (
2018-08-16 21:51:36 -04:00
$table ,
array (
2017-11-30 18:11:00 -05:00
$column => $object_id ,
'meta_key' => $meta_key ,
'meta_value' => $meta_value ,
)
);
2015-11-20 02:24:30 -05:00
2017-11-30 18:11:00 -05:00
if ( ! $result ) {
2015-11-20 02:24:30 -05:00
return false ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
$mid = ( int ) $wpdb -> insert_id ;
2017-11-30 18:11:00 -05:00
wp_cache_delete ( $object_id , $meta_type . '_meta' );
2015-11-20 02:24:30 -05:00
/**
* Fires immediately after meta of a specific type is added .
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
2018-08-08 17:45:24 -04:00
* object type ( comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
*
* @ since 2.9 . 0
*
2019-03-27 13:10:53 -04:00
* @ param int $mid The meta ID after successful update .
* @ param int $object_id Object ID .
* @ param string $meta_key Meta key .
* @ param mixed $_meta_value Meta value .
2015-11-20 02:24:30 -05:00
*/
do_action ( " added_ { $meta_type } _meta " , $mid , $object_id , $meta_key , $_meta_value );
return $mid ;
}
/**
* Update metadata for the specified object . If no value already exists for the specified object
* ID and metadata key , the metadata will be added .
*
* @ since 2.9 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
2018-08-08 17:45:24 -04:00
* @ param string $meta_type Type of object metadata is for ( e . g . , comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
* @ 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
2017-11-30 18:11:00 -05:00
* the specified value . Otherwise , update all entries .
2018-08-27 10:28:26 -04:00
* @ return int | bool The new meta field ID if a field with the given key didn ' t exist and was
* therefore added , true on successful update , false on failure .
2015-11-20 02:24:30 -05:00
*/
2017-11-30 18:11:00 -05:00
function update_metadata ( $meta_type , $object_id , $meta_key , $meta_value , $prev_value = '' ) {
2015-11-20 02:24:30 -05:00
global $wpdb ;
if ( ! $meta_type || ! $meta_key || ! is_numeric ( $object_id ) ) {
return false ;
}
$object_id = absint ( $object_id );
if ( ! $object_id ) {
return false ;
}
$table = _get_meta_table ( $meta_type );
if ( ! $table ) {
return false ;
}
2018-06-27 22:43:21 -04:00
$meta_subtype = get_object_subtype ( $meta_type , $object_id );
2017-11-30 18:11:00 -05:00
$column = sanitize_key ( $meta_type . '_id' );
2015-11-20 02:24:30 -05:00
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id' ;
// expected_slashed ($meta_key)
2016-02-11 12:35:28 -05:00
$raw_meta_key = $meta_key ;
2017-11-30 18:11:00 -05:00
$meta_key = wp_unslash ( $meta_key );
2015-11-20 02:24:30 -05:00
$passed_value = $meta_value ;
2017-11-30 18:11:00 -05:00
$meta_value = wp_unslash ( $meta_value );
2018-06-27 22:43:21 -04:00
$meta_value = sanitize_meta ( $meta_key , $meta_value , $meta_type , $meta_subtype );
2015-11-20 02:24:30 -05:00
/**
2016-05-22 14:50:28 -04:00
* Filters whether to update metadata of a specific type .
2015-11-20 02:24:30 -05:00
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
2018-08-08 17:45:24 -04:00
* object type ( comment , post , term , or user ) . Returning a non - null value
2015-11-20 02:24:30 -05:00
* will effectively short - circuit the function .
*
* @ since 3.1 . 0
*
* @ param null | bool $check Whether to allow updating metadata for the given type .
* @ param int $object_id Object ID .
* @ param string $meta_key Meta key .
* @ param mixed $meta_value Meta 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 .
*/
$check = apply_filters ( " update_ { $meta_type } _metadata " , null , $object_id , $meta_key , $meta_value , $prev_value );
2017-11-30 18:11:00 -05:00
if ( null !== $check ) {
2015-11-20 02:24:30 -05:00
return ( bool ) $check ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
// Compare existing value to new value if no prev value given and the key exists only once.
2017-11-30 18:11:00 -05:00
if ( empty ( $prev_value ) ) {
$old_value = get_metadata ( $meta_type , $object_id , $meta_key );
if ( count ( $old_value ) == 1 ) {
if ( $old_value [ 0 ] === $meta_value ) {
2015-11-20 02:24:30 -05:00
return false ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
}
}
$meta_ids = $wpdb -> get_col ( $wpdb -> prepare ( " SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d " , $meta_key , $object_id ) );
if ( empty ( $meta_ids ) ) {
2016-02-11 12:35:28 -05:00
return add_metadata ( $meta_type , $object_id , $raw_meta_key , $passed_value );
2015-11-20 02:24:30 -05:00
}
$_meta_value = $meta_value ;
2017-11-30 18:11:00 -05:00
$meta_value = maybe_serialize ( $meta_value );
2015-11-20 02:24:30 -05:00
$data = compact ( 'meta_value' );
2017-11-30 18:11:00 -05:00
$where = array (
$column => $object_id ,
'meta_key' => $meta_key ,
);
2015-11-20 02:24:30 -05:00
2017-11-30 18:11:00 -05:00
if ( ! empty ( $prev_value ) ) {
$prev_value = maybe_serialize ( $prev_value );
2015-11-20 02:24:30 -05:00
$where [ 'meta_value' ] = $prev_value ;
}
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately before updating metadata of a specific type .
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
2018-08-08 17:45:24 -04:00
* object type ( comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
*
* @ since 2.9 . 0
*
2019-03-27 13:10:53 -04:00
* @ param int $meta_id ID of the metadata entry to update .
* @ param int $object_id Object ID .
* @ param string $meta_key Meta key .
* @ param mixed $_meta_value Meta value .
2015-11-20 02:24:30 -05:00
*/
do_action ( " update_ { $meta_type } _meta " , $meta_id , $object_id , $meta_key , $_meta_value );
2016-01-28 23:52:28 -05:00
if ( 'post' == $meta_type ) {
2015-11-20 02:24:30 -05:00
/**
* Fires immediately before updating a post ' s metadata .
*
* @ since 2.9 . 0
*
* @ param int $meta_id ID of metadata entry to update .
2019-03-27 13:10:53 -04:00
* @ param int $object_id Post ID .
2015-11-20 02:24:30 -05:00
* @ param string $meta_key Meta key .
2019-03-27 13:10:53 -04:00
* @ param mixed $meta_value Meta value . This will be a PHP - serialized string representation of the value if
* the value is an array , an object , or itself a PHP - serialized string .
2015-11-20 02:24:30 -05:00
*/
do_action ( 'update_postmeta' , $meta_id , $object_id , $meta_key , $meta_value );
}
}
$result = $wpdb -> update ( $table , $data , $where );
2017-11-30 18:11:00 -05:00
if ( ! $result ) {
2015-11-20 02:24:30 -05:00
return false ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
2017-11-30 18:11:00 -05:00
wp_cache_delete ( $object_id , $meta_type . '_meta' );
2015-11-20 02:24:30 -05:00
foreach ( $meta_ids as $meta_id ) {
/**
* Fires immediately after updating metadata of a specific type .
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
2018-08-08 17:45:24 -04:00
* object type ( comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
*
* @ since 2.9 . 0
*
2019-03-27 13:10:53 -04:00
* @ param int $meta_id ID of updated metadata entry .
* @ param int $object_id Object ID .
* @ param string $meta_key Meta key .
* @ param mixed $_meta_value Meta value .
2015-11-20 02:24:30 -05:00
*/
do_action ( " updated_ { $meta_type } _meta " , $meta_id , $object_id , $meta_key , $_meta_value );
2016-01-28 23:52:28 -05:00
if ( 'post' == $meta_type ) {
2015-11-20 02:24:30 -05:00
/**
* Fires immediately after updating a post ' s metadata .
*
* @ since 2.9 . 0
*
* @ param int $meta_id ID of updated metadata entry .
2019-03-27 13:10:53 -04:00
* @ param int $object_id Post ID .
2015-11-20 02:24:30 -05:00
* @ param string $meta_key Meta key .
2019-03-27 13:10:53 -04:00
* @ param mixed $meta_value Meta value . This will be a PHP - serialized string representation of the value if
* the value is an array , an object , or itself a PHP - serialized string .
2015-11-20 02:24:30 -05:00
*/
do_action ( 'updated_postmeta' , $meta_id , $object_id , $meta_key , $meta_value );
}
}
return true ;
}
/**
* Delete metadata for the specified object .
*
* @ since 2.9 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
2018-08-08 17:45:24 -04:00
* @ param string $meta_type Type of object metadata is for ( e . g . , comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
* @ 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 .
2018-07-02 13:58:27 -04:00
* Pass `null` , `false` , or an empty string to skip this check . ( For backward compatibility ,
2015-11-20 02:24:30 -05:00
* 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 .
*/
2017-11-30 18:11:00 -05:00
function delete_metadata ( $meta_type , $object_id , $meta_key , $meta_value = '' , $delete_all = false ) {
2015-11-20 02:24:30 -05:00
global $wpdb ;
if ( ! $meta_type || ! $meta_key || ! is_numeric ( $object_id ) && ! $delete_all ) {
return false ;
}
$object_id = absint ( $object_id );
if ( ! $object_id && ! $delete_all ) {
return false ;
}
$table = _get_meta_table ( $meta_type );
if ( ! $table ) {
return false ;
}
2017-11-30 18:11:00 -05:00
$type_column = sanitize_key ( $meta_type . '_id' );
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id' ;
2015-11-20 02:24:30 -05:00
// expected_slashed ($meta_key)
2017-11-30 18:11:00 -05:00
$meta_key = wp_unslash ( $meta_key );
$meta_value = wp_unslash ( $meta_value );
2015-11-20 02:24:30 -05:00
/**
2016-05-22 14:50:28 -04:00
* Filters whether to delete metadata of a specific type .
2015-11-20 02:24:30 -05:00
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
2018-08-08 17:45:24 -04:00
* object type ( comment , post , term , or user ) . Returning a non - null value
2015-11-20 02:24:30 -05:00
* will effectively short - circuit the function .
*
* @ since 3.1 . 0
*
* @ param null | bool $delete Whether to allow metadata deletion of the given type .
* @ param int $object_id Object ID .
* @ param string $meta_key Meta key .
* @ param mixed $meta_value Meta value . Must be serializable if non - scalar .
* @ param bool $delete_all Whether to delete the matching metadata entries
* for all objects , ignoring the specified $object_id .
* Default false .
*/
$check = apply_filters ( " delete_ { $meta_type } _metadata " , null , $object_id , $meta_key , $meta_value , $delete_all );
2017-11-30 18:11:00 -05:00
if ( null !== $check ) {
2015-11-20 02:24:30 -05:00
return ( bool ) $check ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
$_meta_value = $meta_value ;
2017-11-30 18:11:00 -05:00
$meta_value = maybe_serialize ( $meta_value );
2015-11-20 02:24:30 -05:00
$query = $wpdb -> prepare ( " SELECT $id_column FROM $table WHERE meta_key = %s " , $meta_key );
2017-11-30 18:11:00 -05:00
if ( ! $delete_all ) {
$query .= $wpdb -> prepare ( " AND $type_column = %d " , $object_id );
}
2015-11-20 02:24:30 -05:00
2017-11-30 18:11:00 -05:00
if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) {
$query .= $wpdb -> prepare ( ' AND meta_value = %s' , $meta_value );
}
2015-11-20 02:24:30 -05:00
$meta_ids = $wpdb -> get_col ( $query );
2017-11-30 18:11:00 -05:00
if ( ! count ( $meta_ids ) ) {
2015-11-20 02:24:30 -05:00
return false ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
2016-02-11 21:47:26 -05:00
if ( $delete_all ) {
if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) {
2017-10-31 08:00:49 -04:00
$object_ids = $wpdb -> get_col ( $wpdb -> prepare ( " SELECT $type_column FROM $table WHERE meta_key = %s AND meta_value = %s " , $meta_key , $meta_value ) );
} else {
$object_ids = $wpdb -> get_col ( $wpdb -> prepare ( " SELECT $type_column FROM $table WHERE meta_key = %s " , $meta_key ) );
2016-02-11 21:47:26 -05:00
}
}
2015-11-20 02:24:30 -05:00
/**
* Fires immediately before deleting metadata of a specific type .
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
2018-08-08 17:45:24 -04:00
* object type ( comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
*
* @ since 3.1 . 0
*
2019-10-26 17:09:04 -04:00
* @ param string [] $meta_ids An array of metadata entry IDs to delete .
* @ param int $object_id Object ID .
* @ param string $meta_key Meta key .
* @ param mixed $_meta_value Meta value .
2015-11-20 02:24:30 -05:00
*/
do_action ( " delete_ { $meta_type } _meta " , $meta_ids , $object_id , $meta_key , $_meta_value );
// Old-style action.
if ( 'post' == $meta_type ) {
/**
* Fires immediately before deleting metadata for a post .
*
* @ since 2.9 . 0
*
2019-10-26 17:09:04 -04:00
* @ param string [] $meta_ids An array of metadata entry IDs to delete .
2015-11-20 02:24:30 -05:00
*/
do_action ( 'delete_postmeta' , $meta_ids );
}
2017-11-30 18:11:00 -05:00
$query = " DELETE FROM $table WHERE $id_column IN( " . implode ( ',' , $meta_ids ) . ' )' ;
2015-11-20 02:24:30 -05:00
2017-11-30 18:11:00 -05:00
$count = $wpdb -> query ( $query );
2015-11-20 02:24:30 -05:00
2017-11-30 18:11:00 -05:00
if ( ! $count ) {
2015-11-20 02:24:30 -05:00
return false ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
if ( $delete_all ) {
foreach ( ( array ) $object_ids as $o_id ) {
2017-11-30 18:11:00 -05:00
wp_cache_delete ( $o_id , $meta_type . '_meta' );
2015-11-20 02:24:30 -05:00
}
} else {
2017-11-30 18:11:00 -05:00
wp_cache_delete ( $object_id , $meta_type . '_meta' );
2015-11-20 02:24:30 -05:00
}
/**
* Fires immediately after deleting metadata of a specific type .
*
* The dynamic portion of the hook name , `$meta_type` , refers to the meta
2018-08-08 17:45:24 -04:00
* object type ( comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
*
* @ since 2.9 . 0
*
2019-10-26 17:09:04 -04:00
* @ param string [] $meta_ids An array of metadata entry IDs to delete .
* @ param int $object_id Object ID .
* @ param string $meta_key Meta key .
* @ param mixed $_meta_value Meta value .
2015-11-20 02:24:30 -05:00
*/
do_action ( " deleted_ { $meta_type } _meta " , $meta_ids , $object_id , $meta_key , $_meta_value );
// Old-style action.
if ( 'post' == $meta_type ) {
/**
* Fires immediately after deleting metadata for a post .
*
* @ since 2.9 . 0
*
2019-10-26 17:09:04 -04:00
* @ param string [] $meta_ids An array of metadata entry IDs to delete .
2015-11-20 02:24:30 -05:00
*/
do_action ( 'deleted_postmeta' , $meta_ids );
}
return true ;
}
/**
* Retrieve metadata for the specified object .
*
2009-09-17 16:17:33 -04:00
* @ since 2.9 . 0
2015-11-20 02:24:30 -05:00
*
2018-08-08 17:45:24 -04:00
* @ param string $meta_type Type of object metadata is for ( e . g . , comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
* @ 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
2017-11-30 18:11:00 -05:00
* the specified object .
2015-11-20 02:24:30 -05:00
* @ 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
*/
2017-11-30 18:11:00 -05:00
function get_metadata ( $meta_type , $object_id , $meta_key = '' , $single = false ) {
2015-11-20 02:24:30 -05:00
if ( ! $meta_type || ! is_numeric ( $object_id ) ) {
return false ;
}
$object_id = absint ( $object_id );
if ( ! $object_id ) {
return false ;
}
/**
2016-05-22 14:50:28 -04:00
* Filters whether to retrieve metadata of a specific type .
2015-11-20 02:24:30 -05:00
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
2018-08-08 17:45:24 -04:00
* object type ( comment , post , term , or user ) . Returning a non - null value
2015-11-20 02:24:30 -05:00
* will effectively short - circuit the function .
*
* @ since 3.1 . 0
*
* @ param null | array | string $value The value get_metadata () should return - a single metadata value ,
* or an array of values .
* @ param int $object_id Object ID .
* @ param string $meta_key Meta key .
* @ param bool $single Whether to return only the first value of the specified $meta_key .
*/
$check = apply_filters ( " get_ { $meta_type } _metadata " , null , $object_id , $meta_key , $single );
if ( null !== $check ) {
2017-11-30 18:11:00 -05:00
if ( $single && is_array ( $check ) ) {
2015-11-20 02:24:30 -05:00
return $check [ 0 ];
2017-11-30 18:11:00 -05:00
} else {
2015-11-20 02:24:30 -05:00
return $check ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
}
2017-11-30 18:11:00 -05:00
$meta_cache = wp_cache_get ( $object_id , $meta_type . '_meta' );
2015-11-20 02:24:30 -05:00
2017-11-30 18:11:00 -05:00
if ( ! $meta_cache ) {
2015-11-20 02:24:30 -05:00
$meta_cache = update_meta_cache ( $meta_type , array ( $object_id ) );
2019-07-15 02:25:57 -04:00
if ( isset ( $meta_cache [ $object_id ] ) ) {
$meta_cache = $meta_cache [ $object_id ];
} else {
$meta_cache = null ;
}
2015-11-20 02:24:30 -05:00
}
if ( ! $meta_key ) {
return $meta_cache ;
}
2017-11-30 18:11:00 -05:00
if ( isset ( $meta_cache [ $meta_key ] ) ) {
if ( $single ) {
return maybe_unserialize ( $meta_cache [ $meta_key ][ 0 ] );
} else {
return array_map ( 'maybe_unserialize' , $meta_cache [ $meta_key ] );
}
2015-11-20 02:24:30 -05:00
}
2017-11-30 18:11:00 -05:00
if ( $single ) {
2015-11-20 02:24:30 -05:00
return '' ;
2017-11-30 18:11:00 -05:00
} else {
2015-11-20 02:24:30 -05:00
return array ();
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
}
/**
* Determine if a meta key is set for a given object
*
* @ since 3.3 . 0
*
2018-08-08 17:45:24 -04:00
* @ param string $meta_type Type of object metadata is for ( e . g . , comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
* @ 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 ) ) {
return false ;
}
$object_id = absint ( $object_id );
if ( ! $object_id ) {
return false ;
}
2015-11-21 22:51:28 -05:00
/** This filter is documented in wp-includes/meta.php */
2015-11-20 02:24:30 -05:00
$check = apply_filters ( " get_ { $meta_type } _metadata " , null , $object_id , $meta_key , true );
2017-11-30 18:11:00 -05:00
if ( null !== $check ) {
2015-11-20 02:24:30 -05:00
return ( bool ) $check ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
$meta_cache = wp_cache_get ( $object_id , $meta_type . '_meta' );
2017-11-30 18:11:00 -05:00
if ( ! $meta_cache ) {
2015-11-20 02:24:30 -05:00
$meta_cache = update_meta_cache ( $meta_type , array ( $object_id ) );
2017-11-30 18:11:00 -05:00
$meta_cache = $meta_cache [ $object_id ];
2015-11-20 02:24:30 -05:00
}
2017-11-30 18:11:00 -05:00
if ( isset ( $meta_cache [ $meta_key ] ) ) {
2015-11-20 02:24:30 -05:00
return true ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
return false ;
}
/**
* Get meta data by meta ID
*
* @ since 3.3 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param string $meta_type Type of object metadata is for ( e . g . , comment , post , term , or user ) .
* @ 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 ;
2016-10-01 02:28:30 -04:00
if ( ! $meta_type || ! is_numeric ( $meta_id ) || floor ( $meta_id ) != $meta_id ) {
2015-11-20 02:24:30 -05:00
return false ;
}
2016-10-01 02:28:30 -04:00
$meta_id = intval ( $meta_id );
if ( $meta_id <= 0 ) {
2015-11-20 02:24:30 -05:00
return false ;
}
$table = _get_meta_table ( $meta_type );
if ( ! $table ) {
return false ;
}
$id_column = ( 'user' == $meta_type ) ? 'umeta_id' : 'meta_id' ;
2018-12-11 22:02:24 -05:00
/**
* Filters whether to retrieve metadata of a specific type by meta ID .
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
* object type ( comment , post , term , or user ) . Returning a non - null value
* will effectively short - circuit the function .
*
* @ since 5.0 . 0
*
* @ param mixed $value The value get_metadata_by_mid () should return .
* @ param int $meta_id Meta ID .
*/
$check = apply_filters ( " get_ { $meta_type } _metadata_by_mid " , null , $meta_id );
if ( null !== $check ) {
return $check ;
}
2015-11-20 02:24:30 -05:00
$meta = $wpdb -> get_row ( $wpdb -> prepare ( " SELECT * FROM $table WHERE $id_column = %d " , $meta_id ) );
2017-11-30 18:11:00 -05:00
if ( empty ( $meta ) ) {
2015-11-20 02:24:30 -05:00
return false ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
2017-11-30 18:11:00 -05:00
if ( isset ( $meta -> meta_value ) ) {
2015-11-20 02:24:30 -05:00
$meta -> meta_value = maybe_unserialize ( $meta -> meta_value );
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
return $meta ;
}
/**
* Update meta data by meta ID
*
* @ since 3.3 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
2018-08-08 17:45:24 -04:00
* @ param string $meta_type Type of object metadata is for ( e . g . , comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
* @ 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
* @ return bool True on successful update , false on failure .
*/
function update_metadata_by_mid ( $meta_type , $meta_id , $meta_value , $meta_key = false ) {
global $wpdb ;
// Make sure everything is valid.
2016-10-01 02:28:30 -04:00
if ( ! $meta_type || ! is_numeric ( $meta_id ) || floor ( $meta_id ) != $meta_id ) {
2015-11-20 02:24:30 -05:00
return false ;
}
2016-10-01 02:28:30 -04:00
$meta_id = intval ( $meta_id );
if ( $meta_id <= 0 ) {
2015-11-20 02:24:30 -05:00
return false ;
}
$table = _get_meta_table ( $meta_type );
if ( ! $table ) {
return false ;
}
2017-11-30 18:11:00 -05:00
$column = sanitize_key ( $meta_type . '_id' );
2015-11-20 02:24:30 -05:00
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id' ;
2018-12-11 22:02:24 -05:00
/**
* Filters whether to update metadata of a specific type by meta ID .
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
* object type ( comment , post , term , or user ) . Returning a non - null value
* will effectively short - circuit the function .
*
* @ since 5.0 . 0
*
* @ param null | bool $check Whether to allow updating metadata for the given type .
* @ param int $meta_id Meta ID .
* @ param mixed $meta_value Meta value . Must be serializable if non - scalar .
* @ param string | bool $meta_key Meta key , if provided .
*/
$check = apply_filters ( " update_ { $meta_type } _metadata_by_mid " , null , $meta_id , $meta_value , $meta_key );
if ( null !== $check ) {
return ( bool ) $check ;
}
2015-11-20 02:24:30 -05:00
// Fetch the meta and go on if it's found.
2019-07-02 19:42:58 -04:00
$meta = get_metadata_by_mid ( $meta_type , $meta_id );
if ( $meta ) {
2015-11-20 02:24:30 -05:00
$original_key = $meta -> meta_key ;
2017-11-30 18:11:00 -05:00
$object_id = $meta -> { $column };
2015-11-20 02:24:30 -05:00
// If a new meta_key (last parameter) was specified, change the meta key,
// otherwise use the original key in the update statement.
if ( false === $meta_key ) {
$meta_key = $original_key ;
} elseif ( ! is_string ( $meta_key ) ) {
return false ;
}
2018-06-27 22:43:21 -04:00
$meta_subtype = get_object_subtype ( $meta_type , $object_id );
2020-01-28 19:45:18 -05:00
// Sanitize the meta.
2015-11-20 02:24:30 -05:00
$_meta_value = $meta_value ;
2018-06-27 22:43:21 -04:00
$meta_value = sanitize_meta ( $meta_key , $meta_value , $meta_type , $meta_subtype );
2017-11-30 18:11:00 -05:00
$meta_value = maybe_serialize ( $meta_value );
2015-11-20 02:24:30 -05:00
// Format the data query arguments.
$data = array (
2017-11-30 18:11:00 -05:00
'meta_key' => $meta_key ,
'meta_value' => $meta_value ,
2015-11-20 02:24:30 -05:00
);
// Format the where query arguments.
2017-11-30 18:11:00 -05:00
$where = array ();
$where [ $id_column ] = $meta_id ;
2015-11-20 02:24:30 -05:00
2015-11-21 22:51:28 -05:00
/** This action is documented in wp-includes/meta.php */
2015-11-20 02:24:30 -05:00
do_action ( " update_ { $meta_type } _meta " , $meta_id , $object_id , $meta_key , $_meta_value );
if ( 'post' == $meta_type ) {
2015-11-21 22:51:28 -05:00
/** This action is documented in wp-includes/meta.php */
2015-11-20 02:24:30 -05:00
do_action ( 'update_postmeta' , $meta_id , $object_id , $meta_key , $meta_value );
}
// Run the update query, all fields in $data are %s, $where is a %d.
$result = $wpdb -> update ( $table , $data , $where , '%s' , '%d' );
2017-11-30 18:11:00 -05:00
if ( ! $result ) {
2015-11-20 02:24:30 -05:00
return false ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
// Clear the caches.
2017-11-30 18:11:00 -05:00
wp_cache_delete ( $object_id , $meta_type . '_meta' );
2015-11-20 02:24:30 -05:00
2015-11-21 22:51:28 -05:00
/** This action is documented in wp-includes/meta.php */
2015-11-20 02:24:30 -05:00
do_action ( " updated_ { $meta_type } _meta " , $meta_id , $object_id , $meta_key , $_meta_value );
if ( 'post' == $meta_type ) {
2015-11-21 22:51:28 -05:00
/** This action is documented in wp-includes/meta.php */
2015-11-20 02:24:30 -05:00
do_action ( 'updated_postmeta' , $meta_id , $object_id , $meta_key , $meta_value );
}
return true ;
}
// And if the meta was not found.
return false ;
}
/**
* Delete meta data by meta ID
*
* @ since 3.3 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
* @ param string $meta_type Type of object metadata is for ( e . g . , comment , post , term , or user ) .
* @ 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 ) {
global $wpdb ;
// Make sure everything is valid.
2016-10-01 02:28:30 -04:00
if ( ! $meta_type || ! is_numeric ( $meta_id ) || floor ( $meta_id ) != $meta_id ) {
2015-11-20 02:24:30 -05:00
return false ;
}
2016-10-01 02:28:30 -04:00
$meta_id = intval ( $meta_id );
if ( $meta_id <= 0 ) {
2015-11-20 02:24:30 -05:00
return false ;
}
$table = _get_meta_table ( $meta_type );
if ( ! $table ) {
return false ;
}
2020-01-28 19:45:18 -05:00
// Object and ID columns.
2017-11-30 18:11:00 -05:00
$column = sanitize_key ( $meta_type . '_id' );
2015-11-20 02:24:30 -05:00
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id' ;
2018-12-11 22:02:24 -05:00
/**
* Filters whether to delete metadata of a specific type by meta ID .
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
* object type ( comment , post , term , or user ) . Returning a non - null value
* will effectively short - circuit the function .
*
* @ since 5.0 . 0
*
* @ param null | bool $delete Whether to allow metadata deletion of the given type .
* @ param int $meta_id Meta ID .
*/
$check = apply_filters ( " delete_ { $meta_type } _metadata_by_mid " , null , $meta_id );
if ( null !== $check ) {
return ( bool ) $check ;
}
2015-11-20 02:24:30 -05:00
// Fetch the meta and go on if it's found.
2019-07-02 19:42:58 -04:00
$meta = get_metadata_by_mid ( $meta_type , $meta_id );
if ( $meta ) {
2019-03-28 17:59:52 -04:00
$object_id = ( int ) $meta -> { $column };
2015-11-20 02:24:30 -05:00
2015-11-21 22:51:28 -05:00
/** This action is documented in wp-includes/meta.php */
2015-11-20 02:24:30 -05:00
do_action ( " delete_ { $meta_type } _meta " , ( array ) $meta_id , $object_id , $meta -> meta_key , $meta -> meta_value );
// Old-style action.
if ( 'post' == $meta_type || 'comment' == $meta_type ) {
/**
* Fires immediately before deleting post or comment metadata of a specific type .
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
* object type ( post or comment ) .
*
* @ since 3.4 . 0
*
* @ param int $meta_id ID of the metadata entry to delete .
*/
do_action ( " delete_ { $meta_type } meta " , $meta_id );
}
2020-01-28 19:45:18 -05:00
// Run the query, will return true if deleted, false otherwise.
2015-11-20 02:24:30 -05:00
$result = ( bool ) $wpdb -> delete ( $table , array ( $id_column => $meta_id ) );
// Clear the caches.
2017-11-30 18:11:00 -05:00
wp_cache_delete ( $object_id , $meta_type . '_meta' );
2015-11-20 02:24:30 -05:00
2015-11-21 22:51:28 -05:00
/** This action is documented in wp-includes/meta.php */
2015-11-20 02:24:30 -05:00
do_action ( " deleted_ { $meta_type } _meta " , ( array ) $meta_id , $object_id , $meta -> meta_key , $meta -> meta_value );
// Old-style action.
if ( 'post' == $meta_type || 'comment' == $meta_type ) {
/**
* Fires immediately after deleting post or comment metadata of a specific type .
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
* object type ( post or comment ) .
*
* @ since 3.4 . 0
*
* @ param int $meta_ids Deleted metadata entry ID .
*/
do_action ( " deleted_ { $meta_type } meta " , $meta_id );
}
return $result ;
}
2020-01-28 19:45:18 -05:00
// Meta ID was not found.
2015-11-20 02:24:30 -05:00
return false ;
}
/**
* Update the metadata cache for the specified objects .
*
* @ since 2.9 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
2019-08-30 07:36:08 -04:00
* @ param string $meta_type Type of object metadata is for ( e . g . , comment , post , term , or user ) .
* @ param string | int [] $object_ids Array or comma delimited list of object IDs to update cache for .
2015-11-20 02:24:30 -05:00
* @ return array | false Metadata cache for the specified objects , or false on failure .
*/
2017-11-30 18:11:00 -05:00
function update_meta_cache ( $meta_type , $object_ids ) {
2015-11-20 02:24:30 -05:00
global $wpdb ;
if ( ! $meta_type || ! $object_ids ) {
return false ;
}
$table = _get_meta_table ( $meta_type );
if ( ! $table ) {
return false ;
}
2017-11-30 18:11:00 -05:00
$column = sanitize_key ( $meta_type . '_id' );
2015-11-20 02:24:30 -05:00
2017-11-30 18:11:00 -05:00
if ( ! is_array ( $object_ids ) ) {
$object_ids = preg_replace ( '|[^0-9,]|' , '' , $object_ids );
$object_ids = explode ( ',' , $object_ids );
2015-11-20 02:24:30 -05:00
}
2017-11-30 18:11:00 -05:00
$object_ids = array_map ( 'intval' , $object_ids );
2015-11-20 02:24:30 -05:00
2018-12-11 22:02:24 -05:00
/**
* Filters whether to update the metadata cache of a specific type .
*
* The dynamic portion of the hook , `$meta_type` , refers to the meta
* object type ( comment , post , term , or user ) . Returning a non - null value
* will effectively short - circuit the function .
*
* @ since 5.0 . 0
*
* @ param mixed $check Whether to allow updating the meta cache of the given type .
2019-08-30 07:36:08 -04:00
* @ param int [] $object_ids Array of object IDs to update the meta cache for .
2018-12-11 22:02:24 -05:00
*/
$check = apply_filters ( " update_ { $meta_type } _metadata_cache " , null , $object_ids );
if ( null !== $check ) {
return ( bool ) $check ;
}
2015-11-20 02:24:30 -05:00
$cache_key = $meta_type . '_meta' ;
2017-11-30 18:11:00 -05:00
$ids = array ();
$cache = array ();
2015-11-20 02:24:30 -05:00
foreach ( $object_ids as $id ) {
$cached_object = wp_cache_get ( $id , $cache_key );
2017-11-30 18:11:00 -05:00
if ( false === $cached_object ) {
2015-11-20 02:24:30 -05:00
$ids [] = $id ;
2017-11-30 18:11:00 -05:00
} else {
$cache [ $id ] = $cached_object ;
}
2015-11-20 02:24:30 -05:00
}
2017-11-30 18:11:00 -05:00
if ( empty ( $ids ) ) {
2015-11-20 02:24:30 -05:00
return $cache ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
2020-01-28 19:45:18 -05:00
// Get meta info.
2017-11-30 18:11:00 -05:00
$id_list = join ( ',' , $ids );
2015-11-20 02:24:30 -05:00
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id' ;
$meta_list = $wpdb -> get_results ( " SELECT $column , meta_key, meta_value FROM $table WHERE $column IN ( $id_list ) ORDER BY $id_column ASC " , ARRAY_A );
2017-11-30 18:11:00 -05:00
if ( ! empty ( $meta_list ) ) {
foreach ( $meta_list as $metarow ) {
$mpid = intval ( $metarow [ $column ] );
2015-11-20 02:24:30 -05:00
$mkey = $metarow [ 'meta_key' ];
$mval = $metarow [ 'meta_value' ];
2020-01-28 19:45:18 -05:00
// Force subkeys to be array type.
2017-11-30 18:11:00 -05:00
if ( ! isset ( $cache [ $mpid ] ) || ! is_array ( $cache [ $mpid ] ) ) {
$cache [ $mpid ] = array ();
}
if ( ! isset ( $cache [ $mpid ][ $mkey ] ) || ! is_array ( $cache [ $mpid ][ $mkey ] ) ) {
$cache [ $mpid ][ $mkey ] = array ();
}
2015-11-20 02:24:30 -05:00
2020-01-28 19:45:18 -05:00
// Add a value to the current pid/key.
2017-11-30 18:11:00 -05:00
$cache [ $mpid ][ $mkey ][] = $mval ;
2015-11-20 02:24:30 -05:00
}
}
foreach ( $ids as $id ) {
2017-11-30 18:11:00 -05:00
if ( ! isset ( $cache [ $id ] ) ) {
$cache [ $id ] = array ();
}
wp_cache_add ( $id , $cache [ $id ], $cache_key );
2015-11-20 02:24:30 -05:00
}
return $cache ;
}
More performance improvements to metadata lazyloading.
Comment and term meta lazyloading for `WP_Query` loops, introduced in 4.4,
depended on filter callback methods belonging to `WP_Query` objects. This meant
storing `WP_Query` objects in the `$wp_filter` global (via `add_filter()`),
requiring that PHP retain the objects in memory, even when the local variables
would typically be expunged during normal garbage collection. In cases where a
large number of `WP_Query` objects were instantiated on a single pageload,
and/or where the contents of the `WP_Query` objects were quite large, serious
performance issues could result.
We skirt this problem by moving metadata lazyloading out of `WP_Query`. The
new `WP_Metadata_Lazyloader` class acts as a lazyload queue. Query instances
register items whose metadata should be lazyloaded - such as post terms, or
comments - and a `WP_Metadata_Lazyloader` method will intercept comment and
term meta requests to perform the cache priming. Since `WP_Metadata_Lazyloader`
instances are far smaller than `WP_Query` (containing only object IDs), and
clean up after themselves far better than the previous `WP_Query` methods (bp
only running their callbacks a single time for a given set of queued objects),
the resource use is decreased dramatically.
See [36525] for an earlier step in this direction.
Props lpawlik, stevegrunwell, boonebgorges.
Fixes #35816.
Built from https://develop.svn.wordpress.org/trunk@36566
git-svn-id: http://core.svn.wordpress.org/trunk@36533 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2016-02-17 17:58:26 -05:00
/**
2016-03-10 12:50:27 -05:00
* Retrieves the queue for lazy - loading metadata .
More performance improvements to metadata lazyloading.
Comment and term meta lazyloading for `WP_Query` loops, introduced in 4.4,
depended on filter callback methods belonging to `WP_Query` objects. This meant
storing `WP_Query` objects in the `$wp_filter` global (via `add_filter()`),
requiring that PHP retain the objects in memory, even when the local variables
would typically be expunged during normal garbage collection. In cases where a
large number of `WP_Query` objects were instantiated on a single pageload,
and/or where the contents of the `WP_Query` objects were quite large, serious
performance issues could result.
We skirt this problem by moving metadata lazyloading out of `WP_Query`. The
new `WP_Metadata_Lazyloader` class acts as a lazyload queue. Query instances
register items whose metadata should be lazyloaded - such as post terms, or
comments - and a `WP_Metadata_Lazyloader` method will intercept comment and
term meta requests to perform the cache priming. Since `WP_Metadata_Lazyloader`
instances are far smaller than `WP_Query` (containing only object IDs), and
clean up after themselves far better than the previous `WP_Query` methods (bp
only running their callbacks a single time for a given set of queued objects),
the resource use is decreased dramatically.
See [36525] for an earlier step in this direction.
Props lpawlik, stevegrunwell, boonebgorges.
Fixes #35816.
Built from https://develop.svn.wordpress.org/trunk@36566
git-svn-id: http://core.svn.wordpress.org/trunk@36533 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2016-02-17 17:58:26 -05:00
*
* @ since 4.5 . 0
*
* @ return WP_Metadata_Lazyloader $lazyloader Metadata lazyloader queue .
*/
function wp_metadata_lazyloader () {
static $wp_metadata_lazyloader ;
if ( null === $wp_metadata_lazyloader ) {
$wp_metadata_lazyloader = new WP_Metadata_Lazyloader ();
}
return $wp_metadata_lazyloader ;
}
2015-11-20 02:24:30 -05:00
/**
* Given a meta query , generates SQL clauses to be appended to a main query .
*
* @ since 3.2 . 0
*
* @ see WP_Meta_Query
*
* @ param array $meta_query A meta query .
* @ param string $type Type of meta .
* @ param string $primary_table Primary database table name .
* @ param string $primary_id_column Primary ID column name .
* @ param object $context Optional . The main query object
* @ return array Associative array of `JOIN` and `WHERE` SQL .
*/
function get_meta_sql ( $meta_query , $type , $primary_table , $primary_id_column , $context = null ) {
$meta_query_obj = new WP_Meta_Query ( $meta_query );
return $meta_query_obj -> get_sql ( $type , $primary_table , $primary_id_column , $context );
}
/**
* Retrieve the name of the metadata table for the specified object type .
*
* @ since 2.9 . 0
*
* @ global wpdb $wpdb WordPress database abstraction object .
*
2018-08-08 17:45:24 -04:00
* @ param string $type Type of object to get metadata table for ( e . g . , comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
* @ return string | false Metadata table name , or false if no metadata table exists
*/
2017-11-30 18:11:00 -05:00
function _get_meta_table ( $type ) {
2015-11-20 02:24:30 -05:00
global $wpdb ;
$table_name = $type . 'meta' ;
2017-11-30 18:11:00 -05:00
if ( empty ( $wpdb -> $table_name ) ) {
2015-11-20 02:24:30 -05:00
return false ;
2017-11-30 18:11:00 -05:00
}
2015-11-20 02:24:30 -05:00
return $wpdb -> $table_name ;
}
/**
2018-04-30 10:39:21 -04:00
* Determines whether a meta key is considered protected .
2015-11-20 02:24:30 -05:00
*
* @ since 3.1 . 3
*
2018-04-30 10:39:21 -04:00
* @ param string $meta_key Meta key .
2018-08-08 17:45:24 -04:00
* @ param string | null $meta_type Optional . Type of object metadata is for ( e . g . , comment , post , term , or user ) .
2018-04-30 10:39:21 -04:00
* @ return bool Whether the meta key is considered protected .
2015-11-20 02:24:30 -05:00
*/
function is_protected_meta ( $meta_key , $meta_type = null ) {
$protected = ( '_' == $meta_key [ 0 ] );
/**
2018-04-30 10:39:21 -04:00
* Filters whether a meta key is considered protected .
2015-11-20 02:24:30 -05:00
*
* @ since 3.2 . 0
*
2018-04-30 10:39:21 -04:00
* @ param bool $protected Whether the key is considered protected .
* @ param string $meta_key Meta key .
2018-08-08 17:45:24 -04:00
* @ param string | null $meta_type Type of object metadata is for ( e . g . , comment , post , term , or user ) .
2015-11-20 02:24:30 -05:00
*/
return apply_filters ( 'is_protected_meta' , $protected , $meta_key , $meta_type );
}
/**
* Sanitize meta value .
*
* @ since 3.1 . 3
2018-07-23 13:02:25 -04:00
* @ since 4.9 . 8 The `$object_subtype` parameter was added .
2015-11-20 02:24:30 -05:00
*
2016-06-29 21:02:29 -04:00
* @ param string $meta_key Meta key .
* @ param mixed $meta_value Meta value to sanitize .
* @ param string $object_type Type of object the meta is registered to .
2018-07-23 13:14:26 -04:00
* @ param string $object_subtype Optional . The subtype of the object type .
2016-06-29 21:02:29 -04:00
*
* @ return mixed Sanitized $meta_value .
2015-11-20 02:24:30 -05:00
*/
2018-06-27 22:43:21 -04:00
function sanitize_meta ( $meta_key , $meta_value , $object_type , $object_subtype = '' ) {
if ( ! empty ( $object_subtype ) && has_filter ( " sanitize_ { $object_type } _meta_ { $meta_key } _for_ { $object_subtype } " ) ) {
/**
* Filters the sanitization of a specific meta key of a specific meta type and subtype .
*
* The dynamic portions of the hook name , `$object_type` , `$meta_key` ,
2018-08-08 17:45:24 -04:00
* and `$object_subtype` , refer to the metadata object type ( comment , post , term , or user ),
2018-06-27 22:43:21 -04:00
* the meta key value , and the object subtype respectively .
*
2018-07-23 13:02:25 -04:00
* @ since 4.9 . 8
2018-06-27 22:43:21 -04:00
*
* @ param mixed $meta_value Meta value to sanitize .
* @ param string $meta_key Meta key .
* @ param string $object_type Object type .
* @ param string $object_subtype Object subtype .
*/
return apply_filters ( " sanitize_ { $object_type } _meta_ { $meta_key } _for_ { $object_subtype } " , $meta_value , $meta_key , $object_type , $object_subtype );
}
2015-11-20 02:24:30 -05:00
/**
2016-05-22 14:50:28 -04:00
* Filters the sanitization of a specific meta key of a specific meta type .
2015-11-20 02:24:30 -05:00
*
* The dynamic portions of the hook name , `$meta_type` , and `$meta_key` ,
2018-08-08 17:45:24 -04:00
* refer to the metadata object type ( comment , post , term , or user ) and the meta
2016-06-29 21:02:29 -04:00
* key value , respectively .
2015-11-20 02:24:30 -05:00
*
* @ since 3.3 . 0
*
2016-06-29 21:02:29 -04:00
* @ param mixed $meta_value Meta value to sanitize .
* @ param string $meta_key Meta key .
* @ param string $object_type Object type .
2015-11-20 02:24:30 -05:00
*/
2016-07-18 17:16:29 -04:00
return apply_filters ( " sanitize_ { $object_type } _meta_ { $meta_key } " , $meta_value , $meta_key , $object_type );
2015-11-20 02:24:30 -05:00
}
/**
2016-06-29 21:02:29 -04:00
* Registers a meta key .
2015-11-20 02:24:30 -05:00
*
2018-06-27 22:43:21 -04:00
* It is recommended to register meta keys for a specific combination of object type and object subtype . If passing
* an object subtype is omitted , the meta key will be registered for the entire object type , however it can be partly
* overridden in case a more specific meta key of the same name exists for the same object type and a subtype .
*
* If an object type does not support any subtypes , such as users or comments , you should commonly call this function
* without passing a subtype .
*
2015-11-20 02:24:30 -05:00
* @ since 3.3 . 0
2016-11-01 02:54:34 -04:00
* @ since 4.6 . 0 { @ link https :// core . trac . wordpress . org / ticket / 35658 Modified
2016-07-09 12:50:35 -04:00
* to support an array of data to attach to registered meta keys } . Previous arguments for
2016-06-29 21:02:29 -04:00
* `$sanitize_callback` and `$auth_callback` have been folded into this array .
2018-07-23 13:02:25 -04:00
* @ since 4.9 . 8 The `$object_subtype` argument was added to the arguments array .
2019-09-19 10:36:55 -04:00
* @ since 5.3 . 0 Valid meta types expanded to include " array " and " object " .
2015-11-20 02:24:30 -05:00
*
2016-06-29 21:02:29 -04:00
* @ param string $object_type Type of object this meta is registered to .
* @ param string $meta_key Meta key to register .
* @ param array $args {
* Data used to describe the meta key when registered .
*
2019-09-19 10:36:55 -04:00
* @ type string $object_subtype A subtype ; e . g . if the object type is " post " , the post type . If left empty ,
* the meta key will be registered on the entire object type . Default empty .
* @ type string $type The type of data associated with this meta key .
* Valid values are 'string' , 'boolean' , 'integer' , 'number' , 'array' , and 'object' .
* @ type string $description A description of the data attached to this meta key .
* @ type bool $single Whether the meta key has one value per object , or an array of values per object .
* @ type string $sanitize_callback A function or method to call when sanitizing `$meta_key` data .
* @ type string $auth_callback Optional . A function or method to call when performing edit_post_meta ,
* add_post_meta , and delete_post_meta capability checks .
* @ type bool | array $show_in_rest Whether data associated with this meta key can be considered public and
* should be accessible via the REST API . A custom post type must also declare
* support for custom fields for registered meta to be accessible via REST .
* When registering complex meta values this argument may optionally be an
* array with 'schema' or 'prepare_callback' keys instead of a boolean .
2016-06-29 21:02:29 -04:00
* }
2016-06-30 15:00:31 -04:00
* @ param string | array $deprecated Deprecated . Use `$args` instead .
2016-06-29 21:02:29 -04:00
*
2016-07-18 17:16:29 -04:00
* @ return bool True if the meta key was successfully registered in the global array , false if not .
2016-07-06 14:09:32 -04:00
* Registering a meta key with distinct sanitize and auth callbacks will fire those
2016-07-18 17:16:29 -04:00
* callbacks , but will not add to the global registry .
2009-09-17 16:17:33 -04:00
*/
2016-06-30 15:00:31 -04:00
function register_meta ( $object_type , $meta_key , $args , $deprecated = null ) {
2016-06-29 21:02:29 -04:00
global $wp_meta_keys ;
2009-09-17 16:17:33 -04:00
2016-06-29 21:02:29 -04:00
if ( ! is_array ( $wp_meta_keys ) ) {
$wp_meta_keys = array ();
}
$defaults = array (
2018-06-27 22:43:21 -04:00
'object_subtype' => '' ,
2016-06-29 21:02:29 -04:00
'type' => 'string' ,
'description' => '' ,
2016-06-30 17:25:27 -04:00
'single' => false ,
2016-06-29 21:02:29 -04:00
'sanitize_callback' => null ,
'auth_callback' => null ,
'show_in_rest' => false ,
);
2020-01-28 19:45:18 -05:00
// There used to be individual args for sanitize and auth callbacks.
2016-06-30 12:39:29 -04:00
$has_old_sanitize_cb = false ;
2017-11-30 18:11:00 -05:00
$has_old_auth_cb = false ;
2016-06-29 21:02:29 -04:00
2016-06-30 15:00:31 -04:00
if ( is_callable ( $args ) ) {
$args = array (
'sanitize_callback' => $args ,
);
2016-06-29 21:02:29 -04:00
$has_old_sanitize_cb = true ;
} else {
2016-06-30 15:00:31 -04:00
$args = ( array ) $args ;
2016-06-29 21:02:29 -04:00
}
2016-06-30 15:00:31 -04:00
if ( is_callable ( $deprecated ) ) {
$args [ 'auth_callback' ] = $deprecated ;
2017-11-30 18:11:00 -05:00
$has_old_auth_cb = true ;
2016-06-29 21:02:29 -04:00
}
/**
* Filters the registration arguments when registering meta .
*
* @ since 4.6 . 0
*
* @ param array $args Array of meta registration arguments .
* @ param array $defaults Array of default arguments .
* @ param string $object_type Object type .
* @ param string $meta_key Meta key .
*/
$args = apply_filters ( 'register_meta_args' , $args , $defaults , $object_type , $meta_key );
2016-07-18 17:16:29 -04:00
$args = wp_parse_args ( $args , $defaults );
2016-06-29 21:02:29 -04:00
2019-09-19 10:36:55 -04:00
// Require an item schema when registering array meta.
if ( false !== $args [ 'show_in_rest' ] && 'array' === $args [ 'type' ] ) {
if ( ! is_array ( $args [ 'show_in_rest' ] ) || ! isset ( $args [ 'show_in_rest' ][ 'schema' ][ 'items' ] ) ) {
_doing_it_wrong ( __FUNCTION__ , __ ( 'When registering an "array" meta type to show in the REST API, you must specify the schema for each array item in "show_in_rest.schema.items".' ), '5.3.0' );
return false ;
}
}
2018-06-27 22:43:21 -04:00
$object_subtype = ! empty ( $args [ 'object_subtype' ] ) ? $args [ 'object_subtype' ] : '' ;
2016-06-29 21:02:29 -04:00
// If `auth_callback` is not provided, fall back to `is_protected_meta()`.
if ( empty ( $args [ 'auth_callback' ] ) ) {
if ( is_protected_meta ( $meta_key , $object_type ) ) {
$args [ 'auth_callback' ] = '__return_false' ;
} else {
$args [ 'auth_callback' ] = '__return_true' ;
}
}
2016-07-13 00:46:28 -04:00
// Back-compat: old sanitize and auth callbacks are applied to all of an object type.
2016-07-18 17:16:29 -04:00
if ( is_callable ( $args [ 'sanitize_callback' ] ) ) {
2018-06-27 22:43:21 -04:00
if ( ! empty ( $object_subtype ) ) {
add_filter ( " sanitize_ { $object_type } _meta_ { $meta_key } _for_ { $object_subtype } " , $args [ 'sanitize_callback' ], 10 , 4 );
} else {
add_filter ( " sanitize_ { $object_type } _meta_ { $meta_key } " , $args [ 'sanitize_callback' ], 10 , 3 );
}
2016-07-13 00:46:28 -04:00
}
2016-07-18 17:16:29 -04:00
if ( is_callable ( $args [ 'auth_callback' ] ) ) {
2018-06-27 22:43:21 -04:00
if ( ! empty ( $object_subtype ) ) {
add_filter ( " auth_ { $object_type } _meta_ { $meta_key } _for_ { $object_subtype } " , $args [ 'auth_callback' ], 10 , 6 );
} else {
add_filter ( " auth_ { $object_type } _meta_ { $meta_key } " , $args [ 'auth_callback' ], 10 , 6 );
}
2016-07-13 00:46:28 -04:00
}
2016-07-18 17:16:29 -04:00
// Global registry only contains meta keys registered with the array of arguments added in 4.6.0.
if ( ! $has_old_auth_cb && ! $has_old_sanitize_cb ) {
2018-06-27 22:43:21 -04:00
unset ( $args [ 'object_subtype' ] );
$wp_meta_keys [ $object_type ][ $object_subtype ][ $meta_key ] = $args ;
2016-06-29 21:02:29 -04:00
return true ;
}
2016-07-18 17:16:29 -04:00
return false ;
2016-06-29 21:02:29 -04:00
}
/**
* Checks if a meta key is registered .
*
* @ since 4.6 . 0
2018-07-23 13:02:25 -04:00
* @ since 4.9 . 8 The `$object_subtype` parameter was added .
2016-06-29 21:02:29 -04:00
*
* @ param string $object_type The type of object .
* @ param string $meta_key The meta key .
2018-06-27 22:43:21 -04:00
* @ param string $object_subtype Optional . The subtype of the object type .
2016-06-29 21:02:29 -04:00
*
2018-06-27 22:43:21 -04:00
* @ return bool True if the meta key is registered to the object type and , if provided ,
* the object subtype . False if not .
2016-06-29 21:02:29 -04:00
*/
2018-06-27 22:43:21 -04:00
function registered_meta_key_exists ( $object_type , $meta_key , $object_subtype = '' ) {
$meta_keys = get_registered_meta_keys ( $object_type , $object_subtype );
2016-06-29 21:02:29 -04:00
2018-06-27 22:43:21 -04:00
return isset ( $meta_keys [ $meta_key ] );
2016-06-29 21:02:29 -04:00
}
/**
* Unregisters a meta key from the list of registered keys .
*
* @ since 4.6 . 0
2018-07-23 13:02:25 -04:00
* @ since 4.9 . 8 The `$object_subtype` parameter was added .
2016-06-29 21:02:29 -04:00
*
2018-06-27 22:43:21 -04:00
* @ param string $object_type The type of object .
* @ param string $meta_key The meta key .
* @ param string $object_subtype Optional . The subtype of the object type .
2016-07-18 17:16:29 -04:00
* @ return bool True if successful . False if the meta key was not registered .
2016-06-29 21:02:29 -04:00
*/
2018-06-27 22:43:21 -04:00
function unregister_meta_key ( $object_type , $meta_key , $object_subtype = '' ) {
2016-06-29 21:02:29 -04:00
global $wp_meta_keys ;
2018-06-27 22:43:21 -04:00
if ( ! registered_meta_key_exists ( $object_type , $meta_key , $object_subtype ) ) {
2016-07-18 17:16:29 -04:00
return false ;
2016-06-29 21:02:29 -04:00
}
2018-06-27 22:43:21 -04:00
$args = $wp_meta_keys [ $object_type ][ $object_subtype ][ $meta_key ];
2016-07-13 00:13:30 -04:00
if ( isset ( $args [ 'sanitize_callback' ] ) && is_callable ( $args [ 'sanitize_callback' ] ) ) {
2018-06-27 22:43:21 -04:00
if ( ! empty ( $object_subtype ) ) {
remove_filter ( " sanitize_ { $object_type } _meta_ { $meta_key } _for_ { $object_subtype } " , $args [ 'sanitize_callback' ] );
} else {
remove_filter ( " sanitize_ { $object_type } _meta_ { $meta_key } " , $args [ 'sanitize_callback' ] );
}
2016-07-13 00:13:30 -04:00
}
if ( isset ( $args [ 'auth_callback' ] ) && is_callable ( $args [ 'auth_callback' ] ) ) {
2018-06-27 22:43:21 -04:00
if ( ! empty ( $object_subtype ) ) {
remove_filter ( " auth_ { $object_type } _meta_ { $meta_key } _for_ { $object_subtype } " , $args [ 'auth_callback' ] );
} else {
remove_filter ( " auth_ { $object_type } _meta_ { $meta_key } " , $args [ 'auth_callback' ] );
}
2016-07-13 00:13:30 -04:00
}
2018-06-27 22:43:21 -04:00
unset ( $wp_meta_keys [ $object_type ][ $object_subtype ][ $meta_key ] );
2016-06-29 21:02:29 -04:00
2020-01-28 19:45:18 -05:00
// Do some clean up.
2018-06-27 22:43:21 -04:00
if ( empty ( $wp_meta_keys [ $object_type ][ $object_subtype ] ) ) {
unset ( $wp_meta_keys [ $object_type ][ $object_subtype ] );
}
2016-06-29 21:02:29 -04:00
if ( empty ( $wp_meta_keys [ $object_type ] ) ) {
unset ( $wp_meta_keys [ $object_type ] );
}
return true ;
}
/**
2016-07-18 17:16:29 -04:00
* Retrieves a list of registered meta keys for an object type .
2016-06-29 21:02:29 -04:00
*
* @ since 4.6 . 0
2018-07-23 13:02:25 -04:00
* @ since 4.9 . 8 The `$object_subtype` parameter was added .
2016-06-29 21:02:29 -04:00
*
2018-06-27 22:43:21 -04:00
* @ param string $object_type The type of object . Post , comment , user , term .
* @ param string $object_subtype Optional . The subtype of the object type .
2019-11-05 16:23:02 -05:00
* @ return string [] List of registered meta keys .
2016-06-29 21:02:29 -04:00
*/
2018-06-27 22:43:21 -04:00
function get_registered_meta_keys ( $object_type , $object_subtype = '' ) {
2016-06-29 21:02:29 -04:00
global $wp_meta_keys ;
2018-06-27 22:43:21 -04:00
if ( ! is_array ( $wp_meta_keys ) || ! isset ( $wp_meta_keys [ $object_type ] ) || ! isset ( $wp_meta_keys [ $object_type ][ $object_subtype ] ) ) {
2016-06-29 21:02:29 -04:00
return array ();
}
2018-06-27 22:43:21 -04:00
return $wp_meta_keys [ $object_type ][ $object_subtype ];
2016-06-29 21:02:29 -04:00
}
/**
* Retrieves registered metadata for a specified object .
*
2018-06-27 22:43:21 -04:00
* The results include both meta that is registered specifically for the
* object ' s subtype and meta that is registered for the entire object type .
*
2016-06-29 21:02:29 -04:00
* @ since 4.6 . 0
*
2016-07-18 17:16:29 -04:00
* @ param string $object_type Type of object to request metadata for . ( e . g . comment , post , term , user )
* @ param int $object_id ID of the object the metadata is for .
* @ param string $meta_key Optional . Registered metadata key . If not specified , retrieve all registered
* metadata for the specified object .
* @ return mixed A single value or array of values for a key if specified . An array of all registered keys
2018-06-27 22:43:21 -04:00
* and values for an object ID if not . False if a given $meta_key is not registered .
2016-06-29 21:02:29 -04:00
*/
2016-07-18 17:16:29 -04:00
function get_registered_metadata ( $object_type , $object_id , $meta_key = '' ) {
2018-06-27 22:43:21 -04:00
$object_subtype = get_object_subtype ( $object_type , $object_id );
2016-06-29 21:02:29 -04:00
if ( ! empty ( $meta_key ) ) {
2018-06-27 22:43:21 -04:00
if ( ! empty ( $object_subtype ) && ! registered_meta_key_exists ( $object_type , $meta_key , $object_subtype ) ) {
$object_subtype = '' ;
}
if ( ! registered_meta_key_exists ( $object_type , $meta_key , $object_subtype ) ) {
2016-07-18 17:16:29 -04:00
return false ;
2016-06-29 21:02:29 -04:00
}
2018-06-27 22:43:21 -04:00
$meta_keys = get_registered_meta_keys ( $object_type , $object_subtype );
2016-06-30 17:25:27 -04:00
$meta_key_data = $meta_keys [ $meta_key ];
2016-06-29 21:02:29 -04:00
2016-06-30 17:25:27 -04:00
$data = get_metadata ( $object_type , $object_id , $meta_key , $meta_key_data [ 'single' ] );
2016-06-29 21:02:29 -04:00
return $data ;
}
2016-07-06 20:18:27 -04:00
$data = get_metadata ( $object_type , $object_id );
2018-06-27 22:43:21 -04:00
if ( ! $data ) {
return array ();
}
2016-06-29 21:02:29 -04:00
2018-06-27 22:43:21 -04:00
$meta_keys = get_registered_meta_keys ( $object_type );
if ( ! empty ( $object_subtype ) ) {
$meta_keys = array_merge ( $meta_keys , get_registered_meta_keys ( $object_type , $object_subtype ) );
2016-06-29 21:02:29 -04:00
}
2018-06-27 22:43:21 -04:00
return array_intersect_key ( $data , $meta_keys );
2016-06-29 21:02:29 -04:00
}
/**
* Filter out `register_meta()` args based on a whitelist .
* `register_meta()` args may change over time , so requiring the whitelist
* to be explicitly turned off is a warranty seal of sorts .
*
* @ access private
2018-06-27 22:43:21 -04:00
* @ since 4.6 . 0
2016-06-29 21:02:29 -04:00
*
2018-06-27 22:43:21 -04:00
* @ param array $args Arguments from `register_meta()` .
* @ param array $default_args Default arguments for `register_meta()` .
2016-06-29 21:02:29 -04:00
*
* @ return array Filtered arguments .
*/
function _wp_register_meta_args_whitelist ( $args , $default_args ) {
2018-06-27 22:43:21 -04:00
return array_intersect_key ( $args , $default_args );
}
2016-06-29 21:02:29 -04:00
2018-06-27 22:43:21 -04:00
/**
* Returns the object subtype for a given object ID of a specific type .
*
2018-07-23 13:02:25 -04:00
* @ since 4.9 . 8
2018-06-27 22:43:21 -04:00
*
* @ param string $object_type Type of object to request metadata for . ( e . g . comment , post , term , user )
* @ param int $object_id ID of the object to retrieve its subtype .
* @ return string The object subtype or an empty string if unspecified subtype .
*/
function get_object_subtype ( $object_type , $object_id ) {
$object_id = ( int ) $object_id ;
$object_subtype = '' ;
switch ( $object_type ) {
case 'post' :
$post_type = get_post_type ( $object_id );
if ( ! empty ( $post_type ) ) {
$object_subtype = $post_type ;
}
break ;
case 'term' :
$term = get_term ( $object_id );
if ( ! $term instanceof WP_Term ) {
break ;
}
$object_subtype = $term -> taxonomy ;
break ;
case 'comment' :
$comment = get_comment ( $object_id );
if ( ! $comment ) {
break ;
}
$object_subtype = 'comment' ;
break ;
case 'user' :
$user = get_user_by ( 'id' , $object_id );
if ( ! $user ) {
break ;
}
$object_subtype = 'user' ;
break ;
2015-11-20 02:24:30 -05:00
}
2015-09-22 09:30:24 -04:00
2018-06-27 22:43:21 -04:00
/**
* Filters the object subtype identifier for a non standard object type .
*
* The dynamic portion of the hook , `$object_type` , refers to the object
* type ( post , comment , term , or user ) .
*
2018-07-23 13:02:25 -04:00
* @ since 4.9 . 8
2018-06-27 22:43:21 -04:00
*
* @ param string $object_subtype Empty string to override .
* @ param int $object_id ID of the object to get the subtype for .
*/
return apply_filters ( " get_object_subtype_ { $object_type } " , $object_subtype , $object_id );
2015-11-20 02:24:30 -05:00
}