WordPress.org

Make WordPress Core

Changeset 43510


Ignore:
Timestamp:
07/19/2018 06:48:52 PM (13 months ago)
Author:
kadamwhite
Message:

REST API: Support meta registration for specific object subtypes.

Introduce an object_subtype argument to the args array for register_meta() which can be used to limit meta registration to a single subtype (e.g. a custom post type or taxonomy, vs all posts or taxonomies).

Introduce register_post_meta() and register_term_meta() wrapper methods for register_meta to provide a convenient interface for the common case of registering meta for a specific taxonomy or post type. These methods work the way plugin developers have often expected register_meta to function, and should be used in place of direct register_meta where possible.

Props flixos90, tharsheblows, spacedmonkey.

Merges [43378] to the 4.9 branch.
Fixes #38323.

Location:
branches/4.9
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • branches/4.9/src/wp-includes/capabilities.php

    r43287 r43510  
    277277        list( $_, $object_type, $_ ) = explode( '_', $cap );
    278278        $object_id = (int) $args[0];
    279 
    280         switch ( $object_type ) {
    281             case 'post':
    282                 $post = get_post( $object_id );
    283                 if ( ! $post ) {
    284                     break;
    285                 }
    286 
    287                 $sub_type = get_post_type( $post );
    288                 break;
    289 
    290             case 'comment':
    291                 $comment = get_comment( $object_id );
    292                 if ( ! $comment ) {
    293                     break;
    294                 }
    295 
    296                 $sub_type = empty( $comment->comment_type ) ? 'comment' : $comment->comment_type;
    297                 break;
    298 
    299             case 'term':
    300                 $term = get_term( $object_id );
    301                 if ( ! $term instanceof WP_Term ) {
    302                     break;
    303                 }
    304 
    305                 $sub_type = $term->taxonomy;
    306                 break;
    307 
    308             case 'user':
    309                 $user = get_user_by( 'id', $object_id );
    310                 if ( ! $user ) {
    311                     break;
    312                 }
    313 
    314                 $sub_type = 'user';
    315                 break;
    316         }
    317 
    318         if ( empty( $sub_type ) ) {
     279        $object_subtype = get_object_subtype( $object_type, $object_id );
     280
     281        if ( empty( $object_subtype ) ) {
    319282            $caps[] = 'do_not_allow';
    320283            break;
     
    325288        $meta_key = isset( $args[1] ) ? $args[1] : false;
    326289
    327         $has_filter = has_filter( "auth_{$object_type}_meta_{$meta_key}" ) || has_filter( "auth_{$object_type}_{$sub_type}_meta_{$meta_key}" );
    328         if ( $meta_key && $has_filter ) {
    329 
    330             /**
    331              * Filters whether the user is allowed to edit meta.
    332              *
    333              * Use the {@see auth_post_$object_type_meta_$meta_key} filter to modify capabilities for
    334              * specific object types. Return true to have the mapped meta caps from edit_{$object_type} apply.
    335              *
    336              * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered.
    337              * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap().
    338              *
    339              * @since 3.3.0 As 'auth_post_meta_{$meta_key}'.
    340              * @since 4.6.0
    341              *
    342              * @param bool   $allowed  Whether the user can add the post meta. Default false.
    343              * @param string $meta_key The meta key.
    344              * @param int    $post_id  Post ID.
    345              * @param int    $user_id  User ID.
    346              * @param string $cap      Capability name.
    347              * @param array  $caps     User capabilities.
    348              */
    349             $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}", false, $meta_key, $object_id, $user_id, $cap, $caps );
    350 
    351             /**
    352              * Filters whether the user is allowed to add post meta to a post of a given type.
    353              *
    354              * Use the {@see auth_$object_type_$sub_type_meta_$meta_key} filter to modify capabilities for
    355              * specific object types/subtypes. Return true to have the mapped meta caps from edit_{$object_type} apply.
    356              *
    357              * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered.
    358              * The dynamic portion of the hook name, `$sub_type` refers to the object subtype being filtered.
    359              * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap().
    360              *
    361              * @since 4.6.0 As 'auth_post_{$post_type}_meta_{$meta_key}'.
    362              * @since 4.7.0
    363              *
    364              * @param bool   $allowed  Whether the user can add the post meta. Default false.
    365              * @param string $meta_key The meta key.
    366              * @param int    $post_id  Post ID.
    367              * @param int    $user_id  User ID.
    368              * @param string $cap      Capability name.
    369              * @param array  $caps     User capabilities.
    370              */
    371             $allowed = apply_filters( "auth_{$object_type}_{$sub_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps );
     290        if ( $meta_key ) {
     291            $allowed = ! is_protected_meta( $meta_key, $object_type );
     292
     293            if ( ! empty( $object_subtype ) && has_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) {
     294
     295                /**
     296                 * Filters whether the user is allowed to edit a specific meta key of a specific object type and subtype.
     297                 *
     298                 * The dynamic portions of the hook name, `$object_type`, `$meta_key`,
     299                 * and `$object_subtype`, refer to the metadata object type (comment, post, term or user),
     300                 * the meta key value, and the object subtype respectively.
     301                 *
     302                 * @since 4.9.8
     303                 *
     304                 * @param bool     $allowed   Whether the user can add the object meta. Default false.
     305                 * @param string   $meta_key  The meta key.
     306                 * @param int      $object_id Object ID.
     307                 * @param int      $user_id   User ID.
     308                 * @param string   $cap       Capability name.
     309                 * @param string[] $caps      Array of the user's capabilities.
     310                 */
     311                $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps );
     312            } else {
     313
     314                /**
     315                 * Filters whether the user is allowed to edit a specific meta key of a specific object type.
     316                 *
     317                 * Return true to have the mapped meta caps from `edit_{$object_type}` apply.
     318                 *
     319                 * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered.
     320                 * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap().
     321                 *
     322                 * @since 3.3.0 As `auth_post_meta_{$meta_key}`.
     323                 * @since 4.6.0
     324                 *
     325                 * @param bool     $allowed   Whether the user can add the object meta. Default false.
     326                 * @param string   $meta_key  The meta key.
     327                 * @param int      $object_id Object ID.
     328                 * @param int      $user_id   User ID.
     329                 * @param string   $cap       Capability name.
     330                 * @param string[] $caps      Array of the user's capabilities.
     331                 */
     332                $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps );
     333            }
     334
     335            if ( ! empty( $object_subtype ) ) {
     336
     337                /**
     338                 * Filters whether the user is allowed to edit meta for specific object types/subtypes.
     339                 *
     340                 * Return true to have the mapped meta caps from `edit_{$object_type}` apply.
     341                 *
     342                 * The dynamic portion of the hook name, `$object_type` refers to the object type being filtered.
     343                 * The dynamic portion of the hook name, `$object_subtype` refers to the object subtype being filtered.
     344                 * The dynamic portion of the hook name, `$meta_key`, refers to the meta key passed to map_meta_cap().
     345                 *
     346                 * @since 4.6.0 As `auth_post_{$post_type}_meta_{$meta_key}`.
     347                 * @since 4.7.0
     348                 * @deprecated 4.9.8 Use `auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}`
     349                 *
     350                 * @param bool     $allowed   Whether the user can add the object meta. Default false.
     351                 * @param string   $meta_key  The meta key.
     352                 * @param int      $object_id Object ID.
     353                 * @param int      $user_id   User ID.
     354                 * @param string   $cap       Capability name.
     355                 * @param string[] $caps      Array of the user's capabilities.
     356                 */
     357                $allowed = apply_filters_deprecated( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", array( $allowed, $meta_key, $object_id, $user_id, $cap, $caps ), '4.9.8', "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" );
     358            }
    372359
    373360            if ( ! $allowed ) {
    374361                $caps[] = $cap;
    375362            }
    376         } elseif ( $meta_key && is_protected_meta( $meta_key, $object_type ) ) {
    377             $caps[] = $cap;
    378363        }
    379364        break;
  • branches/4.9/src/wp-includes/meta.php

    r42056 r43510  
    4545    }
    4646
     47    $meta_subtype = get_object_subtype( $meta_type, $object_id );
     48
    4749    $column = sanitize_key($meta_type . '_id');
    4850
     
    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    /**
     
    158160    }
    159161
     162    $meta_subtype = get_object_subtype( $meta_type, $object_id );
     163
    160164    $column = sanitize_key($meta_type . '_id');
    161165    $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
     
    166170    $passed_value = $meta_value;
    167171    $meta_value = wp_unslash($meta_value);
    168     $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
     172    $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype );
    169173
    170174    /**
     
    641645        }
    642646
     647        $meta_subtype = get_object_subtype( $meta_type, $object_id );
     648
    643649        // Sanitize the meta
    644650        $_meta_value = $meta_value;
    645         $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
    646         $meta_value = maybe_serialize( $meta_value );
     651        $meta_value  = sanitize_meta( $meta_key, $meta_value, $meta_type, $meta_subtype );
     652        $meta_value  = maybe_serialize( $meta_value );
    647653
    648654        // Format the data query arguments.
     
    936942 *
    937943 * @since 3.1.3
     944 * @since 4.9.8 The `$object_subtype` parameter was added.
    938945 *
    939946 * @param string $meta_key       Meta key.
     
    943950 * @return mixed Sanitized $meta_value.
    944951 */
    945 function sanitize_meta( $meta_key, $meta_value, $object_type ) {
     952function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype = '' ) {
     953    if ( ! empty( $object_subtype ) && has_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) {
     954
     955        /**
     956         * Filters the sanitization of a specific meta key of a specific meta type and subtype.
     957         *
     958         * The dynamic portions of the hook name, `$object_type`, `$meta_key`,
     959         * and `$object_subtype`, refer to the metadata object type (comment, post, term or user),
     960         * the meta key value, and the object subtype respectively.
     961         *
     962         * @since 4.9.8
     963         *
     964         * @param mixed  $meta_value     Meta value to sanitize.
     965         * @param string $meta_key       Meta key.
     966         * @param string $object_type    Object type.
     967         * @param string $object_subtype Object subtype.
     968         */
     969        return apply_filters( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $meta_value, $meta_key, $object_type, $object_subtype );
     970    }
     971
    946972    /**
    947973     * Filters the sanitization of a specific meta key of a specific meta type.
     
    963989 * Registers a meta key.
    964990 *
     991 * It is recommended to register meta keys for a specific combination of object type and object subtype. If passing
     992 * an object subtype is omitted, the meta key will be registered for the entire object type, however it can be partly
     993 * overridden in case a more specific meta key of the same name exists for the same object type and a subtype.
     994 *
     995 * If an object type does not support any subtypes, such as users or comments, you should commonly call this function
     996 * without passing a subtype.
     997 *
    965998 * @since 3.3.0
    966999 * @since 4.6.0 {@link https://core.trac.wordpress.org/ticket/35658 Modified
    9671000 *              to support an array of data to attach to registered meta keys}. Previous arguments for
    9681001 *              `$sanitize_callback` and `$auth_callback` have been folded into this array.
     1002 * @since 4.9.8 The `$object_subtype` argument was added to the arguments array.
    9691003 *
    9701004 * @param string $object_type    Type of object this meta is registered to.
     
    9731007 *     Data used to describe the meta key when registered.
    9741008 *
     1009 *     @type string $object_subtype    A subtype; e.g. if the object type is "post", the post type. If left empty,
     1010 *                                     the meta key will be registered on the entire object type. Default empty.
    9751011 *     @type string $type              The type of data associated with this meta key.
    9761012 *                                     Valid values are 'string', 'boolean', 'integer', and 'number'.
     
    9951031
    9961032    $defaults = array(
     1033        'object_subtype'    => '',
    9971034        'type'              => 'string',
    9981035        'description'       => '',
     
    10351072    $args = wp_parse_args( $args, $defaults );
    10361073
     1074    $object_subtype = ! empty( $args['object_subtype'] ) ? $args['object_subtype'] : '';
     1075
    10371076    // If `auth_callback` is not provided, fall back to `is_protected_meta()`.
    10381077    if ( empty( $args['auth_callback'] ) ) {
     
    10461085    // Back-compat: old sanitize and auth callbacks are applied to all of an object type.
    10471086    if ( is_callable( $args['sanitize_callback'] ) ) {
    1048         add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 3 );
     1087        if ( ! empty( $object_subtype ) ) {
     1088            add_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'], 10, 4 );
     1089        } else {
     1090            add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 3 );
     1091        }
    10491092    }
    10501093
    10511094    if ( is_callable( $args['auth_callback'] ) ) {
    1052         add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 );
     1095        if ( ! empty( $object_subtype ) ) {
     1096            add_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'], 10, 6 );
     1097        } else {
     1098            add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 );
     1099        }
    10531100    }
    10541101
    10551102    // Global registry only contains meta keys registered with the array of arguments added in 4.6.0.
    10561103    if ( ! $has_old_auth_cb && ! $has_old_sanitize_cb ) {
    1057         $wp_meta_keys[ $object_type ][ $meta_key ] = $args;
     1104        unset( $args['object_subtype'] );
     1105
     1106        $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] = $args;
    10581107
    10591108        return true;
     
    10671116 *
    10681117 * @since 4.6.0
     1118 * @since 4.9.8 The `$object_subtype` parameter was added.
    10691119 *
    10701120 * @param string $object_type    The type of object.
    10711121 * @param string $meta_key       The meta key.
    1072  *
    1073  * @return bool True if the meta key is registered to the object type. False if not.
    1074  */
    1075 function registered_meta_key_exists( $object_type, $meta_key ) {
     1122 * @param string $object_subtype Optional. The subtype of the object type.
     1123 *
     1124 * @return bool True if the meta key is registered to the object type and, if provided,
     1125 *              the object subtype. False if not.
     1126 */
     1127function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = '' ) {
     1128    $meta_keys = get_registered_meta_keys( $object_type, $object_subtype );
     1129
     1130    return isset( $meta_keys[ $meta_key ] );
     1131}
     1132
     1133/**
     1134 * Unregisters a meta key from the list of registered keys.
     1135 *
     1136 * @since 4.6.0
     1137 * @since 4.9.8 The `$object_subtype` parameter was added.
     1138 *
     1139 * @param string $object_type    The type of object.
     1140 * @param string $meta_key       The meta key.
     1141 * @param string $object_subtype Optional. The subtype of the object type.
     1142 * @return bool True if successful. False if the meta key was not registered.
     1143 */
     1144function unregister_meta_key( $object_type, $meta_key, $object_subtype = '' ) {
    10761145    global $wp_meta_keys;
    10771146
    1078     if ( ! is_array( $wp_meta_keys ) ) {
    1079         return false;
    1080     }
    1081 
    1082     if ( ! isset( $wp_meta_keys[ $object_type ] ) ) {
    1083         return false;
    1084     }
    1085 
    1086     if ( isset( $wp_meta_keys[ $object_type ][ $meta_key ] ) ) {
    1087         return true;
    1088     }
    1089 
    1090     return false;
    1091 }
    1092 
    1093 /**
    1094  * Unregisters a meta key from the list of registered keys.
    1095  *
    1096  * @since 4.6.0
    1097  *
    1098  * @param string $object_type The type of object.
    1099  * @param string $meta_key    The meta key.
    1100  * @return bool True if successful. False if the meta key was not registered.
    1101  */
    1102 function unregister_meta_key( $object_type, $meta_key ) {
    1103     global $wp_meta_keys;
    1104 
    1105     if ( ! registered_meta_key_exists( $object_type, $meta_key ) ) {
    1106         return false;
    1107     }
    1108 
    1109     $args = $wp_meta_keys[ $object_type ][ $meta_key ];
     1147    if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
     1148        return false;
     1149    }
     1150
     1151    $args = $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ];
    11101152
    11111153    if ( isset( $args['sanitize_callback'] ) && is_callable( $args['sanitize_callback'] ) ) {
    1112         remove_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'] );
     1154        if ( ! empty( $object_subtype ) ) {
     1155            remove_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'] );
     1156        } else {
     1157            remove_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'] );
     1158        }
    11131159    }
    11141160
    11151161    if ( isset( $args['auth_callback'] ) && is_callable( $args['auth_callback'] ) ) {
    1116         remove_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'] );
    1117     }
    1118 
    1119     unset( $wp_meta_keys[ $object_type ][ $meta_key ] );
     1162        if ( ! empty( $object_subtype ) ) {
     1163            remove_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'] );
     1164        } else {
     1165            remove_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'] );
     1166        }
     1167    }
     1168
     1169    unset( $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] );
    11201170
    11211171    // Do some clean up
     1172    if ( empty( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) {
     1173        unset( $wp_meta_keys[ $object_type ][ $object_subtype ] );
     1174    }
    11221175    if ( empty( $wp_meta_keys[ $object_type ] ) ) {
    11231176        unset( $wp_meta_keys[ $object_type ] );
     
    11311184 *
    11321185 * @since 4.6.0
    1133  *
    1134  * @param string $object_type The type of object. Post, comment, user, term.
     1186 * @since 4.9.8 The `$object_subtype` parameter was added.
     1187 *
     1188 * @param string $object_type    The type of object. Post, comment, user, term.
     1189 * @param string $object_subtype Optional. The subtype of the object type.
    11351190 * @return array List of registered meta keys.
    11361191 */
    1137 function get_registered_meta_keys( $object_type ) {
     1192function get_registered_meta_keys( $object_type, $object_subtype = '' ) {
    11381193    global $wp_meta_keys;
    11391194
    1140     if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $object_type ] ) ) {
     1195    if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $object_type ] ) || ! isset( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) {
    11411196        return array();
    11421197    }
    11431198
    1144     return $wp_meta_keys[ $object_type ];
     1199    return $wp_meta_keys[ $object_type ][ $object_subtype ];
    11451200}
    11461201
    11471202/**
    11481203 * Retrieves registered metadata for a specified object.
     1204 *
     1205 * The results include both meta that is registered specifically for the
     1206 * object's subtype and meta that is registered for the entire object type.
    11491207 *
    11501208 * @since 4.6.0
     
    11551213 *                            metadata for the specified object.
    11561214 * @return mixed A single value or array of values for a key if specified. An array of all registered keys
    1157  *               and values for an object ID if not.
     1215 *               and values for an object ID if not. False if a given $meta_key is not registered.
    11581216 */
    11591217function get_registered_metadata( $object_type, $object_id, $meta_key = '' ) {
     1218    $object_subtype = get_object_subtype( $object_type, $object_id );
     1219
    11601220    if ( ! empty( $meta_key ) ) {
    1161         if ( ! registered_meta_key_exists( $object_type, $meta_key ) ) {
     1221        if ( ! empty( $object_subtype ) && ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
     1222            $object_subtype = '';
     1223        }
     1224
     1225        if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) {
    11621226            return false;
    11631227        }
    1164         $meta_keys = get_registered_meta_keys( $object_type );
     1228
     1229        $meta_keys     = get_registered_meta_keys( $object_type, $object_subtype );
    11651230        $meta_key_data = $meta_keys[ $meta_key ];
    11661231
     
    11711236
    11721237    $data = get_metadata( $object_type, $object_id );
     1238    if ( ! $data ) {
     1239        return array();
     1240    }
    11731241
    11741242    $meta_keys = get_registered_meta_keys( $object_type );
    1175     $registered_data = array();
    1176 
    1177     // Someday, array_filter()
    1178     foreach ( $meta_keys as $k => $v ) {
    1179         if ( isset( $data[ $k ] ) ) {
    1180             $registered_data[ $k ] = $data[ $k ];
    1181         }
    1182     }
    1183 
    1184     return $registered_data;
     1243    if ( ! empty( $object_subtype ) ) {
     1244        $meta_keys = array_merge( $meta_keys, get_registered_meta_keys( $object_type, $object_subtype ) );
     1245    }
     1246
     1247    return array_intersect_key( $data, $meta_keys );
    11851248}
    11861249
     
    11911254 *
    11921255 * @access private
    1193  * @since  4.6.0
    1194  *
    1195  * @param  array $args         Arguments from `register_meta()`.
    1196  * @param  array $default_args Default arguments for `register_meta()`.
     1256 * @since 4.6.0
     1257 *
     1258 * @param array $args         Arguments from `register_meta()`.
     1259 * @param array $default_args Default arguments for `register_meta()`.
    11971260 *
    11981261 * @return array Filtered arguments.
    11991262 */
    12001263function _wp_register_meta_args_whitelist( $args, $default_args ) {
    1201     $whitelist = array_keys( $default_args );
    1202 
    1203     // In an anonymous function world, this would be better as an array_filter()
    1204     foreach ( $args as $key => $value ) {
    1205         if ( ! in_array( $key, $whitelist ) ) {
    1206             unset( $args[ $key ] );
    1207         }
    1208     }
    1209 
    1210     return $args;
    1211 }
     1264    return array_intersect_key( $args, $default_args );
     1265}
     1266
     1267/**
     1268 * Returns the object subtype for a given object ID of a specific type.
     1269 *
     1270 * @since 4.9.8
     1271 *
     1272 * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user)
     1273 * @param int    $object_id   ID of the object to retrieve its subtype.
     1274 * @return string The object subtype or an empty string if unspecified subtype.
     1275 */
     1276function get_object_subtype( $object_type, $object_id ) {
     1277    $object_id      = (int) $object_id;
     1278    $object_subtype = '';
     1279
     1280    switch ( $object_type ) {
     1281        case 'post':
     1282            $post_type = get_post_type( $object_id );
     1283
     1284            if ( ! empty( $post_type ) ) {
     1285                $object_subtype = $post_type;
     1286            }
     1287            break;
     1288
     1289        case 'term':
     1290            $term = get_term( $object_id );
     1291            if ( ! $term instanceof WP_Term ) {
     1292                break;
     1293            }
     1294
     1295            $object_subtype = $term->taxonomy;
     1296            break;
     1297
     1298        case 'comment':
     1299            $comment = get_comment( $object_id );
     1300            if ( ! $comment ) {
     1301                break;
     1302            }
     1303
     1304            $object_subtype = 'comment';
     1305            break;
     1306
     1307        case 'user':
     1308            $user = get_user_by( 'id', $object_id );
     1309            if ( ! $user ) {
     1310                break;
     1311            }
     1312
     1313            $object_subtype = 'user';
     1314            break;
     1315    }
     1316
     1317    /**
     1318     * Filters the object subtype identifier for a non standard object type.
     1319     *
     1320     * The dynamic portion of the hook, `$object_type`, refers to the object
     1321     * type (post, comment, term, or user).
     1322     *
     1323     * @since 4.9.8
     1324     *
     1325     * @param string $object_subtype Empty string to override.
     1326     * @param int    $object_id      ID of the object to get the subtype for.
     1327     */
     1328    return apply_filters( "get_object_subtype_{$object_type}", $object_subtype, $object_id );
     1329}
  • branches/4.9/src/wp-includes/post.php

    r43393 r43510  
    18851885
    18861886/**
     1887 * Registers a meta key for posts.
     1888 *
     1889 * @since 4.9.8
     1890 *
     1891 * @param string $post_type Post type to register a meta key for. Pass an empty string
     1892 *                          to register the meta key across all existing post types.
     1893 * @param string $meta_key  The meta key to register.
     1894 * @param array  $args      Data used to describe the meta key when registered. See
     1895 *                          {@see register_meta()} for a list of supported arguments.
     1896 * @return bool True if the meta key was successfully registered, false if not.
     1897 */
     1898function register_post_meta( $post_type, $meta_key, array $args ) {
     1899    $args['object_subtype'] = $post_type;
     1900
     1901    return register_meta( 'post', $meta_key, $args );
     1902}
     1903
     1904/**
     1905 * Unregisters a meta key for posts.
     1906 *
     1907 * @since 4.9.8
     1908 *
     1909 * @param string $post_type Post type the meta key is currently registered for. Pass
     1910 *                          an empty string if the meta key is registered across all
     1911 *                          existing post types.
     1912 * @param string $meta_key  The meta key to unregister.
     1913 * @return bool True on success, false if the meta key was not previously registered.
     1914 */
     1915function unregister_post_meta( $post_type, $meta_key ) {
     1916    return unregister_meta_key( 'post', $meta_key, $post_type );
     1917}
     1918
     1919/**
    18871920 * Retrieve post meta fields, based on post ID.
    18881921 *
  • branches/4.9/src/wp-includes/rest-api/fields/class-wp-rest-comment-meta-fields.php

    r41162 r43510  
    2929
    3030    /**
     31     * Retrieves the object meta subtype.
     32     *
     33     * @since 4.9.8
     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     *
  • branches/4.9/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php

    r41162 r43510  
    2424     */
    2525    abstract protected function get_meta_type();
     26
     27    /**
     28     * Retrieves the object meta subtype.
     29     *
     30     * @since 4.9.8
     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    }
    2637
    2738    /**
     
    318329        $registered = array();
    319330
    320         foreach ( get_registered_meta_keys( $this->get_meta_type() ) as $name => $args ) {
     331        $meta_type    = $this->get_meta_type();
     332        $meta_subtype = $this->get_meta_subtype();
     333
     334        $meta_keys = get_registered_meta_keys( $meta_type );
     335        if ( ! empty( $meta_subtype ) ) {
     336            $meta_keys = array_merge( $meta_keys, get_registered_meta_keys( $meta_type, $meta_subtype ) );
     337        }
     338
     339        foreach ( $meta_keys as $name => $args ) {
    321340            if ( empty( $args['show_in_rest'] ) ) {
    322341                continue;
  • branches/4.9/src/wp-includes/rest-api/fields/class-wp-rest-post-meta-fields.php

    r41162 r43510  
    4848
    4949    /**
     50     * Retrieves the object meta subtype.
     51     *
     52     * @since 4.9.8
     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     *
  • branches/4.9/src/wp-includes/rest-api/fields/class-wp-rest-term-meta-fields.php

    r41162 r43510  
    4848
    4949    /**
     50     * Retrieves the object meta subtype.
     51     *
     52     * @since 4.9.8
     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     *
  • branches/4.9/src/wp-includes/rest-api/fields/class-wp-rest-user-meta-fields.php

    r41162 r43510  
    2929
    3030    /**
     31     * Retrieves the object meta subtype.
     32     *
     33     * @since 4.9.8
     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     *
  • branches/4.9/src/wp-includes/taxonomy.php

    r41987 r43510  
    12791279
    12801280/**
     1281 * Registers a meta key for terms.
     1282 *
     1283 * @since 4.9.8
     1284 *
     1285 * @param string $taxonomy Taxonomy to register a meta key for. Pass an empty string
     1286 *                         to register the meta key across all existing taxonomies.
     1287 * @param string $meta_key The meta key to register.
     1288 * @param array  $args     Data used to describe the meta key when registered. See
     1289 *                         {@see register_meta()} for a list of supported arguments.
     1290 * @return bool True if the meta key was successfully registered, false if not.
     1291 */
     1292function register_term_meta( $taxonomy, $meta_key, array $args ) {
     1293    $args['object_subtype'] = $taxonomy;
     1294
     1295    return register_meta( 'term', $meta_key, $args );
     1296}
     1297
     1298/**
     1299 * Unregisters a meta key for terms.
     1300 *
     1301 * @since 4.9.8
     1302 *
     1303 * @param string $taxonomy Taxonomy the meta key is currently registered for. Pass
     1304 *                         an empty string if the meta key is registered across all
     1305 *                         existing taxonomies.
     1306 * @param string $meta_key The meta key to unregister.
     1307 * @return bool True on success, false if the meta key was not previously registered.
     1308 */
     1309function unregister_term_meta( $taxonomy, $meta_key ) {
     1310    return unregister_meta_key( 'term', $meta_key, $taxonomy );
     1311}
     1312
     1313/**
    12811314 * Check if Term exists.
    12821315 *
  • branches/4.9/tests/phpunit/tests/meta/registerMeta.php

    r38398 r43510  
    44 */
    55class Tests_Meta_Register_Meta extends WP_UnitTestCase {
     6
    67    protected static $post_id;
     8    protected static $term_id;
     9    protected static $comment_id;
     10    protected static $user_id;
    711
    812    public static function wpSetUpBeforeClass( $factory ) {
    9         self::$post_id = $factory->post->create();
     13        self::$post_id    = $factory->post->create( array( 'post_type' => 'page' ) );
     14        self::$term_id    = $factory->term->create( array( 'taxonomy' => 'category' ) );
     15        self::$comment_id = $factory->comment->create();
     16        self::$user_id    = $factory->user->create();
     17    }
     18
     19    public static function wpTearDownAfterClass() {
     20        wp_delete_post( self::$post_id, true );
     21        wp_delete_term( self::$term_id, 'category' );
     22        wp_delete_comment( self::$comment_id, true );
     23        self::delete_user( self::$user_id );
    1024    }
    1125
     
    7084        $expected = array(
    7185            'post' => array(
    72                 'flight_number' => array(
    73                     'type' => 'string',
    74                     'description' => '',
    75                     'single' => false,
    76                     'sanitize_callback' => null,
    77                     'auth_callback' => '__return_true',
    78                     'show_in_rest' => false,
     86                '' => array(
     87                    'flight_number' => array(
     88                        'type'              => 'string',
     89                        'description'       => '',
     90                        'single'            => false,
     91                        'sanitize_callback' => null,
     92                        'auth_callback'     => '__return_true',
     93                        'show_in_rest'      => false,
     94                    ),
    7995                ),
    8096            ),
    8197        );
    8298
    83         $this->assertEquals( $actual, $expected );
     99        $this->assertEquals( $expected, $actual );
    84100    }
    85101
     
    92108        $expected = array(
    93109            'term' => array(
    94                 'category_icon' => array(
    95                     'type' => 'string',
    96                     'description' => '',
    97                     'single' => false,
    98                     'sanitize_callback' => null,
    99                     'auth_callback' => '__return_true',
    100                     'show_in_rest' => false,
     110                '' => array(
     111                    'category_icon' => array(
     112                        'type'              => 'string',
     113                        'description'       => '',
     114                        'single'            => false,
     115                        'sanitize_callback' => null,
     116                        'auth_callback'     => '__return_true',
     117                        'show_in_rest'      => false,
     118                    ),
    101119                ),
    102120            ),
    103121        );
    104122
    105         $this->assertEquals( $actual, $expected );
     123        $this->assertEquals( $expected, $actual );
    106124    }
    107125
     
    144162        $expected = array(
    145163            'post' => array(
    146                 'flight_number' => array(
    147                     'type' => 'string',
    148                     'description' => '',
    149                     'single' => false,
    150                     'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ),
    151                     'auth_callback' => '__return_true',
    152                     'show_in_rest' => false,
     164                '' => array(
     165                    'flight_number' => array(
     166                        'type'              => 'string',
     167                        'description'       => '',
     168                        'single'            => false,
     169                        'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ),
     170                        'auth_callback'     => '__return_true',
     171                        'show_in_rest'      => false,
     172                    ),
    153173                ),
    154174            ),
     
    297317        $this->assertEmpty( $meta );
    298318    }
     319
     320    /**
     321     * @ticket 38323
     322     * @dataProvider data_get_types_and_subtypes
     323     */
     324    public function test_register_meta_with_subtype_populates_wp_meta_keys( $type, $subtype ) {
     325        global $wp_meta_keys;
     326
     327        register_meta( $type, 'flight_number', array( 'object_subtype' => $subtype ) );
     328
     329        $expected = array(
     330            $type => array(
     331                $subtype => array(
     332                    'flight_number' => array(
     333                        'type'              => 'string',
     334                        'description'       => '',
     335                        'single'            => false,
     336                        'sanitize_callback' => null,
     337                        'auth_callback'     => '__return_true',
     338                        'show_in_rest'      => false,
     339                    ),
     340                ),
     341            ),
     342        );
     343
     344        $actual = $wp_meta_keys;
     345
     346        // Reset global so subsequent data tests do not get polluted.
     347        $wp_meta_keys = array();
     348
     349        $this->assertEquals( $expected, $actual );
     350    }
     351
     352    /**
     353     * @ticket 38323
     354     * @dataProvider data_get_types_and_subtypes
     355     */
     356    public function test_unregister_meta_with_subtype_unpopulates_wp_meta_keys( $type, $subtype ) {
     357        global $wp_meta_keys;
     358
     359        register_meta( $type, 'flight_number', array( 'object_subtype' => $subtype ) );
     360        unregister_meta_key( $type, 'flight_number', $subtype );
     361
     362        $actual = $wp_meta_keys;
     363
     364        // Reset global so subsequent data tests do not get polluted.
     365        $wp_meta_keys = array();
     366
     367        $this->assertEmpty( $actual );
     368    }
     369
     370    /**
     371     * @ticket 38323
     372     * @dataProvider data_get_types_and_subtypes
     373     */
     374    public function test_unregister_meta_without_subtype_keeps_subtype_meta_key( $type, $subtype ) {
     375        global $wp_meta_keys;
     376
     377        register_meta( $type, 'flight_number', array( 'object_subtype' => $subtype ) );
     378
     379        // Unregister meta key without subtype.
     380        unregister_meta_key( $type, 'flight_number' );
     381
     382        $expected = array(
     383            $type => array(
     384                $subtype => array(
     385                    'flight_number' => array(
     386                        'type'              => 'string',
     387                        'description'       => '',
     388                        'single'            => false,
     389                        'sanitize_callback' => null,
     390                        'auth_callback'     => '__return_true',
     391                        'show_in_rest'      => false,
     392                    ),
     393                ),
     394            ),
     395        );
     396
     397        $actual = $wp_meta_keys;
     398
     399        // Reset global so subsequent data tests do not get polluted.
     400        $wp_meta_keys = array();
     401
     402        $this->assertEquals( $expected, $actual );
     403    }
     404
     405    /**
     406     * @ticket 38323
     407     * @dataProvider data_get_types_and_subtypes
     408     */
     409    public function test_get_registered_meta_keys_with_subtype( $type, $subtype ) {
     410        register_meta( $type, 'registered_key1', array( 'object_subtype' => $subtype ) );
     411        register_meta( $type, 'registered_key2', array( 'object_subtype' => $subtype ) );
     412
     413        $meta_keys = get_registered_meta_keys( $type, $subtype );
     414
     415        $this->assertArrayHasKey( 'registered_key1', $meta_keys );
     416        $this->assertArrayHasKey( 'registered_key2', $meta_keys );
     417        $this->assertEmpty( get_registered_meta_keys( $type ) );
     418    }
     419
     420    /**
     421     * @ticket 38323
     422     * @dataProvider data_get_types_and_subtypes
     423     */
     424    public function test_get_registered_metadata_with_subtype( $type, $subtype ) {
     425        register_meta( $type, 'registered_key1', array() );
     426
     427        // This will override the above registration for objects of $subtype.
     428        register_meta( $type, 'registered_key1', array(
     429            'object_subtype' => $subtype,
     430            'single'         => true,
     431        ) );
     432
     433        // For testing with $single => false.
     434        register_meta( $type, 'registered_key2', array(
     435            'object_subtype' => $subtype,
     436        ) );
     437
     438        // Register another meta key for a different subtype.
     439        register_meta( $type, 'registered_key3', array(
     440            'object_subtype' => 'other_subtype',
     441        ) );
     442
     443        $object_property_name = $type . '_id';
     444        $object_id = self::$$object_property_name;
     445
     446        add_metadata( $type, $object_id, 'registered_key1', 'value1' );
     447        add_metadata( $type, $object_id, 'registered_key2', 'value2' );
     448        add_metadata( $type, $object_id, 'registered_key3', 'value3' );
     449
     450        $meta = get_registered_metadata( $type, $object_id );
     451
     452        $key1 = get_registered_metadata( $type, $object_id, 'registered_key1' );
     453        $key2 = get_registered_metadata( $type, $object_id, 'registered_key2' );
     454        $key3 = get_registered_metadata( $type, $object_id, 'registered_key3' );
     455
     456        $this->assertSame( array( 'registered_key1', 'registered_key2' ), array_keys( $meta ) );
     457        $this->assertSame( 'value1', $meta['registered_key1'][0] );
     458        $this->assertSame( 'value2', $meta['registered_key2'][0] );
     459
     460        $this->assertSame( 'value1', $key1 );
     461        $this->assertSame( array( 'value2' ), $key2 );
     462        $this->assertFalse( $key3 );
     463    }
     464
     465    /**
     466     * @ticket 38323
     467     * @dataProvider data_get_types_and_subtypes
     468     */
     469    public function test_get_object_subtype( $type, $expected_subtype ) {
     470        $object_property_name = $type . '_id';
     471        $object_id = self::$$object_property_name;
     472
     473        $this->assertSame( $expected_subtype, get_object_subtype( $type, $object_id ) );
     474    }
     475
     476    /**
     477     * @ticket 38323
     478     */
     479    public function test_get_object_subtype_custom() {
     480        add_filter( 'get_object_subtype_customtype', array( $this, 'filter_get_object_subtype_for_customtype' ), 10, 2 );
     481
     482        $subtype_for_3 = get_object_subtype( 'customtype', 3 );
     483        $subtype_for_4 = get_object_subtype( 'customtype', 4 );
     484
     485        $this->assertSame( 'odd', $subtype_for_3 );
     486        $this->assertSame( 'even', $subtype_for_4 );
     487    }
     488
     489    public function filter_get_object_subtype_for_customtype( $subtype, $object_id ) {
     490        if ( $object_id % 2 === 1 ) {
     491            return 'odd';
     492        }
     493
     494        return 'even';
     495    }
     496
     497    public function data_get_types_and_subtypes() {
     498        return array(
     499            array( 'post', 'page' ),
     500            array( 'term', 'category' ),
     501            array( 'comment', 'comment' ),
     502            array( 'user', 'user' ),
     503        );
     504    }
    299505}
  • branches/4.9/tests/phpunit/tests/post/meta.php

    r35244 r43510  
    66 */
    77class Tests_Post_Meta extends WP_UnitTestCase {
     8
     9    private $last_register_meta_call = array(
     10        'object_type' => '',
     11        'meta_key'    => '',
     12        'args'        => array(),
     13    );
     14
    815    function setUp() {
    916        parent::setUp();
     
    238245
    239246    }
     247
     248    /**
     249     * @ticket 38323
     250     * @dataProvider data_register_post_meta
     251     */
     252    public function test_register_post_meta( $post_type, $meta_key, $args ) {
     253        add_filter( 'register_meta_args', array( $this, 'filter_register_meta_args_set_last_register_meta_call' ), 10, 4 );
     254
     255        register_post_meta( $post_type, $meta_key, $args );
     256
     257        $args['object_subtype'] = $post_type;
     258
     259        // Reset global so subsequent data tests do not get polluted.
     260        $GLOBALS['wp_meta_keys'] = array();
     261
     262        $this->assertEquals( 'post', $this->last_register_meta_call['object_type'] );
     263        $this->assertEquals( $meta_key, $this->last_register_meta_call['meta_key'] );
     264        $this->assertEquals( $args, $this->last_register_meta_call['args'] );
     265    }
     266
     267    public function data_register_post_meta() {
     268        return array(
     269            array( 'post', 'registered_key1', array( 'single' => true ) ),
     270            array( 'page', 'registered_key2', array() ),
     271            array( '', 'registered_key3', array( 'sanitize_callback' => 'absint' ) ),
     272        );
     273    }
     274
     275    public function filter_register_meta_args_set_last_register_meta_call( $args, $defaults, $object_type, $meta_key ) {
     276        $this->last_register_meta_call['object_type'] = $object_type;
     277        $this->last_register_meta_call['meta_key']    = $meta_key;
     278        $this->last_register_meta_call['args']        = $args;
     279
     280        return $args;
     281    }
     282
     283    /**
     284     * @ticket 38323
     285     * @dataProvider data_unregister_post_meta
     286     */
     287    public function test_unregister_post_meta( $post_type, $meta_key ) {
     288        global $wp_meta_keys;
     289
     290        register_post_meta( $post_type, $meta_key, array() );
     291        unregister_post_meta( $post_type, $meta_key );
     292
     293        $actual = $wp_meta_keys;
     294
     295        // Reset global so subsequent data tests do not get polluted.
     296        $wp_meta_keys = array();
     297
     298        $this->assertEmpty( $actual );
     299    }
     300
     301    public function data_unregister_post_meta() {
     302        return array(
     303            array( 'post', 'registered_key1' ),
     304            array( 'page', 'registered_key2' ),
     305            array( '', 'registered_key3' ),
     306        );
     307    }
    240308}
  • branches/4.9/tests/phpunit/tests/rest-api/rest-post-meta-fields.php

    r41176 r43510  
    1313    protected static $wp_meta_keys_saved;
    1414    protected static $post_id;
     15    protected static $cpt_post_id;
    1516
    1617    public static function wpSetUpBeforeClass( $factory ) {
     18        register_post_type( 'cpt', array(
     19            'show_in_rest' => true,
     20            'supports'     => array( 'custom-fields' ),
     21        ) );
     22
    1723        self::$wp_meta_keys_saved = $GLOBALS['wp_meta_keys'];
    1824        self::$post_id = $factory->post->create();
     25        self::$cpt_post_id        = $factory->post->create( array( 'post_type' => 'cpt' ) );
    1926    }
    2027
     
    2229        $GLOBALS['wp_meta_keys'] = self::$wp_meta_keys_saved;
    2330        wp_delete_post( self::$post_id, true );
     31        wp_delete_post( self::$cpt_post_id, true );
     32
     33        unregister_post_type( 'cpt' );
    2434    }
    2535
     
    99109        ));
    100110
     111        register_post_type( 'cpt', array(
     112            'show_in_rest' => true,
     113            'supports'     => array( 'custom-fields' ),
     114        ) );
     115
     116        register_post_meta( 'cpt', 'test_cpt_single', array(
     117            'show_in_rest'   => true,
     118            'single'         => true,
     119        ) );
     120
     121        register_post_meta( 'cpt', 'test_cpt_multi', array(
     122            'show_in_rest'   => true,
     123            'single'         => false,
     124        ) );
     125
     126        // Register 'test_single' on subtype to override for bad auth.
     127        register_post_meta( 'cpt', 'test_single', array(
     128            'show_in_rest'   => true,
     129            'single'         => true,
     130            'auth_callback'  => '__return_false',
     131        ) );
     132
    101133        /** @var WP_REST_Server $wp_rest_server */
    102134        global $wp_rest_server;
     
    10111043
    10121044    /**
     1045     * @ticket 38323
     1046     * @dataProvider data_get_subtype_meta_value
     1047     */
     1048    public function test_get_subtype_meta_value( $post_type, $meta_key, $single, $in_post_type ) {
     1049        $post_id  = self::$post_id;
     1050        $endpoint = 'posts';
     1051        if ( 'cpt' === $post_type ) {
     1052            $post_id  = self::$cpt_post_id;
     1053            $endpoint = 'cpt';
     1054        }
     1055
     1056        $meta_value = 'testvalue';
     1057
     1058        add_post_meta( $post_id, $meta_key, $meta_value );
     1059
     1060        $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/%s/%d', $endpoint, $post_id ) );
     1061        $response = rest_get_server()->dispatch( $request );
     1062
     1063        $this->assertEquals( 200, $response->get_status() );
     1064
     1065        $data = $response->get_data();
     1066
     1067        $this->assertArrayHasKey( 'meta', $data );
     1068        $this->assertInternalType( 'array', $data['meta'] );
     1069
     1070        if ( $in_post_type ) {
     1071            $expected_value = $meta_value;
     1072            if ( ! $single ) {
     1073                $expected_value = array( $expected_value );
     1074            }
     1075
     1076            $this->assertArrayHasKey( $meta_key, $data['meta'] );
     1077            $this->assertEquals( $expected_value, $data['meta'][ $meta_key ] );
     1078        } else {
     1079            $this->assertArrayNotHasKey( $meta_key, $data['meta'] );
     1080        }
     1081    }
     1082
     1083    public function data_get_subtype_meta_value() {
     1084        return array(
     1085            array( 'cpt', 'test_cpt_single', true, true ),
     1086            array( 'cpt', 'test_cpt_multi', false, true ),
     1087            array( 'cpt', 'test_single', true, true ),
     1088            array( 'cpt', 'test_multi', false, true ),
     1089            array( 'post', 'test_cpt_single', true, false ),
     1090            array( 'post', 'test_cpt_multi', false, false ),
     1091            array( 'post', 'test_single', true, true ),
     1092            array( 'post', 'test_multi', false, true ),
     1093        );
     1094    }
     1095
     1096    /**
     1097     * @ticket 38323
     1098     * @dataProvider data_set_subtype_meta_value
     1099     */
     1100    public function test_set_subtype_meta_value( $post_type, $meta_key, $single, $in_post_type, $can_write ) {
     1101        $post_id  = self::$post_id;
     1102        $endpoint = 'posts';
     1103        if ( 'cpt' === $post_type ) {
     1104            $post_id  = self::$cpt_post_id;
     1105            $endpoint = 'cpt';
     1106        }
     1107
     1108        $meta_value = 'value_to_set';
     1109
     1110        $this->grant_write_permission();
     1111
     1112        $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/%s/%d', $endpoint, $post_id ) );
     1113        $request->set_body_params( array(
     1114            'meta' => array(
     1115                $meta_key => $meta_value,
     1116            ),
     1117        ) );
     1118
     1119        $response = rest_get_server()->dispatch( $request );
     1120        if ( ! $can_write ) {
     1121            $this->assertEquals( 403, $response->get_status() );
     1122            $this->assertEmpty( get_post_meta( $post_id, $meta_key, $single ) );
     1123            return;
     1124        }
     1125
     1126        $this->assertEquals( 200, $response->get_status() );
     1127
     1128        $data = $response->get_data();
     1129        $this->assertArrayHasKey( 'meta', $data );
     1130        $this->assertInternalType( 'array', $data['meta'] );
     1131
     1132        if ( $in_post_type ) {
     1133            $expected_value = $meta_value;
     1134            if ( ! $single ) {
     1135                $expected_value = array( $expected_value );
     1136            }
     1137
     1138            $this->assertEquals( $expected_value, get_post_meta( $post_id, $meta_key, $single ) );
     1139            $this->assertArrayHasKey( $meta_key, $data['meta'] );
     1140            $this->assertEquals( $expected_value, $data['meta'][ $meta_key ] );
     1141        } else {
     1142            $this->assertEmpty( get_post_meta( $post_id, $meta_key, $single ) );
     1143            $this->assertArrayNotHasKey( $meta_key, $data['meta'] );
     1144        }
     1145    }
     1146
     1147    public function data_set_subtype_meta_value() {
     1148        $data = $this->data_get_subtype_meta_value();
     1149
     1150        foreach ( $data as $index => $dataset ) {
     1151            $can_write = true;
     1152
     1153            // This combination is not writable because of an auth callback of '__return_false'.
     1154            if ( 'cpt' === $dataset[0] && 'test_single' === $dataset[1] ) {
     1155                $can_write = false;
     1156            }
     1157
     1158            $data[ $index ][] = $can_write;
     1159        }
     1160
     1161        return $data;
     1162    }
     1163
     1164    /**
    10131165     * Internal function used to disable an insert query which
    10141166     * will trigger a wpdb error for testing purposes.
  • branches/4.9/tests/phpunit/tests/term/meta.php

    r41662 r43510  
    77 */
    88class Tests_Term_Meta extends WP_UnitTestCase {
     9
     10    private $last_register_meta_call = array(
     11        'object_type' => '',
     12        'meta_key'    => '',
     13        'args'        => array(),
     14    );
     15
    916    public function setUp() {
    1017        parent::setUp();
     
    442449        $q->set( 'cache_results', true );
    443450    }
     451
     452    /**
     453     * @ticket 38323
     454     * @dataProvider data_register_term_meta
     455     */
     456    public function test_register_term_meta( $taxonomy, $meta_key, $args ) {
     457        add_filter( 'register_meta_args', array( $this, 'filter_register_meta_args_set_last_register_meta_call' ), 10, 4 );
     458
     459        register_term_meta( $taxonomy, $meta_key, $args );
     460
     461        $args['object_subtype'] = $taxonomy;
     462
     463        // Reset global so subsequent data tests do not get polluted.
     464        $GLOBALS['wp_meta_keys'] = array();
     465
     466        $this->assertEquals( 'term', $this->last_register_meta_call['object_type'] );
     467        $this->assertEquals( $meta_key, $this->last_register_meta_call['meta_key'] );
     468        $this->assertEquals( $args, $this->last_register_meta_call['args'] );
     469    }
     470
     471    public function data_register_term_meta() {
     472        return array(
     473            array( 'wptests_tax', 'registered_key1', array( 'single' => true ) ),
     474            array( 'category', 'registered_key2', array() ),
     475            array( '', 'registered_key3', array( 'sanitize_callback' => 'absint' ) ),
     476        );
     477    }
     478
     479    public function filter_register_meta_args_set_last_register_meta_call( $args, $defaults, $object_type, $meta_key ) {
     480        $this->last_register_meta_call['object_type'] = $object_type;
     481        $this->last_register_meta_call['meta_key']    = $meta_key;
     482        $this->last_register_meta_call['args']        = $args;
     483
     484        return $args;
     485    }
     486
     487    /**
     488     * @ticket 38323
     489     * @dataProvider data_unregister_term_meta
     490     */
     491    public function test_unregister_term_meta( $taxonomy, $meta_key ) {
     492        global $wp_meta_keys;
     493
     494        register_term_meta( $taxonomy, $meta_key, array() );
     495        unregister_term_meta( $taxonomy, $meta_key );
     496
     497        $actual = $wp_meta_keys;
     498
     499        // Reset global so subsequent data tests do not get polluted.
     500        $wp_meta_keys = array();
     501
     502        $this->assertEmpty( $actual );
     503    }
     504
     505    public function data_unregister_term_meta() {
     506        return array(
     507            array( 'wptests_tax', 'registered_key1' ),
     508            array( 'category', 'registered_key2' ),
     509            array( '', 'registered_key3' ),
     510        );
     511    }
    444512}
Note: See TracChangeset for help on using the changeset viewer.