Make WordPress Core

Ticket #35658: 35658.5.diff

File 35658.5.diff, 43.9 KB (added by MikeSchinkel, 8 years ago)

Adds an WP_Object_Type class to support meta.php changes

  • www/wp-includes/class-wp-object-type.php

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
     
     1<?php
     2
     3/**
     4 * Class WP_Object_Type
     5 *
     6 * Object Type is an infrastructure class used to classify fields and forms with
     7 * other potential classification use cases in the future.
     8 *
     9 * Registered fields are often intended to be for specific post types and as such
     10 * post types need to be specified. However, Fields should not be specific to
     11 * post types as fields would be beneficial for users, comments, options, and more.
     12 *
     13 * So the Object Type was designed to capture and allow developers to specify both
     14 * the $type of object (i.e. 'post', 'user', 'comment', etc.) as well as the $subtype
     15 * specific to the type, (i.e. 'post', 'page', 'attachment', etc. for Object Types
     16 * of $class 'post.')
     17 *
     18 * Object Types literals are specified in string form with a colon separating $class
     19 * from $subtype, which looks like this:
     20 *
     21 *    'post:post'
     22 *    'post:page'
     23 *    'post:attachment'
     24 *    'post:my_post_type'
     25 *
     26 * Object can be comparied with $object_type where is_object($object_type) is
     27 * true (because of the Object Type's __toString() method.):
     28 *
     29 *    $object_type = new WP_Object_Type( 'post:my_post_type' );
     30 *
     31 *    if ( 'post:my_post_type' == $object_type ) {
     32 *       echo 'They *are* equal!'
     33 *    }
     34 *
     35 * The 'any' subtype will match any item of the specified $class, and if subtype
     36 * is ommitted then it implies 'any'. All of these are equivalent:
     37 *
     38 *    'post:any'
     39 *    'post:'
     40 *    'post'
     41 *
     42 * If the colon is ommitted from an Object Type string literal then the Object Type's
     43 * $class is assumed to be 'post'
     44 *
     45 *    $object_type = new WP_Object_Type( 'my_post_type' );
     46 *
     47 *    if ( 'post:my_post_type' == $object_type ) {
     48 *       echo 'This is equal too.'
     49 *    }
     50 *
     51 * You can specify any other $subtype besides 'post', with or withouta colon. If there is no
     52 * $subtype then it will default to 'any'. All of these groups of three are equivalent.
     53 *
     54 *    'term'
     55 *    'term:'
     56 *    'term:any'
     57 *
     58 *    'user'
     59 *    'user:'
     60 *    'user:any'
     61 *
     62 *    'comment'
     63 *    'comment:'
     64 *    'comment:any'
     65 *
     66 *
     67 * Object Types can be reused by using the assign() method:
     68 *
     69 *    $post_types = get_post_types( array( '_builtin' => false ) );
     70 *    $object_type = new WP_Object_Type()
     71 *    foreach( $post_types as $post_type ) {
     72 *        $object_type->assign( $post_type );
     73 *        // Do something with $object_type
     74 *    }
     75 *
     76 * It's also possible to instantiate an Object Type with an associative array:
     77 *
     78 *    $object_type = new WP_Object_Type( array(
     79 *      'type' => 'post',
     80 *      'subtype' => 'my_post_type',
     81 *    );
     82 *
     83 */
     84final class WP_Object_Type {
     85
     86        /**
     87         * The $type property is used to contain the type of object such as 'post',
     88         * 'user', 'comment', 'option', etc.
     89         *
     90         * @var null|string
     91         */
     92        var $type = null;
     93
     94        /**
     95         * The $subtype property is to contain the 'type' relevant to the Object Type's
     96         * $class, i.e. for 'post' there is 'post', 'page', 'attachment' and whatever
     97         * custom post types have been defined.
     98         *
     99         * For $class values of 'user' we are currently assuming role will used for $subtype.
     100         *
     101         * For all other $class values the value of $subtype is TBD.
     102         *
     103         * @var null|string
     104         */
     105        var $subtype = null;
     106
     107        /**
     108         * List of Short Types
     109         *
     110         * @var array
     111         */
     112        protected static $_short_types = array(
     113                'post'        => 'p',
     114                'term'        => 't',
     115                'user'        => 'u',
     116                'comment'     => 'c',
     117        );
     118
     119        /**
     120         * Initialize an Object Type object with an optional Object Type literal string passed
     121         * in to represent the object type:
     122         *
     123         * @example
     124         *
     125         *    $object_type = new WP_Object_Type( 'my_post_type' );
     126         *
     127         * An Object Type can effectively be cloned by passing an Object Type object instead
     128         * of a literal, i.e.
     129         *
     130         *    $object_type = new WP_Object_Type( 'my_post_type' );
     131         *    $object_type2 = new WP_Object_Type( $object_type );
     132         *
     133         *    if ( (string)$object_type == (string)$object_type2 ) {
     134         *       echo 'This is equal.'
     135         *    }
     136         *    if ( 'post:my_post_type' == $object_type ) {
     137         *       echo 'And this is equal.'
     138         *    }
     139         *    if ( 'post:my_post_type' == $object_type2 ) {
     140         *       echo 'And this is also equal.'
     141         *    }
     142         *    if ( $object_type === $object_type2 ) {
     143         *       echo 'But this is NOT equal.'
     144         *    }
     145         *
     146         * Passing in an object is useful in functions that might be called directly by
     147         * a developer with an object literal but might be also called indirectly where
     148         * the Object Type literal string had already been replaced with its object
     149         * equivalent.
     150         *
     151         * It's also possible to instantiate an Object Type with an associative array:
     152         *
     153         *    $object_type = new WP_Object_Type( array(
     154         *      'type' => 'post',
     155         *      'subtype' => 'my_post_type',
     156         *    );
     157         *
     158         * @param bool|string|array|object $object_type
     159         */
     160        function __construct( $object_type = false ) {
     161
     162                if ( ! empty( $object_type ) ) {
     163
     164                        $this->assign( $object_type );
     165
     166                        if ( ! in_array( $object_type, self::object_types() ) ) {
     167                                _doing_it_wrong( __FUNCTION__, sprintf( __( 'Invalid object type: %s.' ), $object_type ), '4.6.0' );
     168                        }
     169
     170                }
     171
     172        }
     173
     174        /**
     175         * Validates and assigns a value to this Object Type
     176         *
     177         * @example:
     178         *
     179         *    $object_type = new WP_Object_Type();
     180         *    $object_type->assign( 'post:my_type' )
     181         *
     182         * Which is equivalent to:
     183         *
     184         *    $object_type = new WP_Object_Type( 'post:my_type' )
     185         *
     186         * @param bool|string|array|WP_Object_Type $object_type
     187         *
     188         * @todo Add error handling for invalid type.
     189         *
     190         */
     191        function assign( $object_type = false ) {
     192
     193                do {
     194
     195                        if ( empty( $object_type ) ) {
     196
     197                                trigger_error( __METHOD__ . '() cannot be called with an empty or missing parameter.' );
     198
     199                        }
     200
     201                        if ( is_a( $object_type, __CLASS__ ) ) {
     202
     203                                /**
     204                                 * If a WP_Object_Type object was passed in then copy it's values.
     205                                 *
     206                                 * @see The PHPDoc for __construct() to understand why accepting an
     207                                 *      object in addition to a string literal is useful.
     208                                 */
     209                                $this->type    = $object_type->type;
     210
     211                                $this->subtype = $object_type->subtype;
     212
     213                                break;
     214
     215                        }
     216
     217                        if ( is_object( $object_type ) ) {
     218
     219                                /**
     220                                 * If another type object grab its ->type and ->subtype properties,
     221                                 * if it has them.
     222                                 *
     223                                 * @see The PHPDoc for __construct() to understand why accepting an
     224                                 *      object in addition to a string literal is useful.
     225                                 */
     226                                $this->type    = isset( $object_type->type )
     227                                        ? $object_type->type
     228                                        : null;
     229
     230                                $this->subtype = isset( $object_type->subtype ) && is_string( $object_type->subtype )
     231                                        ? $object_type->subtype
     232                                        : null;
     233
     234                                break;
     235
     236                        }
     237
     238                        if ( is_array( $object_type ) && 2 === count( $object_type ) && isset( $object_type[0] ) && isset( $object_type[1] ) ) {
     239
     240                                /**
     241                                 * A 2 element numerically indexed array where the first element is
     242                                 * $class and the 2nd is $subtype. So assign it.
     243                                 */
     244
     245                                list( $this->type, $this->subtype ) = $object_type;
     246
     247                                break;
     248
     249                        }
     250
     251                        if ( is_array( $object_type ) ) {
     252
     253                                /*
     254                                 * Assumes the $object_type passed in is either an associative array with 'type'
     255                                 * and 'subtype' properties or an object that is not of class WP_Object_Type with
     256                                 * $class and $subtype properties
     257                                 *
     258                                 * Not sure why an object not of type WP_Object_Type would ever be needed, but if
     259                                 * someone finds a need for it this this method will support initializing from its
     260                                 * property values.
     261                                 *
     262                                 * Convert the array to object and call recursively.
     263                                 */
     264                                $this->assign( (object) $object_type );
     265                                break;
     266
     267                        }
     268
     269                        if ( is_string( $object_type ) && false !== strpos( $object_type, ':' ) ) {
     270
     271                                /**
     272                                 * Otherwise split the Object Type literal on a the colon and assign
     273                                 * to $class and $subtype, respectively.
     274                                 */
     275                                list( $this->type, $this->subtype ) = explode( ':', $object_type );
     276
     277                                break;
     278                        }
     279
     280                        if ( is_string( $object_type ) ) {
     281
     282                                /**
     283                                 * And the literal contains no colon it is a type,
     284                                 * and its subtype is 'any'
     285                                 * and the string literal passed in is the $subtype (often used
     286                                 * with custom post types.)
     287                                 */
     288                                $this->type    = $object_type;
     289                                break;
     290
     291                        }
     292
     293                } while ( false );
     294
     295
     296
     297                if ( $this->type && is_string( $this->type ) ) {
     298
     299                        /**
     300                         *  Ensure $class is sanitized to be a valid identifier
     301                         */
     302                        $this->type = sanitize_title_with_dashes( $this->type );
     303
     304                }
     305
     306                if ( $this->subtype && is_string( $this->subtype ) ) {
     307                        /**
     308                         *  Ensure $subtype is sanitized to be a valid identifier too, but only need to do if not empty.
     309                         */
     310                        $this->subtype = sanitize_title_with_dashes( $this->subtype );
     311
     312                }
     313
     314                if ( $this->type && empty( $this->subtype ) ) {
     315                        /**
     316                         * Lastly, if $subtype is still empty, set to 'any'.
     317                         */
     318                        $this->subtype = 'any';
     319
     320                }
     321
     322
     323                /**
     324                 * Posts are the only object type with support for object sub types.
     325                 *
     326                 * @note Leaving this in because it was in 35658.4.diff patch but I don't feel it is needed.
     327                 */
     328                if ( 'post' !== $this->type ) {
     329
     330                        /*
     331                         * Set to 'any', even though we *could* support it
     332                         * by just deleting these three lines
     333                         */
     334                        $this->subtype = 'any';
     335
     336                }
     337
     338        }
     339
     340        /**
     341         * @return string[]
     342         */
     343        static function object_types() {
     344
     345                return array_keys( self::$_short_types );
     346
     347        }
     348
     349        /**
     350         * @return string[]
     351         */
     352        static function short_types() {
     353
     354                return self::$_short_types;
     355
     356        }
     357
     358        /**
     359         * @return bool
     360         */
     361        function is_post_type() {
     362
     363                return 'post' === $this->type;
     364
     365        }
     366
     367        /**
     368         * @return bool
     369         */
     370        function is_user_type() {
     371
     372                return 'user' === $this->type;
     373
     374        }
     375
     376        /**
     377         * @return bool
     378         */
     379        function is_comment_type() {
     380
     381                return 'comment' === $this->type;
     382
     383        }
     384
     385        /**
     386         * @return bool
     387         */
     388        function is_term_type() {
     389
     390                return 'term' === $this->type;
     391
     392        }
     393
     394        /**
     395         * Returns the shortest representation of type that is possible
     396         *
     397         * @return null|string
     398         */
     399        function short_type() {
     400
     401                return ! empty( $this->type )
     402                        ? self::$_short_types[ $this->type ]
     403                        : null;
     404
     405        }
     406
     407        /**
     408         * Returns a short representation of object type
     409         *
     410         * This is useful when you want to create a slug that idenfies a relationship
     411         * between two object_types but you have limited number of characters, such
     412         * as the wp_term_taxonomy->taxonomy field which is limited to 32 characters.
     413         *
     414         * @return null|string
     415         */
     416        function short_object_type() {
     417
     418                if ( is_null( $this->subtype ) ) {
     419
     420                        $short_object_type = $this->type;
     421
     422                } else if ( 'post' === $this->type ) {
     423
     424                        if ( ! defined( 'WP_APP_PREFIX' ) ) {
     425
     426                                $short_object_type = $this->subtype;
     427
     428                        } else {
     429
     430                                $regex = '#^' . preg_quote( WP_APP_PREFIX ) . '(.+)$#';
     431                                $short_object_type = preg_replace( $regex, '$1', $this->subtype );
     432
     433                        }
     434
     435                } else {
     436
     437                        $subtype = 'any' !== $this->subtype
     438                                ? $this->subtype
     439                                : '';
     440
     441                        $short_object_type = $this->short_type() . ":{$subtype}";
     442
     443                }
     444
     445                return $short_object_type;
     446
     447        }
     448
     449        /**
     450         * Check if the current Object Type is valid.
     451         *
     452         * Validity is determined by having a non-empty $type value.
     453         *
     454         * @return bool Is the Object Type valid?
     455         */
     456        function is_valid() {
     457
     458                return ! empty( $this->type );
     459
     460        }
     461
     462        /**
     463         * Check if the current Object Type is equivalent to the one passed in.
     464         *
     465         * Equivalency is true if both objects have the same values for their $class and $subtype properties.
     466         *
     467         * If not parameter is passed then this method assume an object type based on the global $post object.
     468         *
     469         * @param WP_Object_Type|string|bool $object_type The Object Type to compare with $this.
     470         *
     471         * @return bool If $object_type is equivalent to $this.
     472         */
     473        function is_equivalent( $object_type = false ) {
     474
     475                if ( ! is_a( $object_type, __CLASS__ ) ) {
     476                        /*
     477                         * First check to see if the passed in parameter is a WP_Object_Type object.
     478                         * If not, instantiate a new object with the passed $arg.
     479                         */
     480                        $object_type = new self( $object_type );
     481
     482                }
     483
     484                /**
     485                 * Check for object equivalency
     486                 * Yes this is correct (if you thought it was not, like I did at first.)
     487                 */
     488                return $this == $object_type;
     489
     490        }
     491
     492        /**
     493         * Magic method to convert the Object Type into it's string literal form.
     494         *
     495         * @return string  An Object Type literal representing $this, the current Object Type.
     496         */
     497        function __toString() {
     498
     499                return "{$this->type}:{$this->subtype}";
     500
     501        }
     502}
  • www/wp-includes/meta.php

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
     
    1717 *
    1818 * @global wpdb $wpdb WordPress database abstraction object.
    1919 *
    20  * @param string $meta_type  Type of object metadata is for (e.g., comment, post, or user)
     20 * @param WP_Object_Type|string $object_type  Type of object metadata is for (e.g., comment, post, or user)
    2121 * @param int    $object_id  ID of the object metadata is for
    2222 * @param string $meta_key   Metadata key
    2323 * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
     
    2727 *                           no change will be made.
    2828 * @return int|false The meta ID on success, false on failure.
    2929 */
    30 function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) {
     30function add_metadata( $object_type, $object_id, $meta_key, $meta_value, $unique = false ) {
    3131        global $wpdb;
    3232
    33         if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
     33        if ( ! $object_type || ! $meta_key || ! is_numeric( $object_id ) ) {
    3434                return false;
    3535        }
    3636
     
    3939                return false;
    4040        }
    4141
     42        if ( ! $object_type instanceof WP_Object_Type ) {
     43                $object_type = new WP_Object_Type( $object_type );
     44        }
     45
     46        $meta_type = $object_type->type;
     47
    4248        $table = _get_meta_table( $meta_type );
    4349        if ( ! $table ) {
    4450                return false;
     
    6672         * @param mixed     $meta_value Meta value. Must be serializable if non-scalar.
    6773         * @param bool      $unique     Whether the specified meta key should be unique
    6874         *                              for the object. Optional. Default false.
     75         * @param WP_Object_Type    $object_type  Type and subtype of object
    6976         */
    70         $check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique );
     77        $check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique, $object_type );
    7178        if ( null !== $check )
    7279                return $check;
    7380
     
    9097         * @param int    $object_id  Object ID.
    9198         * @param string $meta_key   Meta key.
    9299         * @param mixed  $meta_value Meta value.
     100         * @param WP_Object_Type    $object_type  Type and subtype of object
    93101         */
    94         do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value );
     102        do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value, $object_type );
    95103
    96104        $result = $wpdb->insert( $table, array(
    97105                $column => $object_id,
     
    118126         * @param int    $object_id  Object ID.
    119127         * @param string $meta_key   Meta key.
    120128         * @param mixed  $meta_value Meta value.
     129         * @param WP_Object_Type    $object_type  Type and subtype of object
    121130         */
    122         do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value );
     131        do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value, $object_type );
    123132
    124133        return $mid;
    125134}
     
    132141 *
    133142 * @global wpdb $wpdb WordPress database abstraction object.
    134143 *
    135  * @param string $meta_type  Type of object metadata is for (e.g., comment, post, or user)
     144 * @param WP_Object_Type|string $object_type  Type of object metadata is for (e.g., comment, post, or user)
    136145 * @param int    $object_id  ID of the object metadata is for
    137146 * @param string $meta_key   Metadata key
    138147 * @param mixed  $meta_value Metadata value. Must be serializable if non-scalar.
     
    140149 *                                   the specified value. Otherwise, update all entries.
    141150 * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
    142151 */
    143 function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') {
     152function update_metadata( $object_type, $object_id, $meta_key, $meta_value, $prev_value = '' ) {
    144153        global $wpdb;
    145154
    146         if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
     155        if ( ! $object_type || ! $meta_key || ! is_numeric( $object_id ) ) {
    147156                return false;
    148157        }
    149158
     
    152161                return false;
    153162        }
    154163
     164        if ( ! $object_type instanceof WP_Object_Type ) {
     165                $object_type = new WP_Object_Type( $object_type );
     166        }
     167
     168        $meta_type = $object_type->type;
     169
    155170        $table = _get_meta_table( $meta_type );
    156171        if ( ! $table ) {
    157172                return false;
     
    183198         * @param mixed     $prev_value Optional. If specified, only update existing
    184199         *                              metadata entries with the specified value.
    185200         *                              Otherwise, update all entries.
     201         * @param WP_Object_Type    $object_type  Type and subtype of object
    186202         */
    187         $check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value );
     203        $check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value, $object_type );
    188204        if ( null !== $check )
    189205                return (bool) $check;
    190206
     
    226242                 * @param int    $object_id  Object ID.
    227243                 * @param string $meta_key   Meta key.
    228244                 * @param mixed  $meta_value Meta value.
     245                 * @param WP_Object_Type    $object_type  Type and subtype of object
    229246                 */
    230                 do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
     247                do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value, $object_type );
    231248
    232249                if ( 'post' == $meta_type ) {
    233250                        /**
     
    239256                         * @param int    $object_id  Object ID.
    240257                         * @param string $meta_key   Meta key.
    241258                         * @param mixed  $meta_value Meta value.
     259                         * @param WP_Object_Type    $object_type  Type and subtype of object
    242260                         */
    243                         do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
     261                        do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value, $object_type );
    244262                }
    245263        }
    246264
     
    263281                 * @param int    $object_id  Object ID.
    264282                 * @param string $meta_key   Meta key.
    265283                 * @param mixed  $meta_value Meta value.
     284                 * @param WP_Object_Type    $object_type  Type and subtype of object
    266285                 */
    267                 do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
     286                do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value, $object_type );
    268287
    269288                if ( 'post' == $meta_type ) {
    270289                        /**
     
    276295                         * @param int    $object_id  Object ID.
    277296                         * @param string $meta_key   Meta key.
    278297                         * @param mixed  $meta_value Meta value.
     298                         * @param WP_Object_Type    $object_type  Type and subtype of object
    279299                         */
    280                         do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
     300                        do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value, $object_type );
    281301                }
    282302        }
    283303
     
    291311 *
    292312 * @global wpdb $wpdb WordPress database abstraction object.
    293313 *
    294  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
     314 * @param WP_Object_Type|string $object_type Type of object metadata is for (e.g., comment, post, or user)
    295315 * @param int    $object_id  ID of the object metadata is for
    296316 * @param string $meta_key   Metadata key
    297317 * @param mixed  $meta_value Optional. Metadata value. Must be serializable if non-scalar. If specified, only delete
     
    304324 *                           the specified object_id.
    305325 * @return bool True on successful delete, false on failure.
    306326 */
    307 function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) {
     327function delete_metadata( $object_type, $object_id, $meta_key, $meta_value = '', $delete_all = false ) {
    308328        global $wpdb;
    309329
    310         if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) && ! $delete_all ) {
     330        if ( ! $object_type || ! $meta_key || ! is_numeric( $object_id ) && ! $delete_all ) {
    311331                return false;
    312332        }
    313333
     
    316336                return false;
    317337        }
    318338
     339        if ( ! $object_type instanceof WP_Object_Type ) {
     340                $object_type = new WP_Object_Type( $object_type );
     341        }
     342
     343        $meta_type = $object_type->type;
     344
    319345        $table = _get_meta_table( $meta_type );
    320346        if ( ! $table ) {
    321347                return false;
     
    343369         * @param bool      $delete_all Whether to delete the matching metadata entries
    344370         *                              for all objects, ignoring the specified $object_id.
    345371         *                              Default false.
     372         * @param WP_Object_Type    $object_type  Type and subtype of object
    346373         */
    347         $check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all );
     374        $check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all, $object_type );
    348375        if ( null !== $check )
    349376                return (bool) $check;
    350377
     
    384411         * @param int    $object_id  Object ID.
    385412         * @param string $meta_key   Meta key.
    386413         * @param mixed  $meta_value Meta value.
     414         * @param WP_Object_Type    $object_type  Type and subtype of object
    387415         */
    388         do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
     416        do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value, $object_type );
    389417
    390418        // Old-style action.
    391419        if ( 'post' == $meta_type ) {
     
    395423                 * @since 2.9.0
    396424                 *
    397425                 * @param array $meta_ids An array of post metadata entry IDs to delete.
     426                 * @param WP_Object_Type    $object_type  Type and subtype of object
    398427                 */
    399                 do_action( 'delete_postmeta', $meta_ids );
     428                do_action( 'delete_postmeta', $meta_ids, $object_type );
    400429        }
    401430
    402431        $query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . " )";
     
    426455         * @param int    $object_id  Object ID.
    427456         * @param string $meta_key   Meta key.
    428457         * @param mixed  $meta_value Meta value.
     458         * @param WP_Object_Type    $object_type  Type and subtype of object
    429459         */
    430         do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
     460        do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value, $object_type );
    431461
    432462        // Old-style action.
    433463        if ( 'post' == $meta_type ) {
     
    437467                 * @since 2.9.0
    438468                 *
    439469                 * @param array $meta_ids An array of deleted post metadata entry IDs.
     470                 * @param WP_Object_Type    $object_type  Type and subtype of object
    440471                 */
    441                 do_action( 'deleted_postmeta', $meta_ids );
     472                do_action( 'deleted_postmeta', $meta_ids, $object_type );
    442473        }
    443474
    444475        return true;
     
    449480 *
    450481 * @since 2.9.0
    451482 *
    452  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
     483 * @param WP_Object_Type|string $object_type Type of object metadata is for (e.g., comment, post, or user)
    453484 * @param int    $object_id ID of the object metadata is for
    454485 * @param string $meta_key  Optional. Metadata key. If not specified, retrieve all metadata for
    455486 *                                  the specified object.
     
    458489 *                          This parameter has no effect if meta_key is not specified.
    459490 * @return mixed Single metadata value, or array of values
    460491 */
    461 function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) {
    462         if ( ! $meta_type || ! is_numeric( $object_id ) ) {
     492function get_metadata( $object_type, $object_id, $meta_key = '', $single = false ) {
     493
     494        if ( ! $object_type || ! is_numeric( $object_id ) ) {
    463495                return false;
    464496        }
    465497
     
    468500                return false;
    469501        }
    470502
     503        if ( ! $object_type instanceof WP_Object_Type ) {
     504                $object_type = new WP_Object_Type( $object_type );
     505        }
     506
     507        $meta_type = $object_type->type;
     508
    471509        /**
    472510         * Filters whether to retrieve metadata of a specific type.
    473511         *
     
    482520         * @param int               $object_id Object ID.
    483521         * @param string            $meta_key  Meta key.
    484522         * @param bool              $single    Whether to return only the first value of the specified $meta_key.
     523         * @param WP_Object_Type    $object_type  Type and subtype of object
    485524         */
    486         $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single );
     525        $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single, $object_type );
    487526        if ( null !== $check ) {
    488527                if ( $single && is_array( $check ) )
    489528                        return $check[0];
     
    520559 *
    521560 * @since 3.3.0
    522561 *
    523  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
     562 * @param WP_Object_Type|string $object_type Type of object metadata is for (e.g., comment, post, or user)
    524563 * @param int    $object_id ID of the object metadata is for
    525564 * @param string $meta_key  Metadata key.
    526565 * @return bool True of the key is set, false if not.
    527566 */
    528 function metadata_exists( $meta_type, $object_id, $meta_key ) {
    529         if ( ! $meta_type || ! is_numeric( $object_id ) ) {
     567function metadata_exists( $object_type, $object_id, $meta_key ) {
     568        if ( ! $object_type || ! is_numeric( $object_id ) ) {
    530569                return false;
    531570        }
    532571
     
    535574                return false;
    536575        }
    537576
     577        if ( ! $object_type instanceof WP_Object_Type ) {
     578                $object_type = new WP_Object_Type( $object_type );
     579        }
     580
     581        $meta_type = $object_type->type;
     582
    538583        /** This filter is documented in wp-includes/meta.php */
    539         $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true );
     584        $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true , $object_type);
    540585        if ( null !== $check )
    541586                return (bool) $check;
    542587
     
    560605 *
    561606 * @global wpdb $wpdb WordPress database abstraction object.
    562607 *
    563  * @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
     608 * @param WP_Object_Type|string $object_type Type of object metadata is for (e.g., comment, post, or user)
    564609 * @param int    $meta_id   ID for a specific meta row
    565610 * @return object|false Meta object or false.
    566611 */
    567 function get_metadata_by_mid( $meta_type, $meta_id ) {
     612function get_metadata_by_mid( $object_type, $meta_id ) {
    568613        global $wpdb;
    569614
    570         if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
     615        if ( ! $object_type || ! is_numeric( $meta_id ) ) {
    571616                return false;
    572617        }
    573618
     
    576621                return false;
    577622        }
    578623
     624        if ( ! $object_type instanceof WP_Object_Type ) {
     625                $object_type = new WP_Object_Type( $object_type );
     626        }
     627
     628        $meta_type = $object_type->type;
     629
    579630        $table = _get_meta_table( $meta_type );
    580631        if ( ! $table ) {
    581632                return false;
     
    601652 *
    602653 * @global wpdb $wpdb WordPress database abstraction object.
    603654 *
    604  * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
     655 * @param WP_Object_Type|string $object_type Type of object metadata is for (e.g., comment, post, or user)
    605656 * @param int    $meta_id    ID for a specific meta row
    606657 * @param string $meta_value Metadata value
    607  * @param string $meta_key   Optional, you can provide a meta key to update it
     658 * @param string|bool $meta_key   Optional, you can provide a meta key to update it
    608659 * @return bool True on successful update, false on failure.
    609660 */
    610 function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) {
     661function update_metadata_by_mid( $object_type, $meta_id, $meta_value, $meta_key = false ) {
    611662        global $wpdb;
    612663
    613664        // Make sure everything is valid.
    614         if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
     665        if ( ! $object_type || ! is_numeric( $meta_id ) ) {
    615666                return false;
    616667        }
    617668
     
    620671                return false;
    621672        }
    622673
     674        if ( ! $object_type instanceof WP_Object_Type ) {
     675                $object_type = new WP_Object_Type( $object_type );
     676        }
     677
     678        $meta_type = $object_type->type;
     679
    623680        $table = _get_meta_table( $meta_type );
    624681        if ( ! $table ) {
    625682                return false;
     
    657714                $where[$id_column] = $meta_id;
    658715
    659716                /** This action is documented in wp-includes/meta.php */
    660                 do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
     717                do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value, $object_type );
    661718
    662719                if ( 'post' == $meta_type ) {
    663720                        /** This action is documented in wp-includes/meta.php */
    664                         do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
     721                        do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value, $object_type );
    665722                }
    666723
    667724                // Run the update query, all fields in $data are %s, $where is a %d.
     
    673730                wp_cache_delete($object_id, $meta_type . '_meta');
    674731
    675732                /** This action is documented in wp-includes/meta.php */
    676                 do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
     733                do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value, $object_type );
    677734
    678735                if ( 'post' == $meta_type ) {
    679736                        /** This action is documented in wp-includes/meta.php */
    680                         do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
     737                        do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value, $object_type );
    681738                }
    682739
    683740                return true;
     
    694751 *
    695752 * @global wpdb $wpdb WordPress database abstraction object.
    696753 *
    697  * @param string $meta_type Type of object metadata is for (e.g., comment, post, term, or user).
     754 * @param WP_Object_Type|string $object_type Type of object metadata is for (e.g., comment, post, or user)
    698755 * @param int    $meta_id   ID for a specific meta row
    699756 * @return bool True on successful delete, false on failure.
    700757 */
    701 function delete_metadata_by_mid( $meta_type, $meta_id ) {
     758function delete_metadata_by_mid( $object_type, $meta_id ) {
    702759        global $wpdb;
    703760
    704761        // Make sure everything is valid.
    705         if ( ! $meta_type || ! is_numeric( $meta_id ) ) {
     762        if ( ! $object_type || ! is_numeric( $meta_id ) ) {
    706763                return false;
    707764        }
    708765
     
    711768                return false;
    712769        }
    713770
     771        if ( ! $object_type instanceof WP_Object_Type ) {
     772                $object_type = new WP_Object_Type( $object_type );
     773        }
     774
     775        $meta_type = $object_type->type;
     776
    714777        $table = _get_meta_table( $meta_type );
    715778        if ( ! $table ) {
    716779                return false;
     
    725788                $object_id = $meta->{$column};
    726789
    727790                /** This action is documented in wp-includes/meta.php */
    728                 do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
     791                do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value, $object_type );
    729792
    730793                // Old-style action.
    731794                if ( 'post' == $meta_type || 'comment' == $meta_type ) {
     
    738801                         * @since 3.4.0
    739802                         *
    740803                         * @param int $meta_id ID of the metadata entry to delete.
     804                         * @param WP_Object_Type    $object_type  Type and subtype of object
    741805                         */
    742                         do_action( "delete_{$meta_type}meta", $meta_id );
     806                        do_action( "delete_{$meta_type}meta", $meta_id, $object_type );
    743807                }
    744808
    745809                // Run the query, will return true if deleted, false otherwise
     
    749813                wp_cache_delete($object_id, $meta_type . '_meta');
    750814
    751815                /** This action is documented in wp-includes/meta.php */
    752                 do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
     816                do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value, $object_type );
    753817
    754818                // Old-style action.
    755819                if ( 'post' == $meta_type || 'comment' == $meta_type ) {
     
    762826                         * @since 3.4.0
    763827                         *
    764828                         * @param int $meta_ids Deleted metadata entry ID.
     829                         * @param WP_Object_Type    $object_type  Type and subtype of object
    765830                         */
    766                         do_action( "deleted_{$meta_type}meta", $meta_id );
     831                        do_action( "deleted_{$meta_type}meta", $meta_id, $object_type );
    767832                }
    768833
    769834                return $result;
     
    781846 *
    782847 * @global wpdb $wpdb WordPress database abstraction object.
    783848 *
    784  * @param string    $meta_type Type of object metadata is for (e.g., comment, post, or user)
     849 * @param WP_Object_Type|string $object_type Type of object metadata is for (e.g., comment, post, or user)
    785850 * @param int|array $object_ids Array or comma delimited list of object IDs to update cache for
    786851 * @return array|false Metadata cache for the specified objects, or false on failure.
    787852 */
    788 function update_meta_cache($meta_type, $object_ids) {
     853function update_meta_cache( $object_type, $object_ids) {
    789854        global $wpdb;
    790855
    791         if ( ! $meta_type || ! $object_ids ) {
     856        if ( ! $object_type || ! $object_ids ) {
    792857                return false;
    793858        }
    794859
     860        if ( ! $object_type instanceof WP_Object_Type ) {
     861                $object_type = new WP_Object_Type( $object_type );
     862        }
     863
     864        $meta_type = $object_type->type;
     865
    795866        $table = _get_meta_table( $meta_type );
    796867        if ( ! $table ) {
    797868                return false;
     
    894965 *
    895966 * @global wpdb $wpdb WordPress database abstraction object.
    896967 *
    897  * @param string $type Type of object to get metadata table for (e.g., comment, post, or user)
     968 * @param WP_Object_Type|string $object_type Type of object metadata is for (e.g., comment, post, or user)
    898969 * @return string|false Metadata table name, or false if no metadata table exists
    899970 */
    900 function _get_meta_table($type) {
     971function _get_meta_table( $object_type ) {
    901972        global $wpdb;
    902973
    903         $table_name = $type . 'meta';
     974        if ( ! $object_type instanceof WP_Object_Type ) {
     975                $object_type = new WP_Object_Type( $object_type );
     976        }
    904977
     978        $table_name = $object_type->type . 'meta';
     979
    905980        if ( empty($wpdb->$table_name) )
    906981                return false;
    907982
     
    914989 * @since 3.1.3
    915990 *
    916991 * @param string      $meta_key Meta key
    917  * @param string|null $meta_type
     992 * @param WP_Object_Type|string|null $object_type Type of object metadata is for (e.g., comment, post, or user)
    918993 * @return bool True if the key is protected, false otherwise.
    919994 */
    920 function is_protected_meta( $meta_key, $meta_type = null ) {
     995function is_protected_meta( $meta_key, $object_type = null ) {
    921996        $protected = ( '_' == $meta_key[0] );
    922997
    923998        /**
     
    9291004         * @param string $meta_key  Meta key.
    9301005         * @param string $meta_type Meta type.
    9311006         */
    932         return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
     1007        return apply_filters( 'is_protected_meta', $protected, $meta_key, $object_type->type, $object_type );
    9331008}
    9341009
    9351010/**
    9361011 * Sanitize meta value.
    9371012 *
    9381013 * @since 3.1.3
     1014 * @since 4.6.0 Added the `$object_subtype` parameter.
    9391015 *
    940  * @param string $meta_key   Meta key
    941  * @param mixed  $meta_value Meta value to sanitize
    942  * @param string $meta_type  Type of meta
    943  * @return mixed Sanitized $meta_value
     1016 * @param string $meta_key       Meta key.
     1017 * @param mixed  $meta_value     Meta value to sanitize.
     1018 * @param WP_Object_Type|string $object_type  Type of object the meta is registered to.
     1019 *
     1020 * @return mixed Sanitized $meta_value.
    9441021 */
    945 function sanitize_meta( $meta_key, $meta_value, $meta_type ) {
     1022function sanitize_meta( $meta_key, $meta_value, $object_type ) {
    9461023
     1024        if ( ! $object_type instanceof WP_Object_Type ) {
     1025                $object_type = new WP_Object_Type( $object_type );
     1026        }
     1027
    9471028        /**
    9481029         * Filters the sanitization of a specific meta key of a specific meta type.
    9491030         *
     
    9581039         * @param string $meta_key   Meta key.
    9591040         * @param string $meta_type  Meta type.
    9601041         */
    961         return apply_filters( "sanitize_{$meta_type}_meta_{$meta_key}", $meta_value, $meta_key, $meta_type );
     1042        return apply_filters( "sanitize_{$object_type->type}_meta_{$meta_key}", $meta_value, $meta_key, $object_type );
    9621043}
    9631044
    9641045/**
    965  * Register meta key
     1046 * Registers a meta key.
    9661047 *
    9671048 * @since 3.3.0
     1049 * @since 4.6.0 Modified to support an array of data to attach to registered meta keys. Previous arguments for
     1050 *              `$sanitize_callback` and `$auth_callback` have been folded into this array.
    9681051 *
    969  * @param string       $meta_type         Type of meta
    970  * @param string       $meta_key          Meta key
    971  * @param string|array $sanitize_callback A function or method to call when sanitizing the value of $meta_key.
    972  * @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.
     1052 * @param WP_Object_Type|string $object_type  Type of object the meta is registered to.
     1053 * @param string $meta_key                    Meta key to register.
     1054 * @param array  $args {
     1055 *     Data used to describe the meta key when registered.
     1056 *
     1057 *     @type string   $sanitize_callback A function or method to call when sanitizing `$meta_key` data.
     1058 *     @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.
     1059 *     @type string   $type              The type of data associated with this meta key.
     1060 *     @type string   $description       A description of the data attached to this meta key.
     1061 *     @type bool     $show_in_rest      Whether data associated with this meta key can be considered public.
     1062 * }
    9731063 */
    974 function register_meta( $meta_type, $meta_key, $sanitize_callback, $auth_callback = null ) {
    975         if ( is_callable( $sanitize_callback ) )
    976                 add_filter( "sanitize_{$meta_type}_meta_{$meta_key}", $sanitize_callback, 10, 3 );
     1064function register_meta( $object_type, $meta_key, $args ) {
     1065        global $wp_meta_keys;
    9771066
    978         if ( empty( $auth_callback ) ) {
    979                 if ( is_protected_meta( $meta_key, $meta_type ) )
    980                         $auth_callback = '__return_false';
    981                 else
    982                         $auth_callback = '__return_true';
     1067        if ( ! $object_type instanceof WP_Object_Type ) {
     1068                $object_type = new WP_Object_Type( $object_type );
    9831069        }
    9841070
    985         if ( is_callable( $auth_callback ) )
    986                 add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 );
     1071        if ( ! is_array( $wp_meta_keys ) ) {
     1072                $wp_meta_keys = array();
     1073        }
     1074
     1075        $meta_args = (object) array(
     1076                'sanitize_callback' => null,
     1077                'old_sanitize_callback' => null,
     1078                'auth_callback' => null,
     1079                'old_auth_callback' => null,
     1080                'object_subtype' => '',
     1081                'type' => 'string',
     1082                'description' => '',
     1083                'show_in_rest' => false,
     1084        );
     1085
     1086        $passed_args = array_slice( func_get_args(), 2 );
     1087
     1088        if ( is_callable( $passed_args[0] ) ) {
     1089                $meta_args->old_sanitize_callback = $passed_args[0];
     1090        } elseif ( isset( $passed_args[0]['sanitize_callback'] ) ) {
     1091                $meta_args->sanitize_callback = $passed_args[0]['sanitize_callback'];
     1092        }
     1093
     1094        if ( isset( $passed_args[1] ) && is_callable( $passed_args[1] ) ) {
     1095                $meta_args->old_auth_callback = $passed_args[1];
     1096        } elseif ( isset( $passed_args[0]['auth_callback'] ) ) {
     1097                $meta_args->auth_callback = $passed_args[0]['auth_callback'];
     1098        }
     1099
     1100        if ( isset( $passed_args[0]['show_in_rest'] ) && $passed_args[0]['show_in_rest'] ) {
     1101                $meta_args->show_in_rest = true;
     1102        }
     1103
     1104        if ( isset( $passed_args[0]['type'] ) ) {
     1105                $meta_args->type = $passed_args[0]['type'];
     1106        }
     1107
     1108        if ( isset( $passed_args[0]['description'] ) ) {
     1109                $meta_args->description = $passed_args[0]['description'];
     1110        }
     1111
     1112        $wp_meta_keys[ $object_type->type ][ $object_type->subtype ][ $meta_key ] = $args;
     1113
     1114        if ( is_callable( $meta_args->old_sanitize_callback ) ) {
     1115                add_filter( "sanitize_{$object_type->type}_meta_{$meta_key}", $meta_args->old_sanitize_callback, 10, 3 );
     1116        }
     1117
     1118        if ( is_callable( $meta_args->sanitize_callback ) ) {
     1119                add_filter( "sanitize_{$object_type->type}_meta_{$meta_key}", $meta_args->sanitize_callback, 10, 3 );
     1120        }
     1121
     1122        // If neither new or legacy `auth_callback` is provided, fallback to `is_protected_meta()`.
     1123        if ( empty( $meta_args->auth_callback ) && empty( $meta_args->old_auth_callback ) ) {
     1124                if ( is_protected_meta( $meta_key, $object_type ) ) {
     1125                        $meta_args->auth_callback = '__return_false';
     1126                } else {
     1127                        $meta_args->auth_callback = '__return_true';
     1128                }
     1129        }
     1130
     1131        // The auth here is currently used to edit or add meta, not to view, and only for posts.
     1132        if ( 'post' === $object_type->type && is_callable( $meta_args->old_auth_callback ) ) {
     1133                add_filter( "auth_{$object_type->type}_meta_{$meta_key}", $meta_args->old_auth_callback, 10, 6 );
     1134        }
     1135
     1136        if ( 'post' === $object_type->type && is_callable( $meta_args->auth_callback ) ) {
     1137                add_filter( "auth_{$object_type->type}_meta_{$meta_key}", $meta_args->auth_callback, 10, 6 );
     1138        }
     1139}
     1140
     1141/**
     1142 * Checks if a meta key is registered.
     1143 *
     1144 * @since 4.6.0
     1145 *
     1146 * @param WP_Object_Type|string $object_type  Type of object the meta is registered to.
     1147 * @param string $meta_key
     1148 *
     1149 * @return bool True if the meta key is registered to the object type and subtype. False if not.
     1150 */
     1151function registered_meta_key_exists( $object_type, $meta_key ) {
     1152        global $wp_meta_keys;
     1153
     1154        if ( ! is_array( $wp_meta_keys ) ) {
     1155                return false;
     1156        }
     1157
     1158        if ( ! $object_type instanceof WP_Object_Type ) {
     1159                $object_type = new WP_Object_Type( $object_type );
     1160        }
     1161
     1162        if ( ! isset( $wp_meta_keys[ $object_type->type ] ) ) {
     1163                return false;
     1164        }
     1165
     1166        if ( ! isset( $wp_meta_keys[ $object_type->type ][ $object_type->subtype ] ) ) {
     1167                return false;
     1168        }
     1169
     1170        if ( isset( $wp_meta_keys[ $object_type->type ][ $object_type->subtype ][ $meta_key ] ) ) {
     1171                return true;
     1172        }
     1173
     1174        return false;
     1175}
     1176
     1177/**
     1178 * Unregisters a meta key from the list of registered keys.
     1179 *
     1180 * @since 4.6.0
     1181 *
     1182 * @param WP_Object_Type|string $object_type  Type of object the meta is registered to.
     1183 * @param string $meta_key       The meta key.
     1184 *
     1185 * @return bool|WP_Error True if successful. WP_Error if the meta key is invalid.
     1186 */
     1187function unregister_meta_key( $object_type, $meta_key ) {
     1188        global $wp_meta_keys;
     1189
     1190        if ( ! registered_meta_key_exists( $object_type, $meta_key ) ) {
     1191                return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key' ) );
     1192        }
     1193
     1194        if ( ! $object_type instanceof WP_Object_Type ) {
     1195                $object_type = new WP_Object_Type( $object_type );
     1196        }
     1197
     1198        unset( $wp_meta_keys[ $object_type->type ][ $object_type->subtype ][ $meta_key ] );
     1199
     1200        return true;
     1201}
     1202
     1203/**
     1204 * Retrieves a list of registered meta keys for an object type and subtype.
     1205 *
     1206 * @since 4.6.0
     1207 *
     1208 * @param WP_Object_Type|string $object_type  Type of object the meta is registered to.
     1209 *
     1210 * @return array List of registered meta keys.
     1211 */
     1212function get_registered_meta_keys( $object_type ) {
     1213        global $wp_meta_keys;
     1214
     1215        if ( ! $object_type instanceof WP_Object_Type ) {
     1216                $object_type = new WP_Object_Type( $object_type );
     1217        }
     1218
     1219        if ( ! isset( $wp_meta_keys[ $object_type->type ] ) ) {
     1220                return array();
     1221        }
     1222
     1223        if ( ! isset( $wp_meta_keys[ $object_type->type ][ $object_type->subtype ] ) ) {
     1224                return array();
     1225        }
     1226
     1227        return $wp_meta_keys[ $object_type->type ][ $object_type->subtype ];
     1228}
     1229
     1230/**
     1231 * Retrieves registered metadata for a specified object.
     1232 *
     1233 * @since 4.6.0
     1234 *
     1235 * @param WP_Object_Type|string $object_type  Type of object to request metadata for. (e.g. comment, post, term, user)
     1236 * @param int    $object_id      ID of the object the metadata is for.
     1237 * @param string $meta_key       Optional. Registered metadata key. If not specified, retrieve all registered
     1238 *                               metadata for the specified object.
     1239 *
     1240 * @return mixed|WP_Error
     1241 */
     1242function get_registered_metadata( $object_type, $object_id, $meta_key = '' ) {
     1243        global $wp_meta_keys;
     1244       
     1245        if ( ! is_array( $wp_meta_keys ) ) {
     1246                return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered.' ) );
     1247        }
     1248
     1249        if ( ! $object_type instanceof WP_Object_Type ) {
     1250                $object_type = new WP_Object_Type( $object_type );
     1251        }
     1252       
     1253        if ( 'post' === $object_type->type ) {
     1254                $object_type->subtype = get_post_type( $object_id );
     1255        }
     1256
     1257        if( ! empty( $meta_key ) ) {
     1258                if ( ! registered_meta_key_exists( $object_type, $meta_key ) ) {
     1259                        return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered.' ) );
     1260                }
     1261                $meta_keys = get_registered_meta_keys( $object_type );
     1262                $meta_key_data = $meta_keys[ $object_type->type ][ $object_type->subtype ][ $meta_key ];
     1263
     1264                $data = get_metadata( $object_type, $object_id, $meta_key, $meta_key_data->single );
     1265
     1266                return $data;
     1267        }
     1268
     1269        $data = get_metadata( $object_type->type, $object_id, $meta_key );
     1270
     1271        $meta_keys = get_registered_meta_keys( $object_type );
     1272
     1273    $registered_data = array();
     1274
     1275        foreach( $meta_keys as $k => $v ) {
     1276                if ( isset( $data[ $k ] ) ) {
     1277                        $registered_data[ $k ] = $data[ $k ];
     1278                }
     1279        }
     1280
     1281        return $registered_data;
    9871282}