Ticket #38323: 38323.8.register-meta.diff
File 38323.8.register-meta.diff, 37.8 KB (added by , 5 years ago) |
---|
-
src/wp-includes/capabilities.php
281 281 list( $_, $object_type, $_ ) = explode( '_', $cap ); 282 282 $object_id = (int) $args[0]; 283 283 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 ); 290 285 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 ) ) { 323 287 $caps[] = 'do_not_allow'; 324 288 break; 325 289 } … … 328 292 329 293 $meta_key = isset( $args[1] ) ? $args[1] : false; 330 294 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 ); 333 297 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}" ) ) { 353 299 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 { 374 318 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 375 365 if ( ! $allowed ) { 376 366 $caps[] = $cap; 377 367 } 378 } elseif ( $meta_key && is_protected_meta( $meta_key, $object_type ) ) {379 $caps[] = $cap;380 368 } 381 369 break; 382 370 case 'edit_comment': -
src/wp-includes/meta.php
44 44 return false; 45 45 } 46 46 47 $meta_subtype = get_object_subtype( $meta_type, $object_id ); 48 47 49 $column = sanitize_key( $meta_type . '_id' ); 48 50 49 51 // expected_slashed ($meta_key) 50 52 $meta_key = wp_unslash( $meta_key ); 51 53 $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 ); 53 55 54 56 /** 55 57 * Filters whether to add metadata of a specific type. … … 165 167 return false; 166 168 } 167 169 170 $meta_subtype = get_object_subtype( $meta_type, $object_id ); 171 168 172 $column = sanitize_key( $meta_type . '_id' ); 169 173 $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id'; 170 174 … … 173 177 $meta_key = wp_unslash( $meta_key ); 174 178 $passed_value = $meta_value; 175 179 $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 ); 177 181 178 182 /** 179 183 * Filters whether to update metadata of a specific type. … … 666 670 return false; 667 671 } 668 672 673 $meta_subtype = get_object_subtype( $meta_type, $object_id ); 674 669 675 // Sanitize the meta 670 676 $_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 ); 672 678 $meta_value = maybe_serialize( $meta_value ); 673 679 674 680 // Format the data query arguments. … … 968 974 * Sanitize meta value. 969 975 * 970 976 * @since 3.1.3 977 * @since 5.0.0 The `$object_subtype` parameter was added. 971 978 * 972 979 * @param string $meta_key Meta key. 973 980 * @param mixed $meta_value Meta value to sanitize. … … 975 982 * 976 983 * @return mixed Sanitized $meta_value. 977 984 */ 978 function sanitize_meta( $meta_key, $meta_value, $object_type ) { 985 function 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 979 1005 /** 980 1006 * Filters the sanitization of a specific meta key of a specific meta type. 981 1007 * … … 995 1021 /** 996 1022 * Registers a meta key. 997 1023 * 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 * 998 1031 * @since 3.3.0 999 1032 * @since 4.6.0 {@link https://core.trac.wordpress.org/ticket/35658 Modified 1000 1033 * to support an array of data to attach to registered meta keys}. Previous arguments for 1001 1034 * `$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. 1002 1036 * 1003 1037 * @param string $object_type Type of object this meta is registered to. 1004 1038 * @param string $meta_key Meta key to register. 1005 1039 * @param array $args { 1006 1040 * 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. 1008 1044 * @type string $type The type of data associated with this meta key. 1009 1045 * Valid values are 'string', 'boolean', 'integer', and 'number'. 1010 1046 * @type string $description A description of the data attached to this meta key. … … 1027 1063 } 1028 1064 1029 1065 $defaults = array( 1066 'object_subtype' => '', 1030 1067 'type' => 'string', 1031 1068 'description' => '', 1032 1069 'single' => false, … … 1067 1104 $args = apply_filters( 'register_meta_args', $args, $defaults, $object_type, $meta_key ); 1068 1105 $args = wp_parse_args( $args, $defaults ); 1069 1106 1107 $object_subtype = ! empty( $args['object_subtype'] ) ? $args['object_subtype'] : ''; 1108 1070 1109 // If `auth_callback` is not provided, fall back to `is_protected_meta()`. 1071 1110 if ( empty( $args['auth_callback'] ) ) { 1072 1111 if ( is_protected_meta( $meta_key, $object_type ) ) { … … 1078 1117 1079 1118 // Back-compat: old sanitize and auth callbacks are applied to all of an object type. 1080 1119 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 } 1082 1125 } 1083 1126 1084 1127 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 } 1086 1133 } 1087 1134 1088 1135 // Global registry only contains meta keys registered with the array of arguments added in 4.6.0. 1089 1136 if ( ! $has_old_auth_cb && ! $has_old_sanitize_cb ) { 1090 $wp_meta_keys[ $object_type ][ $meta_key ] = $args;1137 unset( $args['object_subtype'] ); 1091 1138 1139 $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] = $args; 1140 1092 1141 return true; 1093 1142 } 1094 1143 … … 1099 1148 * Checks if a meta key is registered. 1100 1149 * 1101 1150 * @since 4.6.0 1151 * @since 5.0.0 The `$object_subtype` parameter was added. 1102 1152 * 1103 1153 * @param string $object_type The type of object. 1104 1154 * @param string $meta_key The meta key. 1155 * @param string $object_subtype Optional. The subtype of the object type. 1105 1156 * 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. 1107 1159 */ 1108 function registered_meta_key_exists( $object_type, $meta_key ) {1109 global $wp_meta_keys;1160 function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = '' ) { 1161 $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); 1110 1162 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 ] ); 1124 1164 } 1125 1165 1126 1166 /** … … 1127 1167 * Unregisters a meta key from the list of registered keys. 1128 1168 * 1129 1169 * @since 4.6.0 1170 * @since 5.0.0 The `$object_subtype` parameter was added. 1130 1171 * 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. 1133 1175 * @return bool True if successful. False if the meta key was not registered. 1134 1176 */ 1135 function unregister_meta_key( $object_type, $meta_key ) {1177 function unregister_meta_key( $object_type, $meta_key, $object_subtype = '' ) { 1136 1178 global $wp_meta_keys; 1137 1179 1138 if ( ! registered_meta_key_exists( $object_type, $meta_key ) ) {1180 if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 1139 1181 return false; 1140 1182 } 1141 1183 1142 $args = $wp_meta_keys[ $object_type ][ $ meta_key ];1184 $args = $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ]; 1143 1185 1144 1186 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 } 1146 1192 } 1147 1193 1148 1194 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 } 1150 1200 } 1151 1201 1152 unset( $wp_meta_keys[ $object_type ][ $ meta_key ] );1202 unset( $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] ); 1153 1203 1154 1204 // Do some clean up 1205 if ( empty( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) { 1206 unset( $wp_meta_keys[ $object_type ][ $object_subtype ] ); 1207 } 1155 1208 if ( empty( $wp_meta_keys[ $object_type ] ) ) { 1156 1209 unset( $wp_meta_keys[ $object_type ] ); 1157 1210 } … … 1163 1216 * Retrieves a list of registered meta keys for an object type. 1164 1217 * 1165 1218 * @since 4.6.0 1219 * @since 5.0.0 The `$object_subtype` parameter was added. 1166 1220 * 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. 1168 1223 * @return array List of registered meta keys. 1169 1224 */ 1170 function get_registered_meta_keys( $object_type ) {1225 function get_registered_meta_keys( $object_type, $object_subtype = '' ) { 1171 1226 global $wp_meta_keys; 1172 1227 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 ] ) ) { 1174 1229 return array(); 1175 1230 } 1176 1231 1177 return $wp_meta_keys[ $object_type ] ;1232 return $wp_meta_keys[ $object_type ][ $object_subtype ]; 1178 1233 } 1179 1234 1180 1235 /** 1181 1236 * Retrieves registered metadata for a specified object. 1182 1237 * 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 * 1183 1241 * @since 4.6.0 1184 1242 * 1185 1243 * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user) … … 1187 1245 * @param string $meta_key Optional. Registered metadata key. If not specified, retrieve all registered 1188 1246 * metadata for the specified object. 1189 1247 * @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. 1191 1249 */ 1192 1250 function get_registered_metadata( $object_type, $object_id, $meta_key = '' ) { 1251 $object_subtype = get_object_subtype( $object_type, $object_id ); 1252 1193 1253 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 ) ) { 1195 1259 return false; 1196 1260 } 1197 $meta_keys = get_registered_meta_keys( $object_type ); 1261 1262 $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); 1198 1263 $meta_key_data = $meta_keys[ $meta_key ]; 1199 1264 1200 1265 $data = get_metadata( $object_type, $object_id, $meta_key, $meta_key_data['single'] ); … … 1203 1268 } 1204 1269 1205 1270 $data = get_metadata( $object_type, $object_id ); 1271 if ( ! $data ) { 1272 return array(); 1273 } 1206 1274 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 ) ); 1215 1278 } 1216 1279 1217 return $registered_data;1280 return array_intersect_key( $data, $meta_keys ); 1218 1281 } 1219 1282 1220 1283 /** … … 1223 1286 * to be explicitly turned off is a warranty seal of sorts. 1224 1287 * 1225 1288 * @access private 1226 * @since 1289 * @since 4.6.0 1227 1290 * 1228 * @param 1229 * @param 1291 * @param array $args Arguments from `register_meta()`. 1292 * @param array $default_args Default arguments for `register_meta()`. 1230 1293 * 1231 1294 * @return array Filtered arguments. 1232 1295 */ 1233 1296 function _wp_register_meta_args_whitelist( $args, $default_args ) { 1234 $whitelist = array_keys( $default_args ); 1297 return array_intersect_key( $args, $default_args ); 1298 } 1235 1299 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 */ 1309 function 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 ); 1241 1363 } 1242 1364 1243 return $ args;1365 return $object_subtype; 1244 1366 } -
src/wp-includes/rest-api/fields/class-wp-rest-comment-meta-fields.php
28 28 } 29 29 30 30 /** 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 /** 31 42 * Retrieves the type for register_rest_field() in the context of comments. 32 43 * 33 44 * @since 4.7.0 -
src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php
25 25 abstract protected function get_meta_type(); 26 26 27 27 /** 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 /** 28 39 * Retrieves the object type for register_rest_field(). 29 40 * 30 41 * @since 4.7.0 … … 340 351 protected function get_registered_fields() { 341 352 $registered = array(); 342 353 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 ) { 344 363 if ( empty( $args['show_in_rest'] ) ) { 345 364 continue; 346 365 } -
src/wp-includes/rest-api/fields/class-wp-rest-post-meta-fields.php
47 47 } 48 48 49 49 /** 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 /** 50 61 * Retrieves the type for register_rest_field(). 51 62 * 52 63 * @since 4.7.0 -
src/wp-includes/rest-api/fields/class-wp-rest-term-meta-fields.php
47 47 } 48 48 49 49 /** 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 /** 50 61 * Retrieves the type for register_rest_field(). 51 62 * 52 63 * @since 4.7.0 -
src/wp-includes/rest-api/fields/class-wp-rest-user-meta-fields.php
28 28 } 29 29 30 30 /** 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 /** 31 42 * Retrieves the type for register_rest_field(). 32 43 * 33 44 * @since 4.7.0 -
tests/phpunit/tests/meta/registerMeta.php
74 74 75 75 $expected = array( 76 76 '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 ), 84 86 ), 85 87 ), 86 88 ); … … 88 90 $this->assertEquals( $actual, $expected ); 89 91 } 90 92 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() { 92 94 global $wp_meta_keys; 93 register_meta( ' term', 'category_icon', array() );95 register_meta( 'post', 'flight_number', array( 'object_subtype' => 'journey' ) ); 94 96 $actual = $wp_meta_keys; 95 unregister_meta_key( ' term', 'category_icon' );97 unregister_meta_key( 'post', 'flight_number', 'journey' ); 96 98 97 99 $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 ), 106 110 ), 107 111 ), 108 112 ); … … 110 114 $this->assertEquals( $actual, $expected ); 111 115 } 112 116 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 113 177 public function test_register_meta_with_deprecated_sanitize_callback_does_not_populate_wp_meta_keys() { 114 178 global $wp_meta_keys; 115 179 … … 148 212 149 213 $expected = array( 150 214 '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 ), 158 224 ), 159 225 ), 160 226 ); -
tests/phpunit/tests/rest-api/rest-post-meta-fields.php
12 12 class WP_Test_REST_Post_Meta_Fields extends WP_Test_REST_TestCase { 13 13 protected static $wp_meta_keys_saved; 14 14 protected static $post_id; 15 protected static $custom_post_type_id; 15 16 16 17 public static function wpSetUpBeforeClass( $factory ) { 17 18 self::$wp_meta_keys_saved = $GLOBALS['wp_meta_keys']; 18 19 self::$post_id = $factory->post->create(); 20 21 self::$custom_post_type_id = $factory->post->create( array( 'post_type' => 'cpt' ) ); 19 22 } 20 23 21 24 public static function wpTearDownAfterClass() { 22 25 $GLOBALS['wp_meta_keys'] = self::$wp_meta_keys_saved; 23 26 wp_delete_post( self::$post_id, true ); 27 wp_delete_post( self::$custom_post_type_id, true ); 24 28 } 25 29 26 30 public function setUp() { … … 120 124 ) 121 125 ); 122 126 127 $args = array( 128 'show_in_rest' => true, 129 'supports' => array( 'custom-fields' ), 130 ); 131 register_post_type( 'cpt', $args ); 132 133 register_meta( 'post', 'test_cpt_single', array( 134 'show_in_rest' => true, 135 'single' => true, 136 'object_subtype' => 'cpt', 137 ) ); 138 139 register_meta( 'post', '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_meta( 'post', 'test_single', array( 148 'show_in_rest' => true, 149 'single' => true, 150 'auth_callback' => '__return_false', 151 'object_subtype' => 'cpt', 152 ) ); 153 123 154 /** @var WP_REST_Server $wp_rest_server */ 124 155 global $wp_rest_server; 125 156 $wp_rest_server = new Spy_REST_Server; … … 1047 1078 $this->assertArrayNotHasKey( 'test_no_type', $meta_schema ); 1048 1079 } 1049 1080 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 1050 1170 /** 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 /** 1051 1218 * Internal function used to disable an insert query which 1052 1219 * will trigger a wpdb error for testing purposes. 1053 1220 */