WordPress.org

Make WordPress Core

Ticket #38323: 38323.9.diff

File 38323.9.diff, 58.6 KB (added by tharsheblows, 2 years ago)

post and term wrappers added back in with tests

  • src/wp-includes/capabilities.php

     
    281281                        list( $_, $object_type, $_ ) = explode( '_', $cap );
    282282                        $object_id                   = (int) $args[0];
    283283
    284                         switch ( $object_type ) {
    285                                 case 'post':
    286                                         $post = get_post( $object_id );
    287                                         if ( ! $post ) {
    288                                                 break;
    289                                         }
     284                        $object_subtype = get_object_subtype( $object_type, $object_id );
    290285
    291                                         $sub_type = get_post_type( $post );
    292                                         break;
    293 
    294                                 case 'comment':
    295                                         $comment = get_comment( $object_id );
    296                                         if ( ! $comment ) {
    297                                                 break;
    298                                         }
    299 
    300                                         $sub_type = empty( $comment->comment_type ) ? 'comment' : $comment->comment_type;
    301                                         break;
    302 
    303                                 case 'term':
    304                                         $term = get_term( $object_id );
    305                                         if ( ! $term instanceof WP_Term ) {
    306                                                 break;
    307                                         }
    308 
    309                                         $sub_type = $term->taxonomy;
    310                                         break;
    311 
    312                                 case 'user':
    313                                         $user = get_user_by( 'id', $object_id );
    314                                         if ( ! $user ) {
    315                                                 break;
    316                                         }
    317 
    318                                         $sub_type = 'user';
    319                                         break;
    320                         }
    321 
    322                         if ( empty( $sub_type ) ) {
     286                        if ( empty( $object_subtype ) ) {
    323287                                $caps[] = 'do_not_allow';
    324288                                break;
    325289                        }
     
    328292
    329293                        $meta_key = isset( $args[1] ) ? $args[1] : false;
    330294
    331                         $has_filter = has_filter( "auth_{$object_type}_meta_{$meta_key}" ) || has_filter( "auth_{$object_type}_{$sub_type}_meta_{$meta_key}" );
    332                         if ( $meta_key && $has_filter ) {
     295                        if ( $meta_key ) {
     296                                $allowed = ! is_protected_meta( $meta_key, $object_type );
    333297
    334                                 /**
    335                                  * Filters whether the user is allowed to edit meta for specific object types.
    336                                  *
    337                                  * Return true to have the mapped meta caps from `edit_{$object_type}` apply.
    338                                  *
    339                                  * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered.
    340                                  * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap().
    341                                  *
    342                                  * @since 3.3.0 As `auth_post_meta_{$meta_key}`.
    343                                  * @since 4.6.0
    344                                  *
    345                                  * @param bool     $allowed   Whether the user can add the object meta. Default false.
    346                                  * @param string   $meta_key  The meta key.
    347                                  * @param int      $object_id Object ID.
    348                                  * @param int      $user_id   User ID.
    349                                  * @param string   $cap       Capability name.
    350                                  * @param string[] $caps      Array of the user's capabilities.
    351                                  */
    352                                 $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}", false, $meta_key, $object_id, $user_id, $cap, $caps );
     298                                if ( ! empty( $object_subtype ) && has_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) {
    353299
    354                                 /**
    355                                  * Filters whether the user is allowed to edit meta for specific object types/subtypes.
    356                                  *
    357                                  * Return true to have the mapped meta caps from `edit_{$object_type}` apply.
    358                                  *
    359                                  * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered.
    360                                  * The dynamic portion of the hook name, `$sub_type` refers to the object subtype being filtered.
    361                                  * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap().
    362                                  *
    363                                  * @since 4.6.0 As `auth_post_{$post_type}_meta_{$meta_key}`.
    364                                  * @since 4.7.0
    365                                  *
    366                                  * @param bool     $allowed   Whether the user can add the object meta. Default false.
    367                                  * @param string   $meta_key  The meta key.
    368                                  * @param int      $object_id Object ID.
    369                                  * @param int      $user_id   User ID.
    370                                  * @param string   $cap       Capability name.
    371                                  * @param string[] $caps      Array of the user's capabilities.
    372                                  */
    373                                 $allowed = apply_filters( "auth_{$object_type}_{$sub_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps );
     300                                        /**
     301                                         * Filters whether the user is allowed to edit a specific meta key of a specific object type and subtype.
     302                                         *
     303                                         * The dynamic portions of the hook name, `$object_type`, `$meta_key`,
     304                                         * and `$object_subtype`, refer to the metadata object type (comment, post, term or user),
     305                                         * the meta key value, and the object subtype respectively.
     306                                         *
     307                                         * @since 5.0.0
     308                                         *
     309                                         * @param bool     $allowed   Whether the user can add the object meta. Default false.
     310                                         * @param string   $meta_key  The meta key.
     311                                         * @param int      $object_id Object ID.
     312                                         * @param int      $user_id   User ID.
     313                                         * @param string   $cap       Capability name.
     314                                         * @param string[] $caps      Array of the user's capabilities.
     315                                         */
     316                                        $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps );
     317                                } else {
    374318
     319                                        /**
     320                                         * Filters whether the user is allowed to edit a specific meta key of a specific object type.
     321                                         *
     322                                         * Return true to have the mapped meta caps from `edit_{$object_type}` apply.
     323                                         *
     324                                         * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered.
     325                                         * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap().
     326                                         *
     327                                         * @since 3.3.0 As `auth_post_meta_{$meta_key}`.
     328                                         * @since 4.6.0
     329                                         *
     330                                         * @param bool     $allowed   Whether the user can add the object meta. Default false.
     331                                         * @param string   $meta_key  The meta key.
     332                                         * @param int      $object_id Object ID.
     333                                         * @param int      $user_id   User ID.
     334                                         * @param string   $cap       Capability name.
     335                                         * @param string[] $caps      Array of the user's capabilities.
     336                                         */
     337                                        $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps );
     338                                }
     339
     340                                if ( ! empty( $object_subtype ) ) {
     341
     342                                        /**
     343                                         * Filters whether the user is allowed to edit meta for specific object types/subtypes.
     344                                         *
     345                                         * Return true to have the mapped meta caps from `edit_{$object_type}` apply.
     346                                         *
     347                                         * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered.
     348                                         * The dynamic portion of the hook name, `$object_subtype` refers to the object subtype being filtered.
     349                                         * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap().
     350                                         *
     351                                         * @since 4.6.0 As `auth_post_{$post_type}_meta_{$meta_key}`.
     352                                         * @since 4.7.0
     353                                         * @deprecated 5.0.0 Use `auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}`
     354                                         *
     355                                         * @param bool     $allowed   Whether the user can add the object meta. Default false.
     356                                         * @param string   $meta_key  The meta key.
     357                                         * @param int      $object_id Object ID.
     358                                         * @param int      $user_id   User ID.
     359                                         * @param string   $cap       Capability name.
     360                                         * @param string[] $caps      Array of the user's capabilities.
     361                                         */
     362                                        $allowed = apply_filters_deprecated( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", array( $allowed, $meta_key, $object_id, $user_id, $cap, $caps ), '5.0.0', "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" );
     363                                }
     364
    375365                                if ( ! $allowed ) {
    376366                                        $caps[] = $cap;
    377367                                }
    378                         } elseif ( $meta_key && is_protected_meta( $meta_key, $object_type ) ) {
    379                                 $caps[] = $cap;
    380368                        }
    381369                        break;
    382370                case 'edit_comment':
  • src/wp-includes/meta.php

     
    4444                return false;
    4545        }
    4646
     47        $meta_subtype = get_object_subtype( $meta_type, $object_id );
     48
    4749        $column = sanitize_key( $meta_type . '_id' );
    4850
    4951        // expected_slashed ($meta_key)
    5052        $meta_key   = wp_unslash( $meta_key );
    5153        $meta_value = wp_unslash( $meta_value );
    52         $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
     54        $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype );
    5355
    5456        /**
    5557         * Filters whether to add metadata of a specific type.
     
    165167                return false;
    166168        }
    167169
     170        $meta_subtype = get_object_subtype( $meta_type, $object_id );
     171
    168172        $column    = sanitize_key( $meta_type . '_id' );
    169173        $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
    170174
     
    173177        $meta_key     = wp_unslash( $meta_key );
    174178        $passed_value = $meta_value;
    175179        $meta_value   = wp_unslash( $meta_value );
    176         $meta_value   = sanitize_meta( $meta_key, $meta_value, $meta_type );
     180        $meta_value   = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype );
    177181
    178182        /**
    179183         * Filters whether to update metadata of a specific type.
     
    666670                        return false;
    667671                }
    668672
     673                $meta_subtype = get_object_subtype( $meta_type, $object_id );
     674
    669675                // Sanitize the meta
    670676                $_meta_value = $meta_value;
    671                 $meta_value  = sanitize_meta( $meta_key, $meta_value, $meta_type );
     677                $meta_value  = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype );
    672678                $meta_value  = maybe_serialize( $meta_value );
    673679
    674680                // Format the data query arguments.
     
    968974 * Sanitize meta value.
    969975 *
    970976 * @since 3.1.3
     977 * @since 5.0.0 The `$object_subtype` parameter was added.
    971978 *
    972979 * @param string $meta_key       Meta key.
    973980 * @param mixed  $meta_value     Meta value to sanitize.
     
    975982 *
    976983 * @return mixed Sanitized $meta_value.
    977984 */
    978 function sanitize_meta( $meta_key, $meta_value, $object_type ) {
     985function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype = '' ) {
     986        if ( ! empty( $object_subtype ) && has_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) {
     987
     988                /**
     989                 * Filters the sanitization of a specific meta key of a specific meta type and subtype.
     990                 *
     991                 * The dynamic portions of the hook name, `$object_type`, `$meta_key`,
     992                 * and `$object_subtype`, refer to the metadata object type (comment, post, term or user),
     993                 * the meta key value, and the object subtype respectively.
     994                 *
     995                 * @since 5.0.0
     996                 *
     997                 * @param mixed  $meta_value     Meta value to sanitize.
     998                 * @param string $meta_key       Meta key.
     999                 * @param string $object_type    Object type.
     1000                 * @param string $object_subtype Object subtype.
     1001                 */
     1002                return apply_filters( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $meta_value, $meta_key, $object_type, $object_subtype );
     1003        }
     1004
    9791005        /**
    9801006         * Filters the sanitization of a specific meta key of a specific meta type.
    9811007         *
     
    9951021/**
    9961022 * Registers a meta key.
    9971023 *
     1024 * It is recommended to register meta keys for a specific combination of object type and object subtype. If passing
     1025 * an object subtype is omitted, the meta key will be registered for the entire object type, however it can be partly
     1026 * overridden in case a more specific meta key of the same name exists for the same object type and a subtype.
     1027 *
     1028 * If an object type does not support any subtypes, such as users or comments, you should commonly call this function
     1029 * without passing a subtype.
     1030 *
    9981031 * @since 3.3.0
    9991032 * @since 4.6.0 {@link https://core.trac.wordpress.org/ticket/35658 Modified
    10001033 *              to support an array of data to attach to registered meta keys}. Previous arguments for
    10011034 *              `$sanitize_callback` and `$auth_callback` have been folded into this array.
     1035 * @since 5.0.0 The `$object_subtype` argument was added to the arguments array.
    10021036 *
    10031037 * @param string $object_type    Type of object this meta is registered to.
    10041038 * @param string $meta_key       Meta key to register.
    10051039 * @param array  $args {
    10061040 *     Data used to describe the meta key when registered.
    1007  *
     1041 *     
     1042 *     @type string $object_subtype    A subtype; e.g. if the object type is "post", the post type. If left empty,
     1043 *                                     the meta key will be registered on the entire object type. Default empty.
    10081044 *     @type string $type              The type of data associated with this meta key.
    10091045 *                                     Valid values are 'string', 'boolean', 'integer', and 'number'.
    10101046 *     @type string $description       A description of the data attached to this meta key.
     
    10271063        }
    10281064
    10291065        $defaults = array(
     1066                'object_subtype'    => '',
    10301067                'type'              => 'string',
    10311068                'description'       => '',
    10321069                'single'            => false,
     
    10671104        $args = apply_filters( 'register_meta_args', $args, $defaults, $object_type, $meta_key );
    10681105        $args = wp_parse_args( $args, $defaults );
    10691106
     1107        $object_subtype = ! empty( $args['object_subtype'] ) ? $args['object_subtype'] : '';
     1108
    10701109        // If `auth_callback` is not provided, fall back to `is_protected_meta()`.
    10711110        if ( empty( $args['auth_callback'] ) ) {
    10721111                if ( is_protected_meta( $meta_key, $object_type ) ) {
     
    10781117
    10791118        // Back-compat: old sanitize and auth callbacks are applied to all of an object type.
    10801119        if ( is_callable( $args['sanitize_callback'] ) ) {
    1081                 add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 3 );
     1120                if ( ! empty( $object_subtype ) ) {
     1121                        add_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'], 10, 4 );
     1122                } else {
     1123                        add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 3 );
     1124                }
    10821125        }
    10831126
    10841127        if ( is_callable( $args['auth_callback'] ) ) {
    1085                 add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 );
     1128                if ( ! empty( $object_subtype ) ) {
     1129                        add_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'], 10, 6 );
     1130                } else {
     1131                        add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 );
     1132                }
    10861133        }
    10871134
    10881135        // Global registry only contains meta keys registered with the array of arguments added in 4.6.0.
    10891136        if ( ! $has_old_auth_cb && ! $has_old_sanitize_cb ) {
    1090                 $wp_meta_keys[ $object_type ][ $meta_key ] = $args;
     1137                unset( $args['object_subtype'] );
    10911138
     1139                $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] = $args;
     1140
    10921141                return true;
    10931142        }
    10941143
     
    10991148 * Checks if a meta key is registered.
    11001149 *
    11011150 * @since 4.6.0
     1151 * @since 5.0.0 The `$object_subtype` parameter was added.
    11021152 *
    11031153 * @param string $object_type    The type of object.
    11041154 * @param string $meta_key       The meta key.
     1155 * @param string $object_subtype Optional. The subtype of the object type.
    11051156 *
    1106  * @return bool True if the meta key is registered to the object type. False if not.
     1157 * @return bool True if the meta key is registered to the object type and, if provided,
     1158 *              the object subtype. False if not.
    11071159 */
    1108 function registered_meta_key_exists( $object_type, $meta_key ) {
    1109         global $wp_meta_keys;
     1160function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = '' ) {
     1161        $meta_keys = get_registered_meta_keys( $object_type, $object_subtype );
    11101162
    1111         if ( ! is_array( $wp_meta_keys ) ) {
    1112                 return false;
    1113         }
    1114 
    1115         if ( ! isset( $wp_meta_keys[ $object_type ] ) ) {
    1116                 return false;
    1117         }
    1118 
    1119         if ( isset( $wp_meta_keys[ $object_type ][ $meta_key ] ) ) {
    1120                 return true;
    1121         }
    1122 
    1123         return false;
     1163        return isset( $meta_keys[ $meta_key ] );
    11241164}
    11251165
    11261166/**
     
    11271167 * Unregisters a meta key from the list of registered keys.
    11281168 *
    11291169 * @since 4.6.0
     1170 * @since 5.0.0 The `$object_subtype` parameter was added.
    11301171 *
    1131  * @param string $object_type The type of object.
    1132  * @param string $meta_key    The meta key.
     1172 * @param string $object_type    The type of object.
     1173 * @param string $meta_key       The meta key.
     1174 * @param string $object_subtype Optional. The subtype of the object type.
    11331175 * @return bool True if successful. False if the meta key was not registered.
    11341176 */
    1135 function unregister_meta_key( $object_type, $meta_key ) {
     1177function unregister_meta_key( $object_type, $meta_key, $object_subtype = '' ) {
    11361178        global $wp_meta_keys;
    11371179
    1138         if ( ! registered_meta_key_exists( $object_type, $meta_key ) ) {
     1180        if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
    11391181                return false;
    11401182        }
    11411183
    1142         $args = $wp_meta_keys[ $object_type ][ $meta_key ];
     1184        $args = $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ];
    11431185
    11441186        if ( isset( $args['sanitize_callback'] ) && is_callable( $args['sanitize_callback'] ) ) {
    1145                 remove_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'] );
     1187                if ( ! empty( $object_subtype ) ) {
     1188                        remove_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'] );
     1189                } else {
     1190                        remove_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'] );
     1191                }
    11461192        }
    11471193
    11481194        if ( isset( $args['auth_callback'] ) && is_callable( $args['auth_callback'] ) ) {
    1149                 remove_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'] );
     1195                if ( ! empty( $object_subtype ) ) {
     1196                        remove_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'] );
     1197                } else {
     1198                        remove_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'] );
     1199                }
    11501200        }
    11511201
    1152         unset( $wp_meta_keys[ $object_type ][ $meta_key ] );
     1202        unset( $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] );
    11531203
    11541204        // Do some clean up
     1205        if ( empty( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) {
     1206                unset( $wp_meta_keys[ $object_type ][ $object_subtype ] );
     1207        }
    11551208        if ( empty( $wp_meta_keys[ $object_type ] ) ) {
    11561209                unset( $wp_meta_keys[ $object_type ] );
    11571210        }
     
    11631216 * Retrieves a list of registered meta keys for an object type.
    11641217 *
    11651218 * @since 4.6.0
     1219 * @since 5.0.0 The `$object_subtype` parameter was added.
    11661220 *
    1167  * @param string $object_type The type of object. Post, comment, user, term.
     1221 * @param string $object_type    The type of object. Post, comment, user, term.
     1222 * @param string $object_subtype Optional. The subtype of the object type.
    11681223 * @return array List of registered meta keys.
    11691224 */
    1170 function get_registered_meta_keys( $object_type ) {
     1225function get_registered_meta_keys( $object_type, $object_subtype = '' ) {
    11711226        global $wp_meta_keys;
    11721227
    1173         if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $object_type ] ) ) {
     1228        if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $object_type ] ) || ! isset( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) {
    11741229                return array();
    11751230        }
    11761231
    1177         return $wp_meta_keys[ $object_type ];
     1232        return $wp_meta_keys[ $object_type ][ $object_subtype ];
    11781233}
    11791234
    11801235/**
    11811236 * Retrieves registered metadata for a specified object.
    11821237 *
     1238 * The results include both meta that is registered specifically for the
     1239 * object's subtype and meta that is registered for the entire object type.
     1240 *
    11831241 * @since 4.6.0
    11841242 *
    11851243 * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user)
     
    11871245 * @param string $meta_key    Optional. Registered metadata key. If not specified, retrieve all registered
    11881246 *                            metadata for the specified object.
    11891247 * @return mixed A single value or array of values for a key if specified. An array of all registered keys
    1190  *               and values for an object ID if not.
     1248 *               and values for an object ID if not. False if a given $meta_key is not registered.
    11911249 */
    11921250function get_registered_metadata( $object_type, $object_id, $meta_key = '' ) {
     1251        $object_subtype = get_object_subtype( $object_type, $object_id );
     1252
    11931253        if ( ! empty( $meta_key ) ) {
    1194                 if ( ! registered_meta_key_exists( $object_type, $meta_key ) ) {
     1254                if ( ! empty( $object_subtype ) && ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
     1255                        $object_subtype = '';
     1256                }
     1257
     1258                if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
    11951259                        return false;
    11961260                }
    1197                 $meta_keys     = get_registered_meta_keys( $object_type );
     1261
     1262                $meta_keys     = get_registered_meta_keys( $object_type, $object_subtype );
    11981263                $meta_key_data = $meta_keys[ $meta_key ];
    11991264
    12001265                $data = get_metadata( $object_type, $object_id, $meta_key, $meta_key_data['single'] );
     
    12031268        }
    12041269
    12051270        $data = get_metadata( $object_type, $object_id );
     1271        if ( ! $data ) {
     1272                return array();
     1273        }
    12061274
    1207         $meta_keys       = get_registered_meta_keys( $object_type );
    1208         $registered_data = array();
    1209 
    1210         // Someday, array_filter()
    1211         foreach ( $meta_keys as $k => $v ) {
    1212                 if ( isset( $data[ $k ] ) ) {
    1213                         $registered_data[ $k ] = $data[ $k ];
    1214                 }
     1275        $meta_keys = get_registered_meta_keys( $object_type );
     1276        if ( ! empty( $object_subtype ) ) {
     1277                $meta_keys = array_merge( $meta_keys, get_registered_meta_keys( $object_type, $object_subtype ) );
    12151278        }
    12161279
    1217         return $registered_data;
     1280        return array_intersect_key( $data, $meta_keys );
    12181281}
    12191282
    12201283/**
     
    12231286 * to be explicitly turned off is a warranty seal of sorts.
    12241287 *
    12251288 * @access private
    1226  * @since  4.6.0
     1289 * @since 4.6.0
    12271290 *
    1228  * @param  array $args         Arguments from `register_meta()`.
    1229  * @param  array $default_args Default arguments for `register_meta()`.
     1291 * @param array $args         Arguments from `register_meta()`.
     1292 * @param array $default_args Default arguments for `register_meta()`.
    12301293 *
    12311294 * @return array Filtered arguments.
    12321295 */
    12331296function _wp_register_meta_args_whitelist( $args, $default_args ) {
    1234         $whitelist = array_keys( $default_args );
     1297        return array_intersect_key( $args, $default_args );
     1298}
    12351299
    1236         // In an anonymous function world, this would be better as an array_filter()
    1237         foreach ( $args as $key => $value ) {
    1238                 if ( ! in_array( $key, $whitelist ) ) {
    1239                         unset( $args[ $key ] );
    1240                 }
     1300/**
     1301 * Returns the object subtype for a given object ID of a specific type.
     1302 *
     1303 * @since 5.0.0
     1304 *
     1305 * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user)
     1306 * @param int    $object_id   ID of the object to retrieve its subtype.
     1307 * @return string The object subtype or an empty string if unspecified subtype.
     1308 */
     1309function get_object_subtype( $object_type, $object_id ) {
     1310        $object_id      = (int) $object_id;
     1311        $object_subtype = '';
     1312
     1313        switch ( $object_type ) {
     1314                case 'post':
     1315                        $post = get_post( $object_id );
     1316                        if ( ! $post ) {
     1317                                break;
     1318                        }
     1319
     1320                        $object_subtype = get_post_type( $post );
     1321                        break;
     1322
     1323                case 'comment':
     1324                        $comment = get_comment( $object_id );
     1325                        if ( ! $comment ) {
     1326                                break;
     1327                        }
     1328
     1329                        $object_subtype = empty( $comment->comment_type ) ? 'comment' : $comment->comment_type;;
     1330                        break;
     1331
     1332                case 'term':
     1333                        $term = get_term( $object_id );
     1334                        if ( ! $term instanceof WP_Term ) {
     1335                                break;
     1336                        }
     1337
     1338                        $object_subtype = $term->taxonomy;
     1339                        break;
     1340
     1341                case 'user':
     1342                        $user = get_user_by( 'id', $object_id );
     1343                        if ( ! $user ) {
     1344                                break;
     1345                        }
     1346
     1347                        $object_subtype = 'user';
     1348                        break;
     1349                default:
     1350
     1351                        /**
     1352                         * Filters the object subtype identifier for a non standard object type.
     1353                         *
     1354                         * The dynamic portion of the hook, `$object_type`, refers to the object
     1355                         * type (post, comment, term, or user).
     1356                         *
     1357                         * @since 5.0.0
     1358                         *
     1359                         * @param string $object_subtype Empty string to override.
     1360                         * @param int    $object_id      ID of the object to get the subtype for.
     1361                         */
     1362                        $object_subtype = apply_filters( "get_object_subtype_{$object_type}", $object_subtype, $object_id );
    12411363        }
    12421364
    1243         return $args;
     1365        return $object_subtype;
    12441366}
  • src/wp-includes/post.php

     
    19901990}
    19911991
    19921992/**
     1993 * Registers a meta key for posts.
     1994 *
     1995 * @since 5.0.0
     1996 *
     1997 * @param string $post_type Post type to register a meta key for. Pass an empty string
     1998 *                          to register the meta key across all existing post types.
     1999 * @param string $meta_key  The meta key to register.
     2000 * @param array  $args      Data used to describe the meta key when registered. See
     2001 *                          {@see register_meta()} for a list of supported arguments.
     2002 * @return bool True if the meta key was successfully registered, false if not.
     2003 */
     2004function register_post_meta( $post_type, $meta_key, array $args ) {
     2005        $args['object_subtype'] = $post_type;
     2006
     2007        return register_meta( 'post', $meta_key, $args );
     2008}
     2009
     2010/**
     2011 * Unregisters a meta key for posts.
     2012 *
     2013 * @since 5.0.0
     2014 *
     2015 * @param string $post_type Post type the meta key is currently registered for. Pass
     2016 *                          an empty string if the meta key is registered across all
     2017 *                          existing post types.
     2018 * @param string $meta_key  The meta key to unregister.
     2019 * @return bool True on success, false if the meta key was not previously registered.
     2020 */
     2021function unregister_post_meta( $post_type, $meta_key ) {
     2022        return unregister_meta_key( 'post', $meta_key, $post_type );
     2023}
     2024
     2025/**
    19932026 * Retrieve post meta fields, based on post ID.
    19942027 *
    19952028 * The post meta fields are retrieved from the cache where possible,
  • src/wp-includes/rest-api/fields/class-wp-rest-comment-meta-fields.php

     
    2828        }
    2929
    3030        /**
     31         * Retrieves the object meta subtype.
     32         *
     33         * @since 5.0.0
     34         *
     35         * @return string 'comment' There are no subtypes.
     36         */
     37        protected function get_meta_subtype() {
     38                return 'comment';
     39        }
     40
     41        /**
    3142         * Retrieves the type for register_rest_field() in the context of comments.
    3243         *
    3344         * @since 4.7.0
  • src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php

     
    2525        abstract protected function get_meta_type();
    2626
    2727        /**
     28         * Retrieves the object meta subtype.
     29         *
     30         * @since 5.0.0
     31         *
     32         * @return string Subtype for the meta type, or empty string if no specific subtype.
     33         */
     34        protected function get_meta_subtype() {
     35                return '';
     36        }
     37
     38        /**
    2839         * Retrieves the object type for register_rest_field().
    2940         *
    3041         * @since 4.7.0
     
    340351        protected function get_registered_fields() {
    341352                $registered = array();
    342353
    343                 foreach ( get_registered_meta_keys( $this->get_meta_type() ) as $name => $args ) {
     354                $meta_type    = $this->get_meta_type();
     355                $meta_subtype = $this->get_meta_subtype();
     356
     357                $meta_keys = get_registered_meta_keys( $meta_type );
     358                if ( ! empty( $meta_subtype ) ) {
     359                        $meta_keys = array_merge( $meta_keys, get_registered_meta_keys( $meta_type, $meta_subtype ) );
     360                }
     361
     362                foreach ( $meta_keys as $name => $args ) {
    344363                        if ( empty( $args['show_in_rest'] ) ) {
    345364                                continue;
    346365                        }
  • src/wp-includes/rest-api/fields/class-wp-rest-post-meta-fields.php

     
    4747        }
    4848
    4949        /**
     50         * Retrieves the object meta subtype.
     51         *
     52         * @since 5.0.0
     53         *
     54         * @return string Subtype for the meta type, or empty string if no specific subtype.
     55         */
     56        protected function get_meta_subtype() {
     57                return $this->post_type;
     58        }
     59
     60        /**
    5061         * Retrieves the type for register_rest_field().
    5162         *
    5263         * @since 4.7.0
  • src/wp-includes/rest-api/fields/class-wp-rest-term-meta-fields.php

     
    4747        }
    4848
    4949        /**
     50         * Retrieves the object meta subtype.
     51         *
     52         * @since 5.0.0
     53         *
     54         * @return string Subtype for the meta type, or empty string if no specific subtype.
     55         */
     56        protected function get_meta_subtype() {
     57                return $this->taxonomy;
     58        }
     59
     60        /**
    5061         * Retrieves the type for register_rest_field().
    5162         *
    5263         * @since 4.7.0
  • src/wp-includes/rest-api/fields/class-wp-rest-user-meta-fields.php

     
    2828        }
    2929
    3030        /**
     31         * Retrieves the object meta subtype.
     32         *
     33         * @since 5.0.0
     34         *
     35         * @return string 'user' There are no subtypes.
     36         */
     37        protected function get_meta_subtype() {
     38                return 'user';
     39        }
     40
     41        /**
    3142         * Retrieves the type for register_rest_field().
    3243         *
    3344         * @since 4.7.0
  • src/wp-includes/taxonomy.php

     
    13231323}
    13241324
    13251325/**
     1326 * Registers a meta key for terms.
     1327 *
     1328 * @since 5.0.0
     1329 *
     1330 * @param string $taxonomy Taxonomy to register a meta key for. Pass an empty string
     1331 *                         to register the meta key across all existing taxonomies.
     1332 * @param string $meta_key The meta key to register.
     1333 * @param array  $args     Data used to describe the meta key when registered. See
     1334 *                         {@see register_meta()} for a list of supported arguments.
     1335 * @return bool True if the meta key was successfully registered, false if not.
     1336 */
     1337function register_term_meta( $taxonomy, $meta_key, array $args ) {
     1338        $args['object_subtype'] = $taxonomy;
     1339
     1340        return register_meta( 'term', $meta_key, $args );
     1341}
     1342
     1343/**
     1344 * Unregisters a meta key for terms.
     1345 *
     1346 * @since 5.0.0
     1347 *
     1348 * @param string $taxonomy Taxonomy the meta key is currently registered for. Pass
     1349 *                         an empty string if the meta key is registered across all
     1350 *                         existing taxonomies.
     1351 * @param string $meta_key The meta key to unregister.
     1352 * @return bool True on success, false if the meta key was not previously registered.
     1353 */
     1354function unregister_term_meta( $taxonomy, $meta_key ) {
     1355        return unregister_meta_key( 'term', $meta_key, $taxonomy );
     1356}
     1357
     1358/**
    13261359 * Determines whether a term exists.
    13271360 *
    13281361 * Formerly is_term(), introduced in 2.3.0.
  • tests/phpunit/tests/meta/registerMeta.php

     
    7474
    7575                $expected = array(
    7676                        'post' => array(
    77                                 'flight_number' => array(
    78                                         'type'              => 'string',
    79                                         'description'       => '',
    80                                         'single'            => false,
    81                                         'sanitize_callback' => null,
    82                                         'auth_callback'     => '__return_true',
    83                                         'show_in_rest'      => false,
     77                                '' => array(
     78                                        'flight_number' => array(
     79                                                'type'              => 'string',
     80                                                'description'       => '',
     81                                                'single'            => false,
     82                                                'sanitize_callback' => null,
     83                                                'auth_callback'     => '__return_true',
     84                                                'show_in_rest'      => false,
     85                                        ),
    8486                                ),
    8587                        ),
    8688                );
     
    8890                $this->assertEquals( $actual, $expected );
    8991        }
    9092
    91         public function test_register_meta_with_term_object_type_populates_wp_meta_keys() {
     93        public function test_register_meta_with_post_subtype_populates_wp_meta_keys() {
    9294                global $wp_meta_keys;
    93                 register_meta( 'term', 'category_icon', array() );
     95                register_meta( 'post', 'flight_number', array( 'object_subtype' => 'journey' ) );
    9496                $actual = $wp_meta_keys;
    95                 unregister_meta_key( 'term', 'category_icon' );
     97                unregister_meta_key( 'post', 'flight_number', 'journey' );
    9698
    9799                $expected = array(
    98                         'term' => array(
    99                                 'category_icon' => array(
    100                                         'type'              => 'string',
    101                                         'description'       => '',
    102                                         'single'            => false,
    103                                         'sanitize_callback' => null,
    104                                         'auth_callback'     => '__return_true',
    105                                         'show_in_rest'      => false,
     100                        'post' => array(
     101                                'journey' => array(
     102                                        'flight_number' => array(
     103                                                'type'              => 'string',
     104                                                'description'       => '',
     105                                                'single'            => false,
     106                                                'sanitize_callback' => null,
     107                                                'auth_callback'     => '__return_true',
     108                                                'show_in_rest'      => false,
     109                                        ),
    106110                                ),
    107111                        ),
    108112                );
     
    110114                $this->assertEquals( $actual, $expected );
    111115        }
    112116
     117        /**
     118         * @depends test_register_meta_with_post_subtype_populates_wp_meta_keys
     119         */
     120        public function test_unregister_meta_with_post_subtype() {
     121                global $wp_meta_keys;
     122                register_meta( 'post', 'flight_number', array( 'object_subtype' => 'journey' ) );
     123                $registered = $wp_meta_keys;
     124                unregister_meta_key( 'post', 'flight_number', 'journey' );
     125                $unregistered = $wp_meta_keys;
     126
     127                $expected_registered = array(
     128                        'post' => array(
     129                                'journey' => array(
     130                                        'flight_number' => array(
     131                                                'type'              => 'string',
     132                                                'description'       => '',
     133                                                'single'            => false,
     134                                                'sanitize_callback' => null,
     135                                                'auth_callback'     => '__return_true',
     136                                                'show_in_rest'      => false,
     137                                        ),
     138                                ),
     139                        ),
     140                );
     141
     142                $this->assertEquals( $registered, $expected_registered );
     143
     144                $this->assertEmpty( $unregistered );
     145        }
     146
     147        /**
     148         * @depends test_register_meta_with_post_subtype_populates_wp_meta_keys
     149         */
     150        public function test_meta_with_post_subtype_unregistering_type_keeps_meta_key() {
     151                global $wp_meta_keys;
     152                register_meta( 'post', 'flight_number', array( 'object_subtype' => 'journey' ) );
     153                $registered = $wp_meta_keys;
     154                unregister_meta_key( 'post', 'flight_number' ); // unregister meta key without subtype
     155                $unregistered = $wp_meta_keys;
     156                unregister_meta_key( 'post', 'flight_number', 'journey' );
     157
     158                $expected = array(
     159                        'post' => array(
     160                                'journey' => array(
     161                                        'flight_number' => array(
     162                                                'type'              => 'string',
     163                                                'description'       => '',
     164                                                'single'            => false,
     165                                                'sanitize_callback' => null,
     166                                                'auth_callback'     => '__return_true',
     167                                                'show_in_rest'      => false,
     168                                        ),
     169                                ),
     170                        ),
     171                );
     172
     173                $this->assertEquals( $registered, $expected );
     174                $this->assertEquals( $unregistered, $expected  );
     175        }
     176
    113177        public function test_register_meta_with_deprecated_sanitize_callback_does_not_populate_wp_meta_keys() {
    114178                global $wp_meta_keys;
    115179
     
    148212
    149213                $expected = array(
    150214                        'post' => array(
    151                                 'flight_number' => array(
    152                                         'type'              => 'string',
    153                                         'description'       => '',
    154                                         'single'            => false,
    155                                         'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ),
    156                                         'auth_callback'     => '__return_true',
    157                                         'show_in_rest'      => false,
     215                                '' => array(
     216                                        'flight_number' => array(
     217                                                'type'              => 'string',
     218                                                'description'       => '',
     219                                                'single'            => false,
     220                                                'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ),
     221                                                'auth_callback'     => '__return_true',
     222                                                'show_in_rest'      => false,
     223                                        ),
    158224                                ),
    159225                        ),
    160226                );
  • tests/phpunit/tests/post/meta.php

     
    2929
    3030                // insert a post
    3131                $this->post_id_2 = wp_insert_post( $post );
     32
     33                $post = array(
     34                        'post_author'  => $this->author->ID,
     35                        'post_status'  => 'publish',
     36                        'post_content' => rand_str(),
     37                        'post_title'   => rand_str(),
     38                        'post_type'        => 'journey'
     39                );
     40
     41                // insert a post with a custom post type of journey
     42                $this->post_journey = wp_insert_post( $post );
     43
     44                // to fix other tests which have not unregistered their meta keys
     45                global $wp_meta_keys;
     46                $wp_meta_keys = array();
    3247        }
    3348
    3449        function test_unique_postmeta() {
     
    235250                $this->assertEquals( $funky_meta, get_post_meta( $this->post_id, 'test_funky_post_meta', true ) );
    236251
    237252        }
     253
     254        public function test_register_post_meta_with_post_object_type_returns_true() {
     255                $result = register_post_meta( 'journey', 'flight_number', array() );
     256                unregister_post_meta( 'journey', 'flight_number' );
     257
     258                $this->assertTrue( $result );
     259        }
     260
     261        public function test_register_post_meta_populates_wp_meta_keys() {
     262                global $wp_meta_keys;
     263
     264                register_post_meta( 'journey', 'flight_number', array() );
     265                $actual = $wp_meta_keys;
     266                unregister_meta_key( 'journey', 'flight_number' );
     267
     268                $expected = array(
     269                        'post' => array(
     270                                'journey' => array(
     271                                        'flight_number' => array(
     272                                                'type'              => 'string',
     273                                                'description'       => '',
     274                                                'single'            => false,
     275                                                'sanitize_callback' => null,
     276                                                'auth_callback'     => '__return_true',
     277                                                'show_in_rest'      => false,
     278                                        ),
     279                                ),
     280                        ),
     281                );
     282
     283                $this->assertEquals( $expected, $actual );
     284        }
     285
     286        /**
     287         * @depends test_register_post_meta_populates_wp_meta_keys
     288         */
     289        public function test_unregister_post_meta() {
     290                global $wp_meta_keys;
     291                register_post_meta( 'journey', 'flight_number', array() );
     292                $registered = $wp_meta_keys;
     293                unregister_post_meta( 'journey', 'flight_number' );
     294                $unregistered = $wp_meta_keys;
     295
     296                $expected_registered = array(
     297                        'post' => array(
     298                                'journey' => array(
     299                                        'flight_number' => array(
     300                                                'type'              => 'string',
     301                                                'description'       => '',
     302                                                'single'            => false,
     303                                                'sanitize_callback' => null,
     304                                                'auth_callback'     => '__return_true',
     305                                                'show_in_rest'      => false,
     306                                        ),
     307                                ),
     308                        ),
     309                );
     310
     311                $this->assertEquals( $expected_registered, $registered );
     312
     313                $this->assertEmpty( $unregistered );
     314        }
     315
     316        public function test_register_post_meta_with_current_sanitize_callback_populates_wp_meta_keys() {
     317                global $wp_meta_keys;
     318                register_post_meta( 'journey', 'flight_number', array( 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) );
     319                $actual = $wp_meta_keys;
     320                unregister_post_meta( 'journey', 'flight_number' );
     321
     322                $expected = array(
     323                        'post' => array(
     324                                'journey' => array(
     325                                        'flight_number' => array(
     326                                                'type'              => 'string',
     327                                                'description'       => '',
     328                                                'single'            => false,
     329                                                'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ),
     330                                                'auth_callback'     => '__return_true',
     331                                                'show_in_rest'      => false,
     332                                        ),
     333                                ),
     334                        ),
     335                );
     336                $this->assertEquals( $expected, $actual );
     337        }
     338
     339        public function test_register_post_meta_with_current_sanitize_callback_returns_true() {
     340                $result = register_post_meta( 'journey', 'flight_number', array( 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) );
     341                unregister_post_meta( 'journey', 'flight_number' );
     342
     343                $this->assertTrue( $result );
     344        }
     345
     346        public function test_register_post_meta_with_new_sanitize_callback_parameter() {
     347                register_post_meta( 'journey', 'new_sanitized_key', array( 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) );
     348                $meta = sanitize_meta( 'new_sanitized_key', 'unsanitized', 'post', 'journey' );
     349
     350                unregister_post_meta( 'journey', 'new_sanitized_key' );
     351
     352                $this->assertEquals( 'new_sanitized_key new sanitized', $meta );
     353        }
     354
     355        public function test_register_post_meta_unregistered_meta_key_removes_sanitize_filter() {
     356                register_post_meta( 'journey', 'new_sanitized_key', array( 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) );
     357                unregister_post_meta( 'journey', 'new_sanitized_key' );
     358
     359                $has_filter = has_filter( 'sanitize_post_meta_new_sanitized_key', array( $this, '_new_sanitize_meta_cb' ) );
     360
     361                $this->assertFalse( $has_filter );
     362        }
     363
     364        public function test_register_post_meta_unregistered_meta_key_removes_auth_filter() {
     365                register_post_meta( 'journey', 'new_auth_key', array( 'auth_callback' => array( $this, '_new_auth_meta_cb' ) ) );
     366                unregister_post_meta( 'journey', 'new_auth_key' );
     367
     368                $has_filter = has_filter( 'auth_post_meta_new_auth_key', array( $this, '_new_auth_meta_cb' ) );
     369
     370                $this->assertFalse( $has_filter );
     371        }
     372
     373        public function test_unregister_post_meta_key_clears_key_from_wp_meta_keys() {
     374                global $wp_meta_keys;
     375                register_post_meta( 'journey', 'registered_key', array() );
     376                unregister_post_meta( 'journey', 'registered_key' );
     377
     378                $this->assertEquals( array(), $wp_meta_keys );
     379        }
     380
     381        public function test_unregister_post_meta_key_with_invalid_key_returns_false() {
     382                $this->assertFalse( unregister_post_meta( 'post', 'not_a_registered_key' ) );
     383        }
     384
     385        public function test_get_registered_meta_keys() {
     386                register_post_meta( 'journey', 'registered_key1', array() );
     387                register_post_meta( 'journey', 'registered_key2', array() );
     388
     389                $meta_keys = get_registered_meta_keys( 'post', 'journey' );
     390
     391                unregister_post_meta( 'journey', 'registered_key1' );
     392                unregister_post_meta( 'journey', 'registered_key2' );
     393
     394                $this->assertArrayHasKey( 'registered_key1', $meta_keys );
     395                $this->assertArrayHasKey( 'registered_key2', $meta_keys );
     396        }
     397
     398        public function test_get_registered_post_meta_keys_with_invalid_type_is_empty() {
     399                register_post_meta( 'journey', 'registered_key1', array() );
     400                register_post_meta( 'journey', 'registered_key2', array() );
     401
     402                $meta_keys = get_registered_meta_keys( 'post', 'invalid-type' );
     403
     404                unregister_post_meta( 'journey', 'registered_key1' );
     405                unregister_post_meta( 'journey', 'registered_key2' );
     406
     407                $this->assertEmpty( $meta_keys );
     408        }
     409
     410        public function test_get_registered_post_meta_keys_description_arg() {
     411                register_post_meta( 'journey', 'registered_key1', array( 'description' => 'I\'m just a field, take a good look at me' ) );
     412
     413                $meta_keys = get_registered_meta_keys( 'post', 'journey' );
     414
     415                unregister_post_meta( 'journey', 'registered_key1' );
     416
     417                $this->assertEquals( 'I\'m just a field, take a good look at me', $meta_keys['registered_key1']['description'] );
     418        }
     419
     420        public function test_get_registered_post_meta_keys_invalid_arg() {
     421                register_post_meta( 'journey', 'registered_key1', array( 'invalid_arg' => 'invalid' ) );
     422
     423                $meta_keys = get_registered_meta_keys( 'post', 'journey' );
     424
     425                unregister_post_meta( 'journey', 'registered_key1' );
     426
     427                $this->assertArrayNotHasKey( 'invalid_arg', $meta_keys['registered_key1'] );
     428        }
     429
     430        public function test_get_registered_metadata() {
     431                register_post_meta( 'journey', 'flight_number', array() );
     432                add_post_meta( $this->post_journey, 'flight_number', 'Oceanic 815' );
     433
     434                $meta = get_registered_metadata( 'post', $this->post_journey );
     435
     436                unregister_post_meta( 'journey', 'flight_number' );
     437
     438                $this->assertEquals( 'Oceanic 815', $meta['flight_number'][0] );
     439        }
     440
     441        public function test_get_registered_metadata_by_key() {
     442                register_post_meta( 'journey', 'flight_number', array() );
     443                add_post_meta( $this->post_journey, 'flight_number', 'Oceanic 815' );
     444
     445                $meta = get_registered_metadata( 'post', $this->post_journey, 'flight_number' );
     446
     447                unregister_post_meta( 'journey', 'flight_number' );
     448
     449                $this->assertEquals( 'Oceanic 815', $meta[0] );
     450        }
     451
     452        public function test_get_registered_metadata_by_key_single() {
     453                register_post_meta( 'journey', 'flight_number', array( 'single' => true ) );
     454                add_post_meta( $this->post_journey, 'flight_number', 'Oceanic 815' );
     455
     456                $meta = get_registered_metadata( 'post', $this->post_journey, 'flight_number' );
     457
     458                unregister_post_meta( 'journey', 'flight_number' );
     459
     460                $this->assertEquals( 'Oceanic 815', $meta );
     461        }
     462
     463        public function test_get_registered_metadata_by_invalid_key() {
     464                register_post_meta( 'journey', 'flight_number', array() );
     465                add_post_meta( $this->post_journey, 'flight_number', 'Oceanic 815' );
     466
     467                $meta = get_registered_metadata( 'journey', $this->post_journey, 'flight_pilot' );
     468
     469                unregister_post_meta( 'journey', 'flight_number' );
     470
     471                $this->assertFalse( $meta );
     472        }
     473
     474        public function _new_sanitize_meta_cb( $meta_value, $meta_key, $object_type ) {
     475                return $meta_key . ' new sanitized';
     476        }
     477
     478        public function _new_auth_meta_cb( $allowed, $meta_key, $post_id, $user_id, $cap, $caps ) {
     479                return $allowed;
     480        }
     481
    238482}
  • tests/phpunit/tests/rest-api/rest-post-meta-fields.php

     
    1212class WP_Test_REST_Post_Meta_Fields extends WP_Test_REST_TestCase {
    1313        protected static $wp_meta_keys_saved;
    1414        protected static $post_id;
     15        protected static $custom_post_type_id;
    1516
    1617        public static function wpSetUpBeforeClass( $factory ) {
    1718                self::$wp_meta_keys_saved = $GLOBALS['wp_meta_keys'];
    1819                self::$post_id            = $factory->post->create();
     20
     21                self::$custom_post_type_id = $factory->post->create( array( 'post_type' => 'cpt' ) );
    1922        }
    2023
    2124        public static function wpTearDownAfterClass() {
    2225                $GLOBALS['wp_meta_keys'] = self::$wp_meta_keys_saved;
    2326                wp_delete_post( self::$post_id, true );
     27                wp_delete_post( self::$custom_post_type_id, true );
    2428        }
    2529
    2630        public function setUp() {
     
    120124                        )
    121125                );
    122126
     127                $args = array(
     128                        'show_in_rest' => true,
     129                        'supports' => array( 'custom-fields' ),
     130                );
     131                register_post_type( 'cpt', $args );
     132
     133                register_post_meta( 'cpt', 'test_cpt_single', array(
     134                        'show_in_rest' => true,
     135                        'single' => true,
     136                        'object_subtype' => 'cpt',
     137                ) );
     138
     139                register_post_meta( 'cpt', 'test_cpt_bad_auth', array(
     140                        'show_in_rest' => true,
     141                        'single' => true,
     142                        'auth_callback' => '__return_false',
     143                        'object_subtype' => 'cpt',
     144                ) );
     145
     146                // registering the key 'test_single' on the cpt post type
     147                register_post_meta( 'cpt', 'test_single', array(
     148                        'show_in_rest' => true,
     149                        'single' => true,
     150                        'auth_callback' => '__return_false',
     151                        'object_subtype' => 'cpt',
     152                ) );
     153
    123154                /** @var WP_REST_Server $wp_rest_server */
    124155                global $wp_rest_server;
    125156                $wp_rest_server = new Spy_REST_Server;
     
    10471078                $this->assertArrayNotHasKey( 'test_no_type', $meta_schema );
    10481079        }
    10491080
     1081        public function test_register_custom_post_meta_get_value () {
     1082                add_post_meta( self::$custom_post_type_id, 'test_cpt_single', 'testcptvalue' );
     1083
     1084                $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/cpt/%d', self::$custom_post_type_id ) );
     1085                $response = rest_get_server()->dispatch( $request );
     1086
     1087                $this->assertEquals( 200, $response->get_status() );
     1088
     1089                $data = $response->get_data();
     1090                $this->assertArrayHasKey( 'meta', $data );
     1091
     1092                $meta = (array) $data['meta'];
     1093                $this->assertArrayHasKey( 'test_cpt_single', $meta );
     1094                $this->assertEquals( 'testcptvalue', $meta['test_cpt_single'] );
     1095        }
     1096
     1097        public function test_register_custom_post_meta_not_in_post () {
     1098                add_post_meta( self::$post_id, 'test_cpt_single', 'testcptvalue' );
     1099
     1100                $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
     1101                $response = rest_get_server()->dispatch( $request );
     1102
     1103                $this->assertEquals( 200, $response->get_status() );
     1104
     1105                $data = $response->get_data();
     1106                $this->assertArrayHasKey( 'meta', $data );
     1107
     1108                $meta = (array) $data['meta'];
     1109                $this->assertArrayNotHasKey( 'test_cpt_single', $meta );
     1110        }
     1111
     1112        public function test_set_value_unregistered_custom_post_type_registered_object() {
     1113                // Ensure no data exists currently.
     1114                $values = get_post_meta( self::$custom_post_type_id, 'test_multi', false );
     1115                $this->assertEmpty( $values );
     1116
     1117                $this->grant_write_permission();
     1118
     1119                $data    = array(
     1120                        'meta' => array(
     1121                                'test_multi' => 'test_value',
     1122                        ),
     1123                );
     1124                $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/cpt/%d', self::$custom_post_type_id ) );
     1125                $request->set_body_params( $data );
     1126
     1127                $response = rest_get_server()->dispatch( $request );
     1128                $this->assertEquals( 200, $response->get_status() );
     1129
     1130                $meta = get_post_meta( self::$custom_post_type_id, 'test_multi', false );
     1131                $this->assertNotEmpty( $meta );
     1132                $this->assertCount( 1, $meta );
     1133                $this->assertEquals( 'test_value', $meta[0] );
     1134
     1135                $data = $response->get_data();
     1136                $meta = (array) $data['meta'];
     1137                $this->assertArrayHasKey( 'test_multi', $meta );
     1138                $this->assertEquals( 'test_value', $meta['test_multi'][0] );
     1139        }
     1140
     1141        public function test_set_value_custom_post_type() {
     1142                // Ensure no data exists currently.
     1143                $values = get_post_meta( self::$custom_post_type_id, 'test_cpt_single', false );
     1144                $this->assertEmpty( $values );
     1145
     1146                $this->grant_write_permission();
     1147
     1148                $data    = array(
     1149                        'meta' => array(
     1150                                'test_cpt_single' => 'test_value',
     1151                        ),
     1152                );
     1153                $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/cpt/%d', self::$custom_post_type_id ) );
     1154                $request->set_body_params( $data );
     1155
     1156                $response = rest_get_server()->dispatch( $request );
     1157                $this->assertEquals( 200, $response->get_status() );
     1158
     1159                $meta = get_post_meta( self::$custom_post_type_id, 'test_cpt_single', false );
     1160                $this->assertNotEmpty( $meta );
     1161                $this->assertCount( 1, $meta );
     1162                $this->assertEquals( 'test_value', $meta[0] );
     1163
     1164                $data = $response->get_data();
     1165                $meta = (array) $data['meta'];
     1166                $this->assertArrayHasKey( 'test_cpt_single', $meta );
     1167                $this->assertEquals( 'test_value', $meta['test_cpt_single'] );
     1168        }
     1169
    10501170        /**
     1171         * @depends test_set_value_custom_post_type
     1172         */
     1173        public function test_set_value_custom_post_type_blocked() {
     1174                $data = array(
     1175                        'meta' => array(
     1176                                'test_cpt_bad_auth' => 'test_value',
     1177                        ),
     1178                );
     1179
     1180                $this->grant_write_permission();
     1181
     1182                $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/cpt/%d', self::$custom_post_type_id ) );
     1183                $request->set_body_params( $data );
     1184
     1185                $response = rest_get_server()->dispatch( $request );
     1186                $this->assertErrorResponse( 'rest_cannot_update', $response, 403 );
     1187                $this->assertEmpty( get_post_meta( self::$custom_post_type_id, 'test_cpt_bad_auth', false ) );
     1188        }
     1189
     1190        /**
     1191         * @depends test_set_value_custom_post_type_blocked
     1192         */
     1193        public function test_set_value_custom_post_type_duplicate_key_blocked() {
     1194                $data = array(
     1195                        'meta' => array(
     1196                                'test_single' => 'test_value',
     1197                        ),
     1198                );
     1199
     1200                $this->grant_write_permission();
     1201
     1202                $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
     1203                $request->set_body_params( $data );
     1204
     1205                $response = rest_get_server()->dispatch( $request );
     1206                $this->assertEquals( get_post_meta( self::$post_id, 'test_single', true ), 'test_value' );
     1207
     1208                $request_cpt = new WP_REST_Request( 'POST', sprintf( '/wp/v2/cpt/%d', self::$custom_post_type_id ) );
     1209                $request_cpt->set_body_params( $data );
     1210
     1211                $response_cpt = rest_get_server()->dispatch( $request_cpt );
     1212
     1213                $this->assertErrorResponse( 'rest_cannot_update', $response_cpt, 403 );
     1214                $this->assertEmpty( get_post_meta( self::$custom_post_type_id, 'test_single', true ) );
     1215        }
     1216
     1217        /**
    10511218         * Internal function used to disable an insert query which
    10521219         * will trigger a wpdb error for testing purposes.
    10531220         */
  • tests/phpunit/tests/term/meta.php

     
    99        public function setUp() {
    1010                parent::setUp();
    1111                register_taxonomy( 'wptests_tax', 'post' );
     12                $this->term = self::factory()->term->create( array( 'taxonomy' => 'wptests_tax' ) );
     13
     14                // to fix other tests which have not unregistered their meta keys
     15                global $wp_meta_keys;
     16                $wp_meta_keys = array();
    1217        }
    1318
    1419        public function test_add() {
     
    463468        public static function set_cache_results( $q ) {
    464469                $q->set( 'cache_results', true );
    465470        }
     471
     472        public function test_register_term_meta_with_post_object_type_returns_true() {
     473                $result = register_term_meta( 'wptests_tax', 'flight_number', array() );
     474                unregister_term_meta( 'wptests_tax', 'flight_number' );
     475
     476                $this->assertTrue( $result );
     477        }
     478
     479        public function test_register_term_meta_populates_wp_meta_keys() {
     480                global $wp_meta_keys;
     481
     482                register_term_meta( 'wptests_tax', 'flight_number', array() );
     483                $actual = $wp_meta_keys;
     484                unregister_meta_key( 'wptests_tax', 'flight_number' );
     485
     486                $expected = array(
     487                        'term' => array(
     488                                'wptests_tax' => array(
     489                                        'flight_number' => array(
     490                                                'type'              => 'string',
     491                                                'description'       => '',
     492                                                'single'            => false,
     493                                                'sanitize_callback' => null,
     494                                                'auth_callback'     => '__return_true',
     495                                                'show_in_rest'      => false,
     496                                        ),
     497                                ),
     498                        ),
     499                );
     500
     501                $this->assertEquals( $expected, $actual );
     502        }
     503
     504        /**
     505         * @depends test_register_term_meta_populates_wp_meta_keys
     506         */
     507        public function test_unregister_term_meta() {
     508                global $wp_meta_keys;
     509                register_term_meta( 'wptests_tax', 'flight_number', array() );
     510                $registered = $wp_meta_keys;
     511                unregister_term_meta( 'wptests_tax', 'flight_number' );
     512                $unregistered = $wp_meta_keys;
     513
     514                $expected_registered = array(
     515                        'term' => array(
     516                                'wptests_tax' => array(
     517                                        'flight_number' => array(
     518                                                'type'              => 'string',
     519                                                'description'       => '',
     520                                                'single'            => false,
     521                                                'sanitize_callback' => null,
     522                                                'auth_callback'     => '__return_true',
     523                                                'show_in_rest'      => false,
     524                                        ),
     525                                ),
     526                        ),
     527                );
     528
     529                $this->assertEquals( $expected_registered, $registered );
     530
     531                $this->assertEmpty( $unregistered );
     532        }
     533
     534        public function test_register_term_meta_with_current_sanitize_callback_populates_wp_meta_keys() {
     535                global $wp_meta_keys;
     536                register_term_meta( 'wptests_tax', 'flight_number', array( 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) );
     537                $actual = $wp_meta_keys;
     538                unregister_term_meta( 'wptests_tax', 'flight_number' );
     539
     540                $expected = array(
     541                        'term' => array(
     542                                'wptests_tax' => array(
     543                                        'flight_number' => array(
     544                                                'type'              => 'string',
     545                                                'description'       => '',
     546                                                'single'            => false,
     547                                                'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ),
     548                                                'auth_callback'     => '__return_true',
     549                                                'show_in_rest'      => false,
     550                                        ),
     551                                ),
     552                        ),
     553                );
     554                $this->assertEquals( $expected, $actual );
     555        }
     556
     557        public function test_register_term_meta_with_current_sanitize_callback_returns_true() {
     558                $result = register_term_meta( 'wptests_tax', 'flight_number', array( 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) );
     559                unregister_term_meta( 'wptests_tax', 'flight_number' );
     560
     561                $this->assertTrue( $result );
     562        }
     563
     564        public function test_register_term_meta_with_new_sanitize_callback_parameter() {
     565                register_term_meta( 'wptests_tax', 'new_sanitized_key', array( 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) );
     566                $meta = sanitize_meta( 'new_sanitized_key', 'unsanitized', 'term', 'wptests_tax' );
     567
     568                unregister_term_meta( 'wptests_tax', 'new_sanitized_key' );
     569
     570                $this->assertEquals( 'new_sanitized_key new sanitized', $meta );
     571        }
     572
     573        public function test_register_term_meta_unregistered_meta_key_removes_sanitize_filter() {
     574                register_term_meta( 'wptests_tax', 'new_sanitized_key', array( 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) );
     575                unregister_term_meta( 'wptests_tax', 'new_sanitized_key' );
     576
     577                $has_filter = has_filter( 'sanitize_term_meta_new_sanitized_key', array( $this, '_new_sanitize_meta_cb' ) );
     578
     579                $this->assertFalse( $has_filter );
     580        }
     581
     582        public function test_register_term_meta_unregistered_meta_key_removes_auth_filter() {
     583                register_term_meta( 'wptests_tax', 'new_auth_key', array( 'auth_callback' => array( $this, '_new_auth_meta_cb' ) ) );
     584                unregister_term_meta( 'wptests_tax', 'new_auth_key' );
     585
     586                $has_filter = has_filter( 'auth_term_meta_new_auth_key', array( $this, '_new_auth_meta_cb' ) );
     587
     588                $this->assertFalse( $has_filter );
     589        }
     590
     591        public function test_unregister_term_meta_key_clears_key_from_wp_meta_keys() {
     592                global $wp_meta_keys;
     593                register_term_meta( 'wptests_tax', 'registered_key', array() );
     594                unregister_term_meta( 'wptests_tax', 'registered_key' );
     595
     596                $this->assertEquals( array(), $wp_meta_keys );
     597        }
     598
     599        public function test_unregister_term_meta_key_with_invalid_key_returns_false() {
     600                $this->assertFalse( unregister_term_meta( 'term', 'not_a_registered_key' ) );
     601        }
     602
     603        public function test_get_registered_meta_keys() {
     604                register_term_meta( 'wptests_tax', 'registered_key1', array() );
     605                register_term_meta( 'wptests_tax', 'registered_key2', array() );
     606
     607                $meta_keys = get_registered_meta_keys( 'term', 'wptests_tax' );
     608
     609                unregister_term_meta( 'wptests_tax', 'registered_key1' );
     610                unregister_term_meta( 'wptests_tax', 'registered_key2' );
     611
     612                $this->assertArrayHasKey( 'registered_key1', $meta_keys );
     613                $this->assertArrayHasKey( 'registered_key2', $meta_keys );
     614        }
     615
     616        public function test_get_registered_term_meta_keys_with_invalid_type_is_empty() {
     617                register_term_meta( 'wptests_tax', 'registered_key1', array() );
     618                register_term_meta( 'wptests_tax', 'registered_key2', array() );
     619
     620                $meta_keys = get_registered_meta_keys( 'term', 'invalid-type' );
     621
     622                unregister_term_meta( 'wptests_tax', 'registered_key1' );
     623                unregister_term_meta( 'wptests_tax', 'registered_key2' );
     624
     625                $this->assertEmpty( $meta_keys );
     626        }
     627
     628        public function test_get_registered_term_meta_keys_description_arg() {
     629                register_term_meta( 'wptests_tax', 'registered_key1', array( 'description' => 'I\'m just a field, take a good look at me' ) );
     630
     631                $meta_keys = get_registered_meta_keys( 'term', 'wptests_tax' );
     632
     633                unregister_term_meta( 'wptests_tax', 'registered_key1' );
     634
     635                $this->assertEquals( 'I\'m just a field, take a good look at me', $meta_keys['registered_key1']['description'] );
     636        }
     637
     638        public function test_get_registered_term_meta_keys_invalid_arg() {
     639                register_term_meta( 'wptests_tax', 'registered_key1', array( 'invalid_arg' => 'invalid' ) );
     640
     641                $meta_keys = get_registered_meta_keys( 'term', 'wptests_tax' );
     642
     643                unregister_term_meta( 'wptests_tax', 'registered_key1' );
     644
     645                $this->assertArrayNotHasKey( 'invalid_arg', $meta_keys['registered_key1'] );
     646        }
     647
     648        public function test_get_registered_metadata() {
     649                register_term_meta( 'wptests_tax', 'flight_number', array() );
     650                add_term_meta( $this->term, 'flight_number', 'Oceanic 815' );
     651
     652                $meta = get_registered_metadata( 'term', $this->term );
     653
     654                unregister_term_meta( 'wptests_tax', 'flight_number' );
     655
     656                $this->assertEquals( 'Oceanic 815', $meta['flight_number'][0] );
     657        }
     658
     659        public function test_get_registered_metadata_by_key() {
     660                register_term_meta( 'wptests_tax', 'flight_number', array() );
     661                add_term_meta( $this->term, 'flight_number', 'Oceanic 815' );
     662
     663                $meta = get_registered_metadata( 'term', $this->term, 'flight_number' );
     664
     665                unregister_term_meta( 'wptests_tax', 'flight_number' );
     666
     667                $this->assertEquals( 'Oceanic 815', $meta[0] );
     668        }
     669
     670        public function test_get_registered_metadata_by_key_single() {
     671                register_term_meta( 'wptests_tax', 'flight_number', array( 'single' => true ) );
     672                add_term_meta( $this->term, 'flight_number', 'Oceanic 815' );
     673
     674                $meta = get_registered_metadata( 'term', $this->term, 'flight_number' );
     675
     676                unregister_term_meta( 'wptests_tax', 'flight_number' );
     677
     678                $this->assertEquals( 'Oceanic 815', $meta );
     679        }
     680
     681        public function test_get_registered_metadata_by_invalid_key() {
     682                register_term_meta( 'wptests_tax', 'flight_number', array() );
     683                add_term_meta( $this->term, 'flight_number', 'Oceanic 815' );
     684
     685                $meta = get_registered_metadata( 'wptests_tax', $this->term, 'flight_pilot' );
     686
     687                unregister_term_meta( 'wptests_tax', 'flight_number' );
     688
     689                $this->assertFalse( $meta );
     690        }
     691
     692        public function _new_sanitize_meta_cb( $meta_value, $meta_key, $object_type ) {
     693                return $meta_key . ' new sanitized';
     694        }
     695
     696        public function _new_auth_meta_cb( $allowed, $meta_key, $term_id, $user_id, $cap, $caps ) {
     697                return $allowed;
     698        }
    466699}