Ticket #35658: 35658.2.diff
File 35658.2.diff, 18.7 KB (added by , 9 years ago) |
---|
-
src/wp-includes/class-wp-meta-manager.php
1 <?php 2 /** 3 * A registry for meta data. 4 */ 5 final class WP_Meta_Manager { 6 /** 7 * Registered meta of the post meta type (including pages and CPTs). 8 */ 9 private $post = array( 10 'all' => array() 11 ); 12 13 function __construct() { 14 $post_types_without_meta = array( 'revision', 'nav_menu_item' ); 15 foreach ( get_post_types( null, 'names' ) as $post_type ) { 16 if ( in_array( $post_type, $post_types_without_meta ) ) { 17 continue; 18 } 19 $this->post[$post_type] = array(); 20 } 21 } 22 23 /** 24 * Register a meta key. 25 * 26 * @param array $query { 27 * Array of meta data properties. 28 * 29 * @type string $object_type The meta type this key belongs to, e.g. `post`. 30 * @type string $meta_subtype The meta subtype this key belongs to, e.g. `page`. 31 * @type string $key The meta key. 32 * @type array $json_data_type The meta key's JSON data type. 33 * @todo Let's change this to an array that 34 * includes all JSON schema properties. 35 * @type array $public Whether the meta key should be publicly queryable. 36 * @return true|WP_Error 37 */ 38 public function register( $args ) { 39 if ( empty( $args['object_type'] ) ) { 40 return new WP_Error( 'missing_object_type', __( 'The meta type is required when registering meta.' ) ); 41 } 42 if ( ! property_exists( $this, $args['object_type'] ) ) { 43 return new WP_Error( 'object_type_does_not_exist', __( 'The meta type does not exist in the registry.' ) ); 44 } 45 if ( ! empty( $args['object_subtype'] ) && ! isset( $this->{$args['object_type']}[$args['object_subtype'] ] ) ) { 46 return new WP_Error( 'meta_subtype_does_not_exist', __( 'The meta subtype does not exist in the registry.' ) ); 47 } 48 49 if ( empty( $args['key'] ) ) { 50 return new WP_Error( 'meta_key_required', __( 'The meta key is required.' ) ); 51 } 52 53 if ( empty( $args['json_data_type'] ) ) { 54 return new WP_Error( 'json_data_type_required', __( 'The JSON data type is required.' ) ); 55 } 56 57 if ( ! isset( $args['public'] ) ) { 58 return new WP_Error( 'public_required', __( 'The public-ness of registered meta is required.' ) ); 59 } 60 61 if ( empty( $args['object_subtype'] ) ) { 62 $args['object_subtype'] = 'all'; 63 } 64 65 $this->{$args['object_type']}[$args['object_subtype']][$args['key']] = $args; 66 } 67 68 /** 69 * Retrieve a list of registered meta keys for an object type and subtype. 70 * 71 * @since 4.5.0 72 * 73 * @param string $object_type The type of object. Post, comment, user, term. 74 * @param string $object_subtype A subtype of the object. 75 * 76 * @return array List of registered meta keys. 77 */ 78 function get_registered_meta_keys( $object_type = 'post', $object_subtype = 'all' ) { 79 if ( ! property_exists( $this, $object_type ) ) { 80 return array(); 81 } 82 83 if ( ! isset( $this->{$object_type}[ $object_subtype ] ) ) { 84 return array(); 85 } 86 87 return $this->{$object_type}[ $object_subtype ]; 88 } 89 90 /** 91 * Check if a meta key is registered. 92 * 93 * @since 4.5.0 94 * 95 * @param string $object_type 96 * @param string $meta_key 97 * @param string $object_subtype 98 * 99 * @return bool True if the meta key is registered to the object type and subtype. False if not. 100 */ 101 function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = 'all' ) { 102 if ( ! property_exists( $this, $object_type ) ) { 103 return false; 104 } 105 106 if ( ! isset( $this->{$object_type}[ $object_subtype ] ) ) { 107 return false; 108 } 109 110 if ( ! isset( $this->{$object_type}[ $object_subtype ][ $meta_key ] ) ) { 111 return false; 112 } 113 114 return true; 115 } 116 117 /** 118 * Unregister a meta key from the list of registered keys. 119 * 120 * @since 4.5.0 121 * 122 * @param string $object_type The type of object. 123 * @param string $meta_key The meta key. 124 * @param string $object_subtype Optional. The subtype of the object type. 125 * 126 * @return bool|WP_Error True if successful. WP_Error if the meta key is invalid. 127 */ 128 function unregister_meta_key( $object_type, $meta_key, $object_subtype = 'all' ) { 129 if ( ! $this->registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 130 return new WP_Error( 'meta_key_is_not_registered', __( 'Meta key is not registered.' ) ); 131 } 132 133 unset( $this->{$object_type}[ $object_subtype ][ $meta_key ] ); 134 135 return true; 136 } 137 } -
src/wp-includes/default-filters.php
477 477 add_filter( 'oembed_dataparse', 'wp_filter_oembed_result', 10, 3 ); 478 478 add_filter( 'oembed_response_data', 'get_oembed_response_data_rich', 10, 4 ); 479 479 480 // Meta 481 add_action( 'plugins_loaded', '_wp_initialize_meta_manager', 0 ); 482 480 483 unset( $filter, $action ); -
src/wp-includes/meta.php
936 936 * Sanitize meta value. 937 937 * 938 938 * @since 3.1.3 939 * @since 4.5.0 Added the `$object_subtype` parameter. 939 940 * 940 941 * @param string $meta_key Meta key 941 942 * @param mixed $meta_value Meta value to sanitize 942 * @param string $meta_type Type of meta 943 * @param string $object_type Type of object the meta is registered to. 944 * @param string $object_subtype Optional. Subtype of object. Will inherit the object type by default. 945 * 943 946 * @return mixed Sanitized $meta_value 944 947 */ 945 function sanitize_meta( $meta_key, $meta_value, $meta_type ) { 946 948 function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype = 'all' ) { 947 949 /** 948 950 * Filter the sanitization of a specific meta key of a specific meta type. 949 951 * … … 958 960 * @param string $meta_key Meta key. 959 961 * @param string $meta_type Meta type. 960 962 */ 961 return apply_filters( "sanitize_{$meta_type}_meta_{$meta_key}", $meta_value, $meta_key, $meta_type ); 963 $meta_value = apply_filters( "sanitize_{$object_type}_meta_{$meta_key}", $meta_value, $meta_key, $object_type ); 964 965 /** 966 * Filter the sanitization of a specific meta key of a specific meta object type and subtype. 967 * 968 * The dynamic portions of the hook name, `$object_type`, `$object_subtype`, and `$meta_key` 969 * refer to the metadata object type (comment, post, or user), the subtype of that object type 970 * and the meta key value respectively. 971 * 972 * @since 4.5.0 973 * 974 * @param mixed $meta_value Meta value to sanitize. 975 * @param string $meta_key Meta key. 976 * @param string $object_type Meta type. 977 * @param string $object_subtype Subtype of the object type. 978 */ 979 return apply_filters( "sanitize_{$object_type}_{$object_subtype}_meta_{$meta_key}", $meta_value, $meta_key, $object_type, $object_subtype ); 962 980 } 963 981 964 982 /** 965 * Register meta key983 * Register a meta key. 966 984 * 985 * @todo should we wrap `register_meta()` with `register_meta_key()` to be more explicit? 986 * 967 987 * @since 3.3.0 988 * @since 4.5.0 Modified to support an array of data to attach to registered meta keys. Previous arguments for 989 * `$sanitize_callback` and `$auth_callback` have been folded into this array. 968 990 * 969 * @param string $meta_type Type of meta 970 * @param string $meta_key Meta key 971 * @param string|array $sanitize_callback A function or method to call when sanitizing the value of $meta_key. 972 * @param string|array $auth_callback Optional. A function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks. 991 * @param string $object_type Type of object this meta is registered to. 992 * @param string $meta_key Meta key to register. 993 * @param array $args { 994 * Data used to describe the meta key when registered. 995 * 996 * @type string $sanitize_callback A function or method to call when sanitizing `$meta_key` data. 997 * @type string $auth_callback Optional. A function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks. 998 * @type bool $show_in_rest Whether data associated with this meta key can be considered public. 999 * @type string $type The type of data associated with this meta key. 1000 * @type string $description A description of the data attached to this meta key. 1001 * } 973 1002 */ 974 function register_meta( $ meta_type, $meta_key, $sanitize_callback, $auth_callback = null) {975 if ( is_callable( $sanitize_callback ) )976 add_filter( "sanitize_{$meta_type}_meta_{$meta_key}", $sanitize_callback, 10, 3 );1003 function register_meta( $object_type, $meta_key, $args ) { 1004 global $wp_meta_manager; 1005 // @todo validate object type as post, comment, user, term? 977 1006 978 if ( empty( $auth_callback ) ) { 979 if ( is_protected_meta( $meta_key, $meta_type ) ) 980 $auth_callback = '__return_false'; 981 else 982 $auth_callback = '__return_true'; 1007 // @todo should this be an object similar to post types? 1008 $args = array( 1009 'sanitize_callback' => null, 1010 'old_sanitize_callback' => null, 1011 'auth_callback' => null, 1012 'old_auth_callback' => null, 1013 'object_subtype' => '', 1014 'public' => false, 1015 'type' => 'string', 1016 'description' => '', 1017 ); 1018 1019 $passed_args = array_slice( func_get_args(), 2 ); 1020 1021 if ( is_callable( $passed_args[0] ) ) { 1022 $args['old_sanitize_callback'] = $passed_args[0]; 1023 } elseif ( isset( $passed_args[0]['sanitize_callback'] ) ) { 1024 $args['sanitize_callback'] = $passed_args[0]['sanitize_callback']; 983 1025 } 984 1026 985 if ( is_callable( $auth_callback ) ) 986 add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 ); 1027 if ( isset( $passed_args[1] ) && is_callable( $passed_args[1] ) ) { 1028 $args['old_auth_callback'] = $passed_args[1]; 1029 } elseif ( isset( $passed_args[0]['auth_callback'] ) ) { 1030 $args['auth_callback'] = $passed_args[0]['auth_callback']; 1031 } 1032 1033 // @todo is there more than one condition here? What if show_in_rest is true, but the 1034 // user fails authentication. No schema? 1035 if ( isset( $passed_args[0]['show_in_rest'] ) && $passed_args[0]['show_in_rest'] ) { 1036 $args['show_in_rest'] = true; 1037 } 1038 1039 if ( isset( $passed_args[0]['type'] ) ) { 1040 $args['type'] = $passed_args[0]['type']; 1041 } 1042 1043 if ( isset( $passed_args[0]['description'] ) ) { 1044 $args['description'] = $passed_args[0]['description']; 1045 } 1046 1047 // @todo validate object sub types to only those objects that support custom object types? 1048 if ( isset( $passed_args[0]['object_subtype'] ) ) { 1049 $object_subtype = $passed_args[0]['object_subtype']; 1050 } else { 1051 $object_subtype = 'all'; 1052 } 1053 1054 $wp_meta_manager->register( array( 1055 'object_type' => $object_type, 1056 'object_subtype' => $object_subtype, 1057 'key' => $meta_key, 1058 'public' => $args['public'], 1059 'json_data_type' => $args['type'], 1060 ) ); 1061 1062 // This legacy filter will fire for all subtypes of an object type. 1063 if ( is_callable( $args['old_sanitize_callback'] ) ) { 1064 add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['old_sanitize_callback'], 10, 3 ); 1065 } 1066 1067 if ( is_callable( $args['sanitize_callback'] ) ) { 1068 add_filter( "sanitize_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args['sanitize_callback'], 10, 4 ); 1069 } 1070 1071 // If neither new or legacy `auth_callback` is provided, fallback to `is_protected_meta()`. 1072 if ( empty( $args['auth_callback'] ) && empty( $args['old_auth_callback'] ) ) { 1073 if ( is_protected_meta( $meta_key, $object_type ) ) { 1074 $args['auth_callback'] = '__return_false'; 1075 } else { 1076 $args['auth_callback'] = '__return_true'; 1077 } 1078 } 1079 1080 // @todo the only core application of this filter is for the `post` object type. What about users, comments, terms? 1081 // The auth here is to edit or add meta, not to view. 1082 if ( is_callable( $args['old_auth_callback'] ) ) { 1083 add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['old_auth_callback'], 10, 6 ); 1084 } 1085 1086 // @todo sort above out before going further 1087 if ( is_callable( $args['auth_callback'] ) ) { 1088 add_filter( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args['auth_callback'], 10, 7 ); 1089 } 987 1090 } 1091 1092 /** 1093 * Check if a meta key is registered. 1094 * 1095 * @since 4.5.0 1096 * 1097 * @param string $object_type 1098 * @param string $meta_key 1099 * @param string $object_subtype 1100 * 1101 * @return bool True if the meta key is registered to the object type and subtype. False if not. 1102 */ 1103 function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = 'all' ) { 1104 global $wp_meta_manager; 1105 return $wp_meta_manager->registered_meta_key_exists( $object_type, $meta_key, $object_subtype ); 1106 } 1107 1108 /** 1109 * Unregister a meta key from the list of registered keys. 1110 * 1111 * @since 4.5.0 1112 * 1113 * @param string $object_type The type of object. 1114 * @param string $meta_key The meta key. 1115 * @param string $object_subtype Optional. The subtype of the object type. 1116 * 1117 * @return bool|WP_Error True if successful. WP_Error if the meta key is invalid. 1118 */ 1119 function unregister_meta_key( $object_type, $meta_key, $object_subtype = 'all' ) { 1120 global $wp_meta_manager; 1121 return $wp_meta_manager->unregister_meta_key( $object_type, $meta_key, $object_subtype ); 1122 } 1123 1124 /** 1125 * Retrieve registered metadata for a specified object. 1126 * 1127 * @since 4.5.0 1128 * 1129 * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user) 1130 * @param int $object_id ID of the object the metadata is for. 1131 * @param string $meta_key Optional. Registered metadata key. If not specified, retrieve all registered 1132 * metadata for the specified object. 1133 * @param bool $single Optional. If true, return only the first value associated 1134 * with the specified meta key. If false, return an array of values. Default false. 1135 * @param string $object_subtype The subtype of the object's type to request metadata for. (e.g. custom post type) 1136 * 1137 * @return mixed|WP_Error 1138 */ 1139 function get_registered_metadata( $object_type = 'post', $object_id, $meta_key = '', $single = false, $object_subtype = 'all' ) { 1140 global $wp_meta_manager; 1141 if ( ! empty( $meta_key ) && ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 1142 return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered.' ) ); 1143 } 1144 1145 if ( 'post' === $object_type && $object_subtype !== get_post_type( $object_id ) ) { 1146 return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered for this subtype.' ) ); 1147 } 1148 1149 $data = get_metadata( $object_type, $object_id, $meta_key, $single ); 1150 1151 // If a meta key was specified, return the value associated with that key. 1152 if ( ! empty( $meta_key ) ) { 1153 return $data; 1154 } 1155 1156 $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); 1157 $registered_data = array(); 1158 1159 foreach( $meta_keys as $k => $v ) { 1160 if ( isset( $data[ $k ] ) ) { 1161 $registered_data[ $k ] = $data[ $k ]; 1162 } 1163 } 1164 1165 return $registered_data; 1166 } 1167 1168 1169 function _wp_initialize_meta_manager() { 1170 if ( empty( $GLOBALS['wp_meta_manager'] ) ) { 1171 $GLOBALS['wp_meta_manager'] = new WP_Meta_Manager(); 1172 } 1173 } -
src/wp-settings.php
133 133 require( ABSPATH . WPINC . '/user.php' ); 134 134 require( ABSPATH . WPINC . '/class-wp-user-query.php' ); 135 135 require( ABSPATH . WPINC . '/session.php' ); 136 require( ABSPATH . WPINC . '/class-wp-meta-manager.php' ); 136 137 require( ABSPATH . WPINC . '/meta.php' ); 137 138 require( ABSPATH . WPINC . '/class-wp-meta-query.php' ); 138 139 require( ABSPATH . WPINC . '/class-wp-metadata-lazyloader.php' ); -
tests/phpunit/tests/meta/registerMeta.php
1 <?php 2 3 /** 4 * @group meta 5 */ 6 class Tests_Meta_Register_Meta extends WP_UnitTestCase { 7 protected static $editor_id; 8 protected static $post_id; 9 protected static $comment_id; 10 11 public static function wpSetUpBeforeClass( $factory ) { 12 self::$editor_id = $factory->user->create( array( 'role' => 'editor' ) ); 13 self::$post_id = $factory->post->create(); 14 self::$comment_id = $factory->comment->create( array( 'comment_post_ID' => self::$post_id ) ); 15 } 16 17 public static function wpTearDownAfterClass() { 18 self::delete_user( self::$editor_id ); 19 wp_delete_comment( self::$comment_id, true ); 20 wp_delete_post( self::$post_id, true ); 21 } 22 23 function setUp() { 24 parent::setUp(); 25 wp_set_current_user( self::$editor_id ); 26 } 27 28 public function _old_sanitize_meta_cb( $meta_value, $meta_key, $meta_type ) { 29 return $meta_key . ' sanitized'; 30 } 31 32 public function _new_sanitize_meta_cb( $meta_value, $meta_key, $object_type, $object_subtype ) { 33 return $meta_key . ' sanitized'; 34 } 35 36 public function test_register_meta_with_sanitize_callback_registers_meta_key() { 37 $x = register_meta( 'post', 'flight_number', array( 'sanitize_callback' => 'esc_html', 'type' => 'string', 'description' => 'A flight number' ) ); 38 $this->assertTrue( registered_meta_key_exists( 'post', 'flight_number' ) ); 39 } 40 41 42 public function test_register_meta_without_sanitize_callback_registers_meta_key() { 43 register_meta( 'post', 'tail_number', array( 'type' => 'string', 'description' => 'A tail number' ) ); 44 $this->assertTrue( registered_meta_key_exists( 'post', 'tail_number' ) ); 45 } 46 47 public function test_register_meta_valid_object_type_parameter() { 48 register_meta( 'post', 'longitude', array( 'object_subtype' => 'post' ) ); 49 $this->assertTrue( registered_meta_key_exists( 'post', 'longitude', 'post' ) ); 50 } 51 52 public function test_register_meta_valid_object_type_does_not_match_invalid_subtype() { 53 register_meta( 'post', 'latitude', array( 'object_subtype' => 'invalid-type' ) ); 54 $this->assertFalse( registered_meta_key_exists( 'post', 'latitude' ) ); 55 } 56 57 public function test_register_meta_with_old_sanitize_callback_parameter() { 58 register_meta( 'post', 'old_sanitized_key', array( $this, '_old_sanitize_meta_cb' ) ); 59 $meta = sanitize_meta( 'old_sanitized_key', 'unsanitized', 'post' ); 60 61 $this->assertEquals( 'old_sanitized_key sanitized', $meta ); 62 } 63 64 public function test_register_meta_with_new_sanitize_callback_parameter() { 65 register_meta( 'post', 'new_sanitized_key', array( 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) ); 66 $meta = sanitize_meta( 'new_sanitized_key', 'unsanitized', 'post' ); 67 68 $this->assertEquals( 'new_sanitized_key sanitized', $meta ); 69 } 70 }