Ticket #38323: 38323.14.diff
File 38323.14.diff, 61.6 KB (added by , 5 years ago) |
---|
-
src/wp-admin/includes/ajax-actions.php
706 706 if ( ! $meta = get_metadata_by_mid( 'post', $id ) ) { 707 707 wp_die( 1 ); 708 708 } 709 710 if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $meta->post_id, $meta->meta_key ) ) {709 $object_subtype = get_object_subtype( 'post', $id ); 710 if ( is_protected_meta( $meta->meta_key, 'post', $object_subtype ) || ! current_user_can( 'delete_post_meta', $meta->post_id, $meta->meta_key ) ) { 711 711 wp_die( -1 ); 712 712 } 713 713 if ( delete_meta( $meta->meta_id ) ) { … … 1439 1439 if ( ! $meta = get_metadata_by_mid( 'post', $mid ) ) { 1440 1440 wp_die( 0 ); // if meta doesn't exist 1441 1441 } 1442 if ( is_protected_meta( $meta->meta_key, 'post' ) || is_protected_meta( $key, 'post' ) || 1442 $object_subtype = get_object_subtype( 'post', $meta->post_id ); 1443 if ( is_protected_meta( $meta->meta_key, 'post', $object_subtype ) || is_protected_meta( $key, 'post', $object_subtype ) || 1443 1444 ! current_user_can( 'edit_post_meta', $meta->post_id, $meta->meta_key ) || 1444 1445 ! current_user_can( 'edit_post_meta', $meta->post_id, $key ) ) { 1445 1446 wp_die( -1 ); -
src/wp-admin/includes/meta-boxes.php
724 724 <div id="ajax-response"></div> 725 725 <?php 726 726 $metadata = has_meta( $post->ID ); 727 $object_subtype = get_object_subtype( 'post', $post->ID ); 727 728 foreach ( $metadata as $key => $value ) { 728 if ( is_protected_meta( $metadata[ $key ]['meta_key'], 'post' ) || ! current_user_can( 'edit_post_meta', $post->ID, $metadata[ $key ]['meta_key'] ) ) {729 if ( is_protected_meta( $metadata[ $key ]['meta_key'], 'post', $object_subtype ) || ! current_user_can( 'edit_post_meta', $post->ID, $metadata[ $key ]['meta_key'] ) ) { 729 730 unset( $metadata[ $key ] ); 730 731 } 731 732 } -
src/wp-admin/includes/post.php
322 322 if ( $meta->post_id != $post_ID ) { 323 323 continue; 324 324 } 325 if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'edit_post_meta', $post_ID, $meta->meta_key ) ) { 325 $object_subtype = get_object_subtype( 'post', $post_ID ); 326 if ( is_protected_meta( $meta->meta_key, 'post', $object_subtype ) || ! current_user_can( 'edit_post_meta', $post_ID, $meta->meta_key ) ) { 326 327 continue; 327 328 } 328 if ( is_protected_meta( $value['key'], 'post' ) || ! current_user_can( 'edit_post_meta', $post_ID, $value['key'] ) ) {329 if ( is_protected_meta( $value['key'], 'post', $object_subtype ) || ! current_user_can( 'edit_post_meta', $post_ID, $value['key'] ) ) { 329 330 continue; 330 331 } 331 332 update_meta( $key, $value['key'], $value['value'] ); … … 340 341 if ( $meta->post_id != $post_ID ) { 341 342 continue; 342 343 } 343 if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $post_ID, $meta->meta_key ) ) { 344 $object_subtype = get_object_subtype( 'post', $post_ID ); 345 if ( is_protected_meta( $meta->meta_key, 'post', $object_subtype ) || ! current_user_can( 'delete_post_meta', $post_ID, $meta->meta_key ) ) { 344 346 continue; 345 347 } 346 348 delete_meta( $key ); … … 878 880 if ( $metakeyinput ) { 879 881 $metakey = $metakeyinput; // default 880 882 } 881 882 if ( is_protected_meta( $metakey, 'post' ) || ! current_user_can( 'add_post_meta', $post_ID, $metakey ) ) {883 $object_subtype = get_object_subtype( 'post', $post_ID ); 884 if ( is_protected_meta( $metakey, 'post', $object_subtype ) || ! current_user_can( 'add_post_meta', $post_ID, $metakey ) ) { 883 885 return false; 884 886 } 885 887 -
src/wp-admin/includes/template.php
582 582 function _list_meta_row( $entry, &$count ) { 583 583 static $update_nonce = ''; 584 584 585 if ( is_protected_meta( $entry['meta_key'], 'post' ) ) { 585 $object_subtype = get_object_subtype( 'post', $entry['post_id'] ); 586 if ( is_protected_meta( $entry['meta_key'], 'post', $object_subtype ) ) { 586 587 return ''; 587 588 } 588 589 … … 695 696 <?php 696 697 697 698 foreach ( $keys as $key ) { 698 if ( is_protected_meta( $key, 'post' ) || ! current_user_can( 'add_post_meta', $post->ID, $key ) ) { 699 $object_subtype = get_object_subtype( 'post', $post->ID ); 700 if ( is_protected_meta( $key, 'post', $object_subtype ) || ! current_user_can( 'add_post_meta', $post->ID, $key ) ) { 699 701 continue; 700 702 } 701 703 echo "\n<option value='" . esc_attr( $key ) . "'>" . esc_html( $key ) . '</option>'; -
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 } 290 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 } 284 $object_subtype = get_object_subtype( $object_type, $object_id ); 317 285 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, $object_subtype ); 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 ); 353 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 ); 298 if ( ! empty( $object_subtype ) && has_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) { 299 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 { 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 } 374 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. … … 947 953 * 948 954 * @param string $meta_key Meta key. 949 955 * @param string|null $meta_type Optional. Type of object metadata is for (e.g., comment, post, or user). 956 * @param string $object_subtype Optional. Sub type of object metadata. 950 957 * @return bool Whether the meta key is considered protected. 951 958 */ 952 function is_protected_meta( $meta_key, $meta_type = null ) {959 function is_protected_meta( $meta_key, $meta_type = null, $object_subtype = '' ) { 953 960 $protected = ( '_' == $meta_key[0] ); 954 961 955 962 /** … … 960 967 * @param bool $protected Whether the key is considered protected. 961 968 * @param string $meta_key Meta key. 962 969 * @param string|null $meta_type Type of object metadata is for (e.g., comment, post, or user). 970 * @param string|null $object_subtype Optional. Sub type of object metadata. 963 971 */ 964 return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );972 return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type, $object_subtype ); 965 973 } 966 974 967 975 /** 968 976 * Sanitize meta value. 969 977 * 970 978 * @since 3.1.3 979 * @since 5.0.0 The `$object_subtype` parameter was added. 971 980 * 972 981 * @param string $meta_key Meta key. 973 982 * @param mixed $meta_value Meta value to sanitize. … … 975 984 * 976 985 * @return mixed Sanitized $meta_value. 977 986 */ 978 function sanitize_meta( $meta_key, $meta_value, $object_type ) { 987 function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype = '' ) { 988 if ( ! empty( $object_subtype ) && has_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}" ) ) { 989 990 /** 991 * Filters the sanitization of a specific meta key of a specific meta type and subtype. 992 * 993 * The dynamic portions of the hook name, `$object_type`, `$meta_key`, 994 * and `$object_subtype`, refer to the metadata object type (comment, post, term or user), 995 * the meta key value, and the object subtype respectively. 996 * 997 * @since 5.0.0 998 * 999 * @param mixed $meta_value Meta value to sanitize. 1000 * @param string $meta_key Meta key. 1001 * @param string $object_type Object type. 1002 * @param string $object_subtype Object subtype. 1003 */ 1004 return apply_filters( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $meta_value, $meta_key, $object_type, $object_subtype ); 1005 } 1006 979 1007 /** 980 1008 * Filters the sanitization of a specific meta key of a specific meta type. 981 1009 * … … 995 1023 /** 996 1024 * Registers a meta key. 997 1025 * 1026 * It is recommended to register meta keys for a specific combination of object type and object subtype. If passing 1027 * an object subtype is omitted, the meta key will be registered for the entire object type, however it can be partly 1028 * overridden in case a more specific meta key of the same name exists for the same object type and a subtype. 1029 * 1030 * If an object type does not support any subtypes, such as users or comments, you should commonly call this function 1031 * without passing a subtype. 1032 * 998 1033 * @since 3.3.0 999 1034 * @since 4.6.0 {@link https://core.trac.wordpress.org/ticket/35658 Modified 1000 1035 * to support an array of data to attach to registered meta keys}. Previous arguments for 1001 1036 * `$sanitize_callback` and `$auth_callback` have been folded into this array. 1037 * @since 5.0.0 The `$object_subtype` argument was added to the arguments array. 1002 1038 * 1003 1039 * @param string $object_type Type of object this meta is registered to. 1004 1040 * @param string $meta_key Meta key to register. 1005 1041 * @param array $args { 1006 1042 * Data used to describe the meta key when registered. 1007 1043 * 1044 * @type string $object_subtype A subtype; e.g. if the object type is "post", the post type. If left empty, 1045 * the meta key will be registered on the entire object type. Default empty. 1008 1046 * @type string $type The type of data associated with this meta key. 1009 1047 * Valid values are 'string', 'boolean', 'integer', and 'number'. 1010 1048 * @type string $description A description of the data attached to this meta key. … … 1027 1065 } 1028 1066 1029 1067 $defaults = array( 1068 'object_subtype' => '', 1030 1069 'type' => 'string', 1031 1070 'description' => '', 1032 1071 'single' => false, … … 1067 1106 $args = apply_filters( 'register_meta_args', $args, $defaults, $object_type, $meta_key ); 1068 1107 $args = wp_parse_args( $args, $defaults ); 1069 1108 1109 $object_subtype = ! empty( $args['object_subtype'] ) ? $args['object_subtype'] : ''; 1110 1070 1111 // If `auth_callback` is not provided, fall back to `is_protected_meta()`. 1071 1112 if ( empty( $args['auth_callback'] ) ) { 1072 if ( is_protected_meta( $meta_key, $object_type ) ) {1113 if ( is_protected_meta( $meta_key, $object_type, $object_subtype ) ) { 1073 1114 $args['auth_callback'] = '__return_false'; 1074 1115 } else { 1075 1116 $args['auth_callback'] = '__return_true'; … … 1078 1119 1079 1120 // Back-compat: old sanitize and auth callbacks are applied to all of an object type. 1080 1121 if ( is_callable( $args['sanitize_callback'] ) ) { 1081 add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 3 ); 1122 if ( ! empty( $object_subtype ) ) { 1123 add_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'], 10, 4 ); 1124 } else { 1125 add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'], 10, 3 ); 1126 } 1082 1127 } 1083 1128 1084 1129 if ( is_callable( $args['auth_callback'] ) ) { 1085 add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 ); 1130 if ( ! empty( $object_subtype ) ) { 1131 add_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'], 10, 6 ); 1132 } else { 1133 add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'], 10, 6 ); 1134 } 1086 1135 } 1087 1136 1088 1137 // Global registry only contains meta keys registered with the array of arguments added in 4.6.0. 1089 1138 if ( ! $has_old_auth_cb && ! $has_old_sanitize_cb ) { 1090 $wp_meta_keys[ $object_type ][ $meta_key ] = $args; 1139 unset( $args['object_subtype'] ); 1140 1141 $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] = $args; 1091 1142 1092 1143 return true; 1093 1144 } … … 1099 1150 * Checks if a meta key is registered. 1100 1151 * 1101 1152 * @since 4.6.0 1153 * @since 5.0.0 The `$object_subtype` parameter was added. 1102 1154 * 1103 1155 * @param string $object_type The type of object. 1104 1156 * @param string $meta_key The meta key. 1157 * @param string $object_subtype Optional. The subtype of the object type. 1105 1158 * 1106 * @return bool True if the meta key is registered to the object type. False if not. 1159 * @return bool True if the meta key is registered to the object type and, if provided, 1160 * the object subtype. False if not. 1107 1161 */ 1108 function registered_meta_key_exists( $object_type, $meta_key ) { 1109 global $wp_meta_keys; 1110 1111 if ( ! is_array( $wp_meta_keys ) ) { 1112 return false; 1113 } 1162 function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = '' ) { 1163 $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); 1114 1164 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; 1165 return isset( $meta_keys[ $meta_key ] ); 1124 1166 } 1125 1167 1126 1168 /** 1127 1169 * Unregisters a meta key from the list of registered keys. 1128 1170 * 1129 1171 * @since 4.6.0 1172 * @since 5.0.0 The `$object_subtype` parameter was added. 1130 1173 * 1131 * @param string $object_type The type of object. 1132 * @param string $meta_key The meta key. 1174 * @param string $object_type The type of object. 1175 * @param string $meta_key The meta key. 1176 * @param string $object_subtype Optional. The subtype of the object type. 1133 1177 * @return bool True if successful. False if the meta key was not registered. 1134 1178 */ 1135 function unregister_meta_key( $object_type, $meta_key ) {1179 function unregister_meta_key( $object_type, $meta_key, $object_subtype = '' ) { 1136 1180 global $wp_meta_keys; 1137 1181 1138 if ( ! registered_meta_key_exists( $object_type, $meta_key ) ) {1182 if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 1139 1183 return false; 1140 1184 } 1141 1185 1142 $args = $wp_meta_keys[ $object_type ][ $ meta_key ];1186 $args = $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ]; 1143 1187 1144 1188 if ( isset( $args['sanitize_callback'] ) && is_callable( $args['sanitize_callback'] ) ) { 1145 remove_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'] ); 1189 if ( ! empty( $object_subtype ) ) { 1190 remove_filter( "sanitize_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['sanitize_callback'] ); 1191 } else { 1192 remove_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['sanitize_callback'] ); 1193 } 1146 1194 } 1147 1195 1148 1196 if ( isset( $args['auth_callback'] ) && is_callable( $args['auth_callback'] ) ) { 1149 remove_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'] ); 1197 if ( ! empty( $object_subtype ) ) { 1198 remove_filter( "auth_{$object_type}_meta_{$meta_key}_for_{$object_subtype}", $args['auth_callback'] ); 1199 } else { 1200 remove_filter( "auth_{$object_type}_meta_{$meta_key}", $args['auth_callback'] ); 1201 } 1150 1202 } 1151 1203 1152 unset( $wp_meta_keys[ $object_type ][ $ meta_key ] );1204 unset( $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] ); 1153 1205 1154 1206 // Do some clean up 1207 if ( empty( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) { 1208 unset( $wp_meta_keys[ $object_type ][ $object_subtype ] ); 1209 } 1155 1210 if ( empty( $wp_meta_keys[ $object_type ] ) ) { 1156 1211 unset( $wp_meta_keys[ $object_type ] ); 1157 1212 } … … 1163 1218 * Retrieves a list of registered meta keys for an object type. 1164 1219 * 1165 1220 * @since 4.6.0 1221 * @since 5.0.0 The `$object_subtype` parameter was added. 1166 1222 * 1167 * @param string $object_type The type of object. Post, comment, user, term. 1223 * @param string $object_type The type of object. Post, comment, user, term. 1224 * @param string $object_subtype Optional. The subtype of the object type. 1168 1225 * @return array List of registered meta keys. 1169 1226 */ 1170 function get_registered_meta_keys( $object_type ) {1227 function get_registered_meta_keys( $object_type, $object_subtype = '' ) { 1171 1228 global $wp_meta_keys; 1172 1229 1173 if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $object_type ] ) ) {1230 if ( ! is_array( $wp_meta_keys ) || ! isset( $wp_meta_keys[ $object_type ] ) || ! isset( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) { 1174 1231 return array(); 1175 1232 } 1176 1233 1177 return $wp_meta_keys[ $object_type ] ;1234 return $wp_meta_keys[ $object_type ][ $object_subtype ]; 1178 1235 } 1179 1236 1180 1237 /** 1181 1238 * Retrieves registered metadata for a specified object. 1182 1239 * 1240 * The results include both meta that is registered specifically for the 1241 * object's subtype and meta that is registered for the entire object type. 1242 * 1183 1243 * @since 4.6.0 1184 1244 * 1185 1245 * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user) … … 1187 1247 * @param string $meta_key Optional. Registered metadata key. If not specified, retrieve all registered 1188 1248 * metadata for the specified object. 1189 1249 * @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. 1250 * and values for an object ID if not. False if a given $meta_key is not registered. 1191 1251 */ 1192 1252 function get_registered_metadata( $object_type, $object_id, $meta_key = '' ) { 1253 $object_subtype = get_object_subtype( $object_type, $object_id ); 1254 1193 1255 if ( ! empty( $meta_key ) ) { 1194 if ( ! registered_meta_key_exists( $object_type, $meta_key ) ) { 1256 if ( ! empty( $object_subtype ) && ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 1257 $object_subtype = ''; 1258 } 1259 1260 if ( ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 1195 1261 return false; 1196 1262 } 1197 $meta_keys = get_registered_meta_keys( $object_type ); 1263 1264 $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); 1198 1265 $meta_key_data = $meta_keys[ $meta_key ]; 1199 1266 1200 1267 $data = get_metadata( $object_type, $object_id, $meta_key, $meta_key_data['single'] ); … … 1203 1270 } 1204 1271 1205 1272 $data = get_metadata( $object_type, $object_id ); 1273 if ( ! $data ) { 1274 return array(); 1275 } 1206 1276 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 } 1277 $meta_keys = get_registered_meta_keys( $object_type ); 1278 if ( ! empty( $object_subtype ) ) { 1279 $meta_keys = array_merge( $meta_keys, get_registered_meta_keys( $object_type, $object_subtype ) ); 1215 1280 } 1216 1281 1217 return $registered_data;1282 return array_intersect_key( $data, $meta_keys ); 1218 1283 } 1219 1284 1220 1285 /** … … 1223 1288 * to be explicitly turned off is a warranty seal of sorts. 1224 1289 * 1225 1290 * @access private 1226 * @since 1291 * @since 4.6.0 1227 1292 * 1228 * @param 1229 * @param 1293 * @param array $args Arguments from `register_meta()`. 1294 * @param array $default_args Default arguments for `register_meta()`. 1230 1295 * 1231 1296 * @return array Filtered arguments. 1232 1297 */ 1233 1298 function _wp_register_meta_args_whitelist( $args, $default_args ) { 1234 $whitelist = array_keys( $default_args ); 1299 return array_intersect_key( $args, $default_args ); 1300 } 1301 1302 /** 1303 * Returns the object subtype for a given object ID of a specific type. 1304 * 1305 * @since 5.0.0 1306 * 1307 * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user) 1308 * @param int $object_id ID of the object to retrieve its subtype. 1309 * @return string The object subtype or an empty string if unspecified subtype. 1310 */ 1311 function get_object_subtype( $object_type, $object_id ) { 1312 $object_id = (int) $object_id; 1313 $object_subtype = ''; 1314 1315 switch ( $object_type ) { 1316 case 'post': 1317 $post_type = get_post_type( $object_type ); 1318 1319 if ( ! empty( $post_type ) ) { 1320 $object_subtype = $post_type; 1321 } 1322 break; 1323 1324 case 'term': 1325 $term = get_term( $object_id ); 1326 if ( ! $term instanceof WP_Term ) { 1327 break; 1328 } 1329 1330 $object_subtype = $term->taxonomy; 1331 break; 1332 1333 case 'comment': 1334 $comment = get_comment( $object_id ); 1335 if ( ! $comment ) { 1336 break; 1337 } 1338 1339 $object_subtype = 'comment'; 1340 break; 1341 1342 case 'user': 1343 $user = get_user_by( 'id', $object_id ); 1344 if ( ! $user ) { 1345 break; 1346 } 1347 1348 $object_subtype = 'user'; 1349 break; 1350 1351 case 'blog': 1352 if ( ! is_multisite() ) { 1353 break; 1354 } 1355 $site = get_site( $object_id ); 1356 if ( ! $site ) { 1357 break; 1358 } 1359 1360 $object_subtype = 'site'; 1361 break; 1235 1362 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 }1241 1363 } 1242 1364 1243 return $args; 1365 /** 1366 * Filters the object subtype identifier for a non standard object type. 1367 * 1368 * The dynamic portion of the hook, `$object_type`, refers to the object 1369 * type (post, comment, term, or user). 1370 * 1371 * @since 5.0.0 1372 * 1373 * @param string $object_subtype Empty string to override. 1374 * @param int $object_id ID of the object to get the subtype for. 1375 */ 1376 return apply_filters( "get_object_subtype_{$object_type}", $object_subtype, $object_id ); 1244 1377 } -
src/wp-includes/post-template.php
1064 1064 */ 1065 1065 function the_meta() { 1066 1066 if ( $keys = get_post_custom_keys() ) { 1067 $object_id = get_the_ID(); 1068 $object_subtype = get_object_subtype( 'post', $object_id ); 1067 1069 $li_html = ''; 1068 1070 foreach ( (array) $keys as $key ) { 1069 1071 $keyt = trim( $key ); 1070 if ( is_protected_meta( $keyt, 'post' ) ) {1072 if ( is_protected_meta( $keyt, 'post', $object_subtype ) ) { 1071 1073 continue; 1072 1074 } 1073 1075 -
src/wp-includes/post.php
1990 1990 } 1991 1991 1992 1992 /** 1993 * Registers a meta key for posts. 1994 * 1995 * @since 5.0.0 1996 * 1997 * @param string $post_type Post type to register a meta key for. Pass an empty string 1998 * to register the meta key across all existing post types. 1999 * @param string $meta_key The meta key to register. 2000 * @param array $args Data used to describe the meta key when registered. See 2001 * {@see register_meta()} for a list of supported arguments. 2002 * @return bool True if the meta key was successfully registered, false if not. 2003 */ 2004 function register_post_meta( $post_type, $meta_key, $args ) { 2005 $args['object_subtype'] = $post_type; 2006 2007 return register_meta( 'post', $meta_key, $args ); 2008 } 2009 2010 /** 2011 * Unregisters a meta key for posts. 2012 * 2013 * @since 5.0.0 2014 * 2015 * @param string $post_type Post type the meta key is currently registered for. Pass 2016 * an empty string if the meta key is registered across all 2017 * existing post types. 2018 * @param string $meta_key The meta key to unregister. 2019 * @return bool True on success, false if the meta key was not previously registered. 2020 */ 2021 function unregister_post_meta( $post_type, $meta_key ) { 2022 return unregister_meta_key( 'post', $meta_key, $post_type ); 2023 } 2024 2025 /** 1993 2026 * Retrieve post meta fields, based on post ID. 1994 2027 * 1995 2028 * The post meta fields are retrieved from the cache where possible, -
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 -
src/wp-includes/taxonomy.php
1323 1323 } 1324 1324 1325 1325 /** 1326 * Registers a meta key for terms. 1327 * 1328 * @since 5.0.0 1329 * 1330 * @param string $taxonomy Taxonomy to register a meta key for. Pass an empty string 1331 * to register the meta key across all existing taxonomies. 1332 * @param string $meta_key The meta key to register. 1333 * @param array $args Data used to describe the meta key when registered. See 1334 * {@see register_meta()} for a list of supported arguments. 1335 * @return bool True if the meta key was successfully registered, false if not. 1336 */ 1337 function register_term_meta( $taxonomy, $meta_key, $args ) { 1338 $args['object_subtype'] = $taxonomy; 1339 1340 return register_meta( 'term', $meta_key, $args ); 1341 } 1342 1343 /** 1344 * Unregisters a meta key for terms. 1345 * 1346 * @since 5.0.0 1347 * 1348 * @param string $taxonomy Taxonomy the meta key is currently registered for. Pass 1349 * an empty string if the meta key is registered across all 1350 * existing taxonomies. 1351 * @param string $meta_key The meta key to unregister. 1352 * @return bool True on success, false if the meta key was not previously registered. 1353 */ 1354 function unregister_term_meta( $taxonomy, $meta_key ) { 1355 return unregister_meta_key( 'term', $meta_key, $taxonomy ); 1356 } 1357 1358 /** 1326 1359 * Determines whether a term exists. 1327 1360 * 1328 1361 * Formerly is_term(), introduced in 2.3.0. -
tests/phpunit/tests/meta/registerMeta.php
3 3 * @group meta 4 4 */ 5 5 class Tests_Meta_Register_Meta extends WP_UnitTestCase { 6 6 7 protected static $post_id; 8 protected static $term_id; 9 protected static $comment_id; 10 protected static $user_id; 7 11 8 12 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 ); 10 24 } 11 25 12 26 public function _old_sanitize_meta_cb( $meta_value, $meta_key, $meta_type ) { … … 74 88 75 89 $expected = array( 76 90 '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, 91 '' => array( 92 'flight_number' => array( 93 'type' => 'string', 94 'description' => '', 95 'single' => false, 96 'sanitize_callback' => null, 97 'auth_callback' => '__return_true', 98 'show_in_rest' => false, 99 ), 84 100 ), 85 101 ), 86 102 ); 87 103 88 $this->assertEquals( $ actual, $expected);104 $this->assertEquals( $expected, $actual ); 89 105 } 90 106 91 107 public function test_register_meta_with_term_object_type_populates_wp_meta_keys() { … … 96 112 97 113 $expected = array( 98 114 '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, 115 '' => array( 116 'category_icon' => array( 117 'type' => 'string', 118 'description' => '', 119 'single' => false, 120 'sanitize_callback' => null, 121 'auth_callback' => '__return_true', 122 'show_in_rest' => false, 123 ), 106 124 ), 107 125 ), 108 126 ); 109 127 110 $this->assertEquals( $ actual, $expected);128 $this->assertEquals( $expected, $actual ); 111 129 } 112 130 113 131 public function test_register_meta_with_deprecated_sanitize_callback_does_not_populate_wp_meta_keys() { … … 148 166 149 167 $expected = array( 150 168 '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, 169 '' => array( 170 'flight_number' => array( 171 'type' => 'string', 172 'description' => '', 173 'single' => false, 174 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ), 175 'auth_callback' => '__return_true', 176 'show_in_rest' => false, 177 ), 158 178 ), 159 179 ), 160 180 ); … … 301 321 302 322 $this->assertEmpty( $meta ); 303 323 } 324 325 /** 326 * @ticket 38323 327 * @dataProvider data_get_types_and_subtypes 328 */ 329 public function test_register_meta_with_subtype_populates_wp_meta_keys( $type, $subtype ) { 330 global $wp_meta_keys; 331 332 register_meta( $type, 'flight_number', array( 'object_subtype' => $subtype ) ); 333 334 $expected = array( 335 $type => array( 336 $subtype => array( 337 'flight_number' => array( 338 'type' => 'string', 339 'description' => '', 340 'single' => false, 341 'sanitize_callback' => null, 342 'auth_callback' => '__return_true', 343 'show_in_rest' => false, 344 ), 345 ), 346 ), 347 ); 348 349 $actual = $wp_meta_keys; 350 351 // Reset global so subsequent data tests do not get polluted. 352 $wp_meta_keys = array(); 353 354 $this->assertEquals( $expected, $actual ); 355 } 356 357 /** 358 * @ticket 38323 359 * @dataProvider data_get_types_and_subtypes 360 */ 361 public function test_unregister_meta_with_subtype_unpopulates_wp_meta_keys( $type, $subtype ) { 362 global $wp_meta_keys; 363 364 register_meta( $type, 'flight_number', array( 'object_subtype' => $subtype ) ); 365 unregister_meta_key( $type, 'flight_number', $subtype ); 366 367 $actual = $wp_meta_keys; 368 369 // Reset global so subsequent data tests do not get polluted. 370 $wp_meta_keys = array(); 371 372 $this->assertEmpty( $actual ); 373 } 374 375 /** 376 * @ticket 38323 377 * @dataProvider data_get_types_and_subtypes 378 */ 379 public function test_unregister_meta_without_subtype_keeps_subtype_meta_key( $type, $subtype ) { 380 global $wp_meta_keys; 381 382 register_meta( $type, 'flight_number', array( 'object_subtype' => $subtype ) ); 383 384 // Unregister meta key without subtype. 385 unregister_meta_key( $type, 'flight_number' ); 386 387 $expected = array( 388 $type => array( 389 $subtype => array( 390 'flight_number' => array( 391 'type' => 'string', 392 'description' => '', 393 'single' => false, 394 'sanitize_callback' => null, 395 'auth_callback' => '__return_true', 396 'show_in_rest' => false, 397 ), 398 ), 399 ), 400 ); 401 402 $actual = $wp_meta_keys; 403 404 // Reset global so subsequent data tests do not get polluted. 405 $wp_meta_keys = array(); 406 407 $this->assertEquals( $expected, $actual ); 408 } 409 410 /** 411 * @ticket 38323 412 * @dataProvider data_get_types_and_subtypes 413 */ 414 public function test_get_registered_meta_keys_with_subtype( $type, $subtype ) { 415 register_meta( $type, 'registered_key1', array( 'object_subtype' => $subtype ) ); 416 register_meta( $type, 'registered_key2', array( 'object_subtype' => $subtype ) ); 417 418 $meta_keys = get_registered_meta_keys( $type, $subtype ); 419 420 $this->assertArrayHasKey( 'registered_key1', $meta_keys ); 421 $this->assertArrayHasKey( 'registered_key2', $meta_keys ); 422 $this->assertEmpty( get_registered_meta_keys( $type ) ); 423 } 424 425 /** 426 * @ticket 38323 427 * @dataProvider data_get_types_and_subtypes 428 */ 429 public function test_get_registered_metadata_with_subtype( $type, $subtype ) { 430 global $wp_meta_keys; 431 register_meta( $type, 'registered_key1', array() ); 432 433 // This will override the above registration for objects of $subtype. 434 register_meta( $type, 'registered_key1', array( 435 'object_subtype' => $subtype, 436 'single' => true, 437 ) ); 438 439 // For testing with $single => false. 440 register_meta( $type, 'registered_key2', array( 441 'object_subtype' => $subtype, 442 ) ); 443 444 // Register another meta key for a different subtype. 445 register_meta( $type, 'registered_key3', array( 446 'object_subtype' => 'other_subtype', 447 ) ); 448 449 $object_property_name = $type . '_id'; 450 $object_id = self::$$object_property_name; 451 452 add_metadata( $type, $object_id, 'registered_key1', 'value1' ); 453 add_metadata( $type, $object_id, 'registered_key2', 'value2' ); 454 add_metadata( $type, $object_id, 'registered_key3', 'value3' ); 455 456 $meta = get_registered_metadata( $type, $object_id ); 457 458 $key1 = get_registered_metadata( $type, $object_id, 'registered_key1' ); 459 $key2 = get_registered_metadata( $type, $object_id, 'registered_key2' ); 460 $key3 = get_registered_metadata( $type, $object_id, 'registered_key3' ); 461 462 //$this->assertSame( array( 'registered_key1', 'registered_key2' ), array_keys( $meta ) ); 463 $this->assertSame( 'value1', $meta['registered_key1'][0] ); 464 $this->assertSame( 'value2', $meta['registered_key2'][0] ); 465 466 $this->assertSame( 'value1', $key1 ); 467 $this->assertSame( array( 'value2' ), $key2 ); 468 $this->assertFalse( $key3 ); 469 } 470 471 /** 472 * @ticket 38323 473 * @dataProvider data_get_types_and_subtypes 474 */ 475 public function test_get_object_subtype( $type, $expected_subtype ) { 476 $object_property_name = $type . '_id'; 477 $object_id = self::$$object_property_name; 478 479 $this->assertSame( $expected_subtype, get_object_subtype( $type, $object_id ) ); 480 } 481 482 /** 483 * @ticket 38323 484 */ 485 public function test_get_object_subtype_custom() { 486 add_filter( 'get_object_subtype_customtype', array( $this, 'filter_get_object_subtype_for_customtype' ), 10, 2 ); 487 488 $subtype_for_3 = get_object_subtype( 'customtype', 3 ); 489 $subtype_for_4 = get_object_subtype( 'customtype', 4 ); 490 491 $this->assertSame( 'odd', $subtype_for_3 ); 492 $this->assertSame( 'even', $subtype_for_4 ); 493 } 494 495 public function filter_get_object_subtype_for_customtype( $subtype, $object_id ) { 496 if ( $object_id % 2 === 1 ) { 497 return 'odd'; 498 } 499 500 return 'even'; 501 } 502 503 public function data_get_types_and_subtypes() { 504 return array( 505 array( 'post', 'page' ), 506 array( 'term', 'category' ), 507 array( 'comment', 'comment' ), 508 array( 'user', 'user' ), 509 ); 510 } 304 511 } -
tests/phpunit/tests/post/meta.php
6 6 */ 7 7 class Tests_Post_Meta extends WP_UnitTestCase { 8 8 9 private $last_register_meta_call = array( 10 'object_type' => '', 11 'meta_key' => '', 12 'args' => array(), 13 ); 14 9 15 protected static $author; 10 16 protected static $post_id; 11 17 protected static $post_id_2; … … 238 244 $this->assertEquals( $funky_meta, get_post_meta( self::$post_id, 'test_funky_post_meta', true ) ); 239 245 240 246 } 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 } 241 308 } -
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 $cpt_post_id; 15 16 16 17 public static function wpSetUpBeforeClass( $factory ) { 18 register_post_type( 'cpt', array( 19 'show_in_rest' => true, 20 'supports' => array( 'custom-fields' ), 21 ) ); 22 17 23 self::$wp_meta_keys_saved = isset( $GLOBALS['wp_meta_keys'] ) ? $GLOBALS['wp_meta_keys'] : array(); 18 24 self::$post_id = $factory->post->create(); 25 self::$cpt_post_id = $factory->post->create( array( 'post_type' => 'cpt' ) ); 19 26 } 20 27 21 28 public static function wpTearDownAfterClass() { 22 29 $GLOBALS['wp_meta_keys'] = self::$wp_meta_keys_saved; 23 30 wp_delete_post( self::$post_id, true ); 31 wp_delete_post( self::$cpt_post_id, true ); 32 33 unregister_post_type( 'cpt' ); 24 34 } 25 35 26 36 public function setUp() { … … 120 130 ) 121 131 ); 122 132 133 register_post_type( 'cpt', array( 134 'show_in_rest' => true, 135 'supports' => array( 'custom-fields' ), 136 ) ); 137 138 register_post_meta( 'cpt', 'test_cpt_single', array( 139 'show_in_rest' => true, 140 'single' => true, 141 ) ); 142 143 register_post_meta( 'cpt', 'test_cpt_multi', array( 144 'show_in_rest' => true, 145 'single' => false, 146 ) ); 147 148 // Register 'test_single' on subtype to override for bad auth. 149 register_post_meta( 'cpt', 'test_single', array( 150 'show_in_rest' => true, 151 'single' => true, 152 'auth_callback' => '__return_false', 153 ) ); 154 123 155 /** @var WP_REST_Server $wp_rest_server */ 124 156 global $wp_rest_server; 125 157 $wp_rest_server = new Spy_REST_Server; … … 1048 1080 } 1049 1081 1050 1082 /** 1083 * @ticket 38323 1084 * @dataProvider data_get_subtype_meta_value 1085 */ 1086 public function test_get_subtype_meta_value( $post_type, $meta_key, $single, $in_post_type ) { 1087 $post_id = self::$post_id; 1088 $endpoint = 'posts'; 1089 if ( 'cpt' === $post_type ) { 1090 $post_id = self::$cpt_post_id; 1091 $endpoint = 'cpt'; 1092 } 1093 1094 $meta_value = 'testvalue'; 1095 1096 add_post_meta( $post_id, $meta_key, $meta_value ); 1097 1098 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/%s/%d', $endpoint, $post_id ) ); 1099 $response = rest_get_server()->dispatch( $request ); 1100 1101 $this->assertEquals( 200, $response->get_status() ); 1102 1103 $data = $response->get_data(); 1104 1105 $this->assertArrayHasKey( 'meta', $data ); 1106 $this->assertInternalType( 'array', $data['meta'] ); 1107 1108 if ( $in_post_type ) { 1109 $expected_value = $meta_value; 1110 if ( ! $single ) { 1111 $expected_value = array( $expected_value ); 1112 } 1113 1114 $this->assertArrayHasKey( $meta_key, $data['meta'] ); 1115 $this->assertEquals( $expected_value, $data['meta'][ $meta_key ] ); 1116 } else { 1117 $this->assertArrayNotHasKey( $meta_key, $data['meta'] ); 1118 } 1119 } 1120 1121 public function data_get_subtype_meta_value() { 1122 return array( 1123 array( 'cpt', 'test_cpt_single', true, true ), 1124 array( 'cpt', 'test_cpt_multi', false, true ), 1125 array( 'cpt', 'test_single', true, true ), 1126 array( 'cpt', 'test_multi', false, true ), 1127 array( 'post', 'test_cpt_single', true, false ), 1128 array( 'post', 'test_cpt_multi', false, false ), 1129 array( 'post', 'test_single', true, true ), 1130 array( 'post', 'test_multi', false, true ), 1131 ); 1132 } 1133 1134 /** 1135 * @ticket 38323 1136 * @dataProvider data_set_subtype_meta_value 1137 */ 1138 public function test_set_subtype_meta_value( $post_type, $meta_key, $single, $in_post_type, $can_write ) { 1139 $post_id = self::$post_id; 1140 $endpoint = 'posts'; 1141 if ( 'cpt' === $post_type ) { 1142 $post_id = self::$cpt_post_id; 1143 $endpoint = 'cpt'; 1144 } 1145 1146 $meta_value = 'value_to_set'; 1147 1148 $this->grant_write_permission(); 1149 1150 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/%s/%d', $endpoint, $post_id ) ); 1151 $request->set_body_params( array( 1152 'meta' => array( 1153 $meta_key => $meta_value, 1154 ), 1155 ) ); 1156 1157 $response = rest_get_server()->dispatch( $request ); 1158 if ( ! $can_write ) { 1159 $this->assertEquals( 403, $response->get_status() ); 1160 $this->assertEmpty( get_post_meta( $post_id, $meta_key, $single ) ); 1161 return; 1162 } 1163 1164 $this->assertEquals( 200, $response->get_status() ); 1165 1166 $data = $response->get_data(); 1167 $this->assertArrayHasKey( 'meta', $data ); 1168 $this->assertInternalType( 'array', $data['meta'] ); 1169 1170 if ( $in_post_type ) { 1171 $expected_value = $meta_value; 1172 if ( ! $single ) { 1173 $expected_value = array( $expected_value ); 1174 } 1175 1176 $this->assertEquals( $expected_value, get_post_meta( $post_id, $meta_key, $single ) ); 1177 $this->assertArrayHasKey( $meta_key, $data['meta'] ); 1178 $this->assertEquals( $expected_value, $data['meta'][ $meta_key ] ); 1179 } else { 1180 $this->assertEmpty( get_post_meta( $post_id, $meta_key, $single ) ); 1181 $this->assertArrayNotHasKey( $meta_key, $data['meta'] ); 1182 } 1183 } 1184 1185 public function data_set_subtype_meta_value() { 1186 $data = $this->data_get_subtype_meta_value(); 1187 1188 foreach ( $data as $index => $dataset ) { 1189 $can_write = true; 1190 1191 // This combination is not writable because of an auth callback of '__return_false'. 1192 if ( 'cpt' === $dataset[0] && 'test_single' === $dataset[1] ) { 1193 $can_write = false; 1194 } 1195 1196 $data[ $index ][] = $can_write; 1197 } 1198 1199 return $data; 1200 } 1201 1202 /** 1051 1203 * Internal function used to disable an insert query which 1052 1204 * will trigger a wpdb error for testing purposes. 1053 1205 */ -
tests/phpunit/tests/rest-api/rest-term-meta-fields.php
12 12 class WP_Test_REST_Term_Meta_Fields extends WP_Test_REST_TestCase { 13 13 protected static $wp_meta_keys_saved; 14 14 protected static $category_id; 15 protected static $customtax_term_id; 15 16 16 17 public static function wpSetUpBeforeClass( $factory ) { 18 register_taxonomy( 'customtax', 'post', array( 19 'show_in_rest' => true, 20 ) ); 21 17 22 self::$wp_meta_keys_saved = isset( $GLOBALS['wp_meta_keys'] ) ? $GLOBALS['wp_meta_keys'] : array(); 18 23 self::$category_id = $factory->category->create(); 24 self::$customtax_term_id = $factory->term->create( array( 'taxonomy' => 'customtax' ) ); 19 25 } 20 26 21 27 public static function wpTearDownAfterClass() { 22 28 $GLOBALS['wp_meta_keys'] = self::$wp_meta_keys_saved; 23 29 wp_delete_term( self::$category_id, 'category' ); 30 wp_delete_term( self::$customtax_term_id, 'customtax' ); 31 32 unregister_taxonomy( 'customtax' ); 24 33 } 25 34 26 35 public function setUp() { … … 120 129 ) 121 130 ); 122 131 132 register_taxonomy( 'customtax', 'post', array( 133 'show_in_rest' => true, 134 ) ); 135 136 register_term_meta( 'customtax', 'test_customtax_single', array( 137 'show_in_rest' => true, 138 'single' => true, 139 ) ); 140 141 register_term_meta( 'customtax', 'test_customtax_multi', array( 142 'show_in_rest' => true, 143 'single' => false, 144 ) ); 145 146 // Register 'test_single' on subtype to override for bad auth. 147 register_term_meta( 'customtax', 'test_single', array( 148 'show_in_rest' => true, 149 'single' => true, 150 'auth_callback' => '__return_false', 151 ) ); 152 123 153 /** @var WP_REST_Server $wp_rest_server */ 124 154 global $wp_rest_server; 125 155 $wp_rest_server = new Spy_REST_Server; … … 1048 1078 } 1049 1079 1050 1080 /** 1081 * @ticket 38323 1082 * @dataProvider data_get_subtype_meta_value 1083 */ 1084 public function test_get_subtype_meta_value( $taxonomy, $meta_key, $single, $in_taxonomy ) { 1085 $term_id = self::$category_id; 1086 $endpoint = 'categories'; 1087 if ( 'customtax' === $taxonomy ) { 1088 $term_id = self::$customtax_term_id; 1089 $endpoint = 'customtax'; 1090 } 1091 1092 $meta_value = 'testvalue'; 1093 1094 add_term_meta( $term_id, $meta_key, $meta_value ); 1095 1096 $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/%s/%d', $endpoint, $term_id ) ); 1097 $response = rest_get_server()->dispatch( $request ); 1098 1099 $this->assertEquals( 200, $response->get_status() ); 1100 1101 $data = $response->get_data(); 1102 1103 $this->assertArrayHasKey( 'meta', $data ); 1104 $this->assertInternalType( 'array', $data['meta'] ); 1105 1106 if ( $in_taxonomy ) { 1107 $expected_value = $meta_value; 1108 if ( ! $single ) { 1109 $expected_value = array( $expected_value ); 1110 } 1111 1112 $this->assertArrayHasKey( $meta_key, $data['meta'] ); 1113 $this->assertEquals( $expected_value, $data['meta'][ $meta_key ] ); 1114 } else { 1115 $this->assertArrayNotHasKey( $meta_key, $data['meta'] ); 1116 } 1117 } 1118 1119 public function data_get_subtype_meta_value() { 1120 return array( 1121 array( 'customtax', 'test_customtax_single', true, true ), 1122 array( 'customtax', 'test_customtax_multi', false, true ), 1123 array( 'customtax', 'test_single', true, true ), 1124 array( 'customtax', 'test_multi', false, true ), 1125 array( 'category', 'test_customtax_single', true, false ), 1126 array( 'category', 'test_customtax_multi', false, false ), 1127 array( 'category', 'test_single', true, true ), 1128 array( 'category', 'test_multi', false, true ), 1129 ); 1130 } 1131 1132 /** 1133 * @ticket 38323 1134 * @dataProvider data_set_subtype_meta_value 1135 */ 1136 public function test_set_subtype_meta_value( $taxonomy, $meta_key, $single, $in_taxonomy, $can_write ) { 1137 $term_id = self::$category_id; 1138 $endpoint = 'categories'; 1139 if ( 'customtax' === $taxonomy ) { 1140 $term_id = self::$customtax_term_id; 1141 $endpoint = 'customtax'; 1142 } 1143 1144 $meta_value = 'value_to_set'; 1145 1146 $this->grant_write_permission(); 1147 1148 $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/%s/%d', $endpoint, $term_id ) ); 1149 $request->set_body_params( array( 1150 'meta' => array( 1151 $meta_key => $meta_value, 1152 ), 1153 ) ); 1154 1155 $response = rest_get_server()->dispatch( $request ); 1156 if ( ! $can_write ) { 1157 $this->assertEquals( 403, $response->get_status() ); 1158 $this->assertEmpty( get_term_meta( $term_id, $meta_key, $single ) ); 1159 return; 1160 } 1161 1162 $this->assertEquals( 200, $response->get_status() ); 1163 1164 $data = $response->get_data(); 1165 $this->assertArrayHasKey( 'meta', $data ); 1166 $this->assertInternalType( 'array', $data['meta'] ); 1167 1168 if ( $in_taxonomy ) { 1169 $expected_value = $meta_value; 1170 if ( ! $single ) { 1171 $expected_value = array( $expected_value ); 1172 } 1173 1174 $this->assertEquals( $expected_value, get_term_meta( $term_id, $meta_key, $single ) ); 1175 $this->assertArrayHasKey( $meta_key, $data['meta'] ); 1176 $this->assertEquals( $expected_value, $data['meta'][ $meta_key ] ); 1177 } else { 1178 $this->assertEmpty( get_term_meta( $term_id, $meta_key, $single ) ); 1179 $this->assertArrayNotHasKey( $meta_key, $data['meta'] ); 1180 } 1181 } 1182 1183 public function data_set_subtype_meta_value() { 1184 $data = $this->data_get_subtype_meta_value(); 1185 1186 foreach ( $data as $index => $dataset ) { 1187 $can_write = true; 1188 1189 // This combination is not writable because of an auth callback of '__return_false'. 1190 if ( 'customtax' === $dataset[0] && 'test_single' === $dataset[1] ) { 1191 $can_write = false; 1192 } 1193 1194 $data[ $index ][] = $can_write; 1195 } 1196 1197 return $data; 1198 } 1199 1200 /** 1051 1201 * Internal function used to disable an insert query which 1052 1202 * will trigger a wpdb error for testing purposes. 1053 1203 */ -
tests/phpunit/tests/term/meta.php
6 6 * @ticket 10142 7 7 */ 8 8 class 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 9 16 public function setUp() { 10 17 parent::setUp(); 11 18 register_taxonomy( 'wptests_tax', 'post' ); … … 463 470 public static function set_cache_results( $q ) { 464 471 $q->set( 'cache_results', true ); 465 472 } 473 474 /** 475 * @ticket 38323 476 * @dataProvider data_register_term_meta 477 */ 478 public function test_register_term_meta( $taxonomy, $meta_key, $args ) { 479 add_filter( 'register_meta_args', array( $this, 'filter_register_meta_args_set_last_register_meta_call' ), 10, 4 ); 480 481 register_term_meta( $taxonomy, $meta_key, $args ); 482 483 $args['object_subtype'] = $taxonomy; 484 485 // Reset global so subsequent data tests do not get polluted. 486 $GLOBALS['wp_meta_keys'] = array(); 487 488 $this->assertEquals( 'term', $this->last_register_meta_call['object_type'] ); 489 $this->assertEquals( $meta_key, $this->last_register_meta_call['meta_key'] ); 490 $this->assertEquals( $args, $this->last_register_meta_call['args'] ); 491 } 492 493 public function data_register_term_meta() { 494 return array( 495 array( 'wptests_tax', 'registered_key1', array( 'single' => true ) ), 496 array( 'category', 'registered_key2', array() ), 497 array( '', 'registered_key3', array( 'sanitize_callback' => 'absint' ) ), 498 ); 499 } 500 501 public function filter_register_meta_args_set_last_register_meta_call( $args, $defaults, $object_type, $meta_key ) { 502 $this->last_register_meta_call['object_type'] = $object_type; 503 $this->last_register_meta_call['meta_key'] = $meta_key; 504 $this->last_register_meta_call['args'] = $args; 505 506 return $args; 507 } 508 509 /** 510 * @ticket 38323 511 * @dataProvider data_unregister_term_meta 512 */ 513 public function test_unregister_term_meta( $taxonomy, $meta_key ) { 514 global $wp_meta_keys; 515 516 register_term_meta( $taxonomy, $meta_key, array() ); 517 unregister_term_meta( $taxonomy, $meta_key ); 518 519 $actual = $wp_meta_keys; 520 521 // Reset global so subsequent data tests do not get polluted. 522 $wp_meta_keys = array(); 523 524 $this->assertEmpty( $actual ); 525 } 526 527 public function data_unregister_term_meta() { 528 return array( 529 array( 'wptests_tax', 'registered_key1' ), 530 array( 'category', 'registered_key2' ), 531 array( '', 'registered_key3' ), 532 ); 533 } 466 534 }