Ticket #35658: 35658-objects.diff
File 35658-objects.diff, 20.4 KB (added by , 8 years ago) |
---|
-
new file src/wp-includes/class-wp-meta-manager.php
diff --git a/src/wp-includes/class-wp-meta-manager.php b/src/wp-includes/class-wp-meta-manager.php new file mode 100644 index 0000000..b5f33d9
- + 1 <?php 2 /** 3 * A registry for meta data. 4 * 5 * @package WordPress 6 * @since 4.6.0 7 */ 8 final class WP_Meta_Manager { 9 10 /** 11 * Registered meta of the post meta type (including pages and CPTs). 12 * 13 * @since 4.6.0 14 * @access private 15 * @var array 16 */ 17 private $post = array( 18 'all' => array() 19 ); 20 21 /** 22 * Registered meta of the taxonomy meta type. 23 * 24 * @since 4.6.0 25 * @access private 26 * @var array 27 */ 28 private $taxonomy = array( 29 'all' => array() 30 ); 31 32 /** 33 * Registered meta of the user meta type. 34 * 35 * @since 4.6.0 36 * @access private 37 * @var array 38 */ 39 private $user = array( 40 'all' => array() 41 ); 42 43 /** 44 * Registered meta of the comment meta type. 45 * 46 * @since 4.6.0 47 * @access private 48 * @var array 49 */ 50 private $comment = array( 51 'all' => array() 52 ); 53 54 /** 55 * @since 4.6.0 56 */ 57 public function __construct() { 58 59 $post_types_without_meta = array( 'revision', 'nav_menu_item' ); 60 61 foreach ( get_post_types( null, 'names' ) as $post_type ) { 62 if ( in_array( $post_type, $post_types_without_meta ) ) { 63 continue; 64 } 65 66 $this->post[ $post_type ] = array(); 67 } 68 69 foreach ( get_taxonomies() as $taxonomy ) { 70 $this->taxonomy[ $taxonomy ] = array(); 71 } 72 73 foreach ( array( 'comment', 'ping' ) as $comment_type ) { 74 $this->comment[ $comment_type ] = array(); 75 } 76 77 } 78 79 /** 80 * Register a meta key. 81 * 82 * @since 4.6.0 83 * 84 * @param array|object $query { 85 * Array or object of meta data properties. 86 * 87 * @type string $object_type The meta type this key belongs to, e.g. `post`. 88 * @type string $object_subtype The meta subtype this key belongs to, e.g. `page`. 89 * @type string $key The meta key. 90 * @type array $schema The meta field's schema, according to JSON schema. 91 * @type array $public Whether the meta key should be publicly queryable. 92 * @return true|WP_Error 93 */ 94 public function register( $args ) { 95 96 $defaults = array( 97 'object_type' => null, 98 'object_subtype' => null, 99 'key' => null, 100 'schema' => false, 101 'public' => false, 102 'show_in_rest' => false, 103 'sanitize_callback' => null, 104 'old_sanitize_callback' => null, 105 'auth_callback' => null, 106 'old_auth_callback' => null, 107 ); 108 109 if ( is_array( $args ) ) { 110 // Merge passed $args array with defaults 111 $args = array_merge( $defaults, $args ); 112 } elseif ( ! is_object( $args ) ) { 113 // No $args passed, use defaults 114 $args = $defaults; 115 } 116 117 // Force object 118 if ( ! is_object( $args ) ) { 119 $args = (object) $args; 120 } 121 122 // @todo validate object sub types to only those objects that support custom object types? 123 if ( empty( $args->object_subtype ) ) { 124 $args->object_subtype = 'all'; 125 } 126 127 // @todo validate object type as post, comment, user, term? 128 129 if ( empty( $args->object_type ) ) { 130 return new WP_Error( 'missing_object_type', __( 'The object type is required to register meta.' ) ); 131 } 132 133 if ( ! property_exists( $this, $args->object_type ) ) { 134 return new WP_Error( 'object_type_does_not_exist', __( sprintf( 'The object type "%s" does not exist.', esc_html( $args['object_type'] ) ) ) ); 135 } 136 137 // @todo This may not be necessary, what if post types are registered later? 138 if ( ! empty( $args->object_subtype ) && ! isset( $this->{$args->object_type}[ $args->object_subtype ] ) ) { 139 return new WP_Error( 'meta_subtype_does_not_exist', __( 'The meta subtype does not exist in the registry.' ) ); 140 } 141 142 if ( empty( $args->key ) ) { 143 return new WP_Error( 'meta_key_required', __( 'The meta key is required.' ) ); 144 } 145 146 if ( ! isset( $args->schema ) ) { 147 return new WP_Error( 'schema_required', __( 'The JSON schema for the meta key is required.' ) ); 148 } 149 150 if ( ! isset( $args->public ) ) { 151 return new WP_Error( 'public_required', __( 'The public argument is required to register meta.' ) ); 152 } 153 154 if ( empty( $args->object_subtype ) ) { 155 $args->object_subtype = 'all'; 156 } 157 158 // If neither new or legacy `auth_callback` is provided, fallback to `is_protected_meta()`. 159 if ( empty( $args->auth_callback ) && empty( $args->old_auth_callback ) ) { 160 if ( is_protected_meta( $args->key, $args->object_type ) ) { 161 $args->auth_callback = '__return_false'; 162 } else { 163 $args->auth_callback = '__return_true'; 164 } 165 } 166 167 $this->setup_hooks( $args ); 168 169 $this->{$args->object_type}[ $args->object_subtype ][ $args->key ] = $args; 170 171 return true; 172 173 } 174 175 /** 176 * Setup hooks for sanitize and authentication checks 177 * 178 * @param object $args 179 */ 180 private function setup_hooks( $args ) { 181 182 $object_type = $args->object_type; 183 $object_subtype = $args->object_subtype; 184 $meta_key = $args->key; 185 186 // This legacy filter will fire for all subtypes of an object type. 187 if ( is_callable( $args->old_sanitize_callback ) ) { 188 add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args->old_sanitize_callback, 10, 3 ); 189 } 190 191 if ( is_callable( $args->sanitize_callback ) ) { 192 add_filter( "sanitize_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args->sanitize_callback, 10, 4 ); 193 } 194 195 // @todo the only core application of this filter is for the `post` object type. What about users, comments, terms? 196 // The auth here is to edit or add meta, not to view. 197 if ( is_callable( $args->old_auth_callback ) ) { 198 add_filter( "auth_{$object_type}_meta_{$meta_key}", $args->old_auth_callback, 10, 6 ); 199 } 200 201 // @todo sort above out before going further 202 if ( is_callable( $args->auth_callback ) ) { 203 add_filter( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args->auth_callback, 10, 7 ); 204 } 205 206 } 207 208 /** 209 * Retrieve a list of registered meta keys for an object type and subtype. 210 * 211 * @since 4.6.0 212 * 213 * @param string $object_type The type of object. Post, comment, user, term. 214 * @param string $object_subtype A subtype of the object. 215 * 216 * @return array List of registered meta keys. 217 */ 218 public function get_registered_meta_keys( $object_type = 'post', $object_subtype = 'all' ) { 219 220 if ( ! property_exists( $this, $object_type ) ) { 221 return array(); 222 } 223 224 if ( ! isset( $this->{$object_type}[ $object_subtype ] ) ) { 225 return array(); 226 } 227 228 return $this->{$object_type}[ $object_subtype ]; 229 230 } 231 232 /** 233 * Check if a meta key is registered. 234 * 235 * @since 4.6.0 236 * 237 * @param string $object_type 238 * @param string $meta_key 239 * @param string $object_subtype 240 * 241 * @return bool True if the meta key is registered to the object type and subtype. False if not. 242 */ 243 public function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = 'all' ) { 244 245 if ( ! property_exists( $this, $object_type ) ) { 246 return false; 247 } 248 249 if ( ! isset( $this->{$object_type}[ $object_subtype ] ) ) { 250 return false; 251 } 252 253 if ( ! isset( $this->{$object_type}[ $object_subtype ][ $meta_key ] ) ) { 254 return false; 255 } 256 257 return true; 258 259 } 260 261 /** 262 * Unregister a meta key from the list of registered keys. 263 * 264 * @since 4.6.0 265 * 266 * @param string $object_type The type of object. 267 * @param string $meta_key The meta key. 268 * @param string $object_subtype Optional. The subtype of the object type. 269 * 270 * @return bool|WP_Error True if successful. WP_Error if the meta key is invalid. 271 */ 272 public function unregister_meta_key( $object_type, $meta_key, $object_subtype = 'all' ) { 273 274 if ( ! $this->registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 275 return new WP_Error( 'meta_key_is_not_registered', __( 'Meta key is not registered.' ) ); 276 } 277 278 unset( $this->{$object_type}[ $object_subtype ][ $meta_key ] ); 279 280 return true; 281 282 } 283 284 } 285 No newline at end of file -
src/wp-includes/default-filters.php
diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index 2ae86d8..a38222d 100644
a b 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
diff --git a/src/wp-includes/meta.php b/src/wp-includes/meta.php index bfdd595..89063a7 100644
a b function is_protected_meta( $meta_key, $meta_type = null ) { 936 936 * Sanitize meta value. 937 937 * 938 938 * @since 3.1.3 939 * @since 4.6.0 Added the `$object_subtype` parameter. 940 * 941 * @param string $meta_key Meta key. 942 * @param mixed $meta_value Meta value to sanitize. 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. 939 945 * 940 * @param string $meta_key Meta key941 * @param mixed $meta_value Meta value to sanitize942 * @param string $meta_type Type of meta943 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 * … … function sanitize_meta( $meta_key, $meta_value, $meta_type ) { 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 key 983 * Register a meta key. 984 * 985 * @todo should we wrap `register_meta()` with `register_meta_key()` to be more explicit? 966 986 * 967 987 * @since 3.3.0 988 * @since 4.6.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. 990 * 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. 968 995 * 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. 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, 998 * add_post_meta, and delete_post_meta capability checks. 999 * @type bool $public Whether data associated with this meta key can be considered public. 1000 * @type array $schema The meta field's schema, according to JSON schema. 1001 * } 1002 * @return true|WP_Error 973 1003 */ 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 ); 1004 function register_meta( $object_type, $meta_key, $args ) { 977 1005 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'; 1006 global $wp_meta_manager; 1007 1008 $defaults = array( 1009 'object_type' => $object_type, 1010 'key' => $meta_key, 1011 ); 1012 1013 $passed_args = func_get_args(); 1014 1015 // Backwards compatibility for sanitize_callback 1016 if ( is_callable( $passed_args[2] ) ) { 1017 // Handle the old sanitize_callback callable argument 1018 $defaults['old_sanitize_callback'] = $passed_args[2]; 1019 1020 // No args passed 1021 $args = array(); 983 1022 } 984 1023 985 if ( is_callable( $auth_callback ) ) 986 add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 ); 1024 // Backwards compatibility for auth_callback 1025 if ( isset( $passed_args[3] ) && is_callable( $passed_args[3] ) ) { 1026 $defaults['old_auth_callback'] = $passed_args[3]; 1027 } 1028 1029 if ( $args && is_array( $args ) ) { 1030 // Merge passed $args array with defaults 1031 $args = array_merge( $defaults, $args ); 1032 } else { 1033 // No $args passed, use defaults 1034 $args = $defaults; 1035 } 1036 1037 return $wp_meta_manager->register( $args ); 1038 1039 } 1040 1041 /** 1042 * Check if a meta key is registered. 1043 * 1044 * @since 4.6.0 1045 * 1046 * @param string $object_type 1047 * @param string $meta_key 1048 * @param string $object_subtype 1049 * 1050 * @return bool True if the meta key is registered to the object type and subtype. False if not. 1051 */ 1052 function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = 'all' ) { 1053 global $wp_meta_manager; 1054 return $wp_meta_manager->registered_meta_key_exists( $object_type, $meta_key, $object_subtype ); 1055 } 1056 1057 /** 1058 * Unregister a meta key from the list of registered keys. 1059 * 1060 * @since 4.6.0 1061 * 1062 * @param string $object_type The type of object. 1063 * @param string $meta_key The meta key. 1064 * @param string $object_subtype Optional. The subtype of the object type. 1065 * 1066 * @return bool|WP_Error True if successful. WP_Error if the meta key is invalid. 1067 */ 1068 function unregister_meta_key( $object_type, $meta_key, $object_subtype = 'all' ) { 1069 global $wp_meta_manager; 1070 return $wp_meta_manager->unregister_meta_key( $object_type, $meta_key, $object_subtype ); 1071 } 1072 1073 /** 1074 * Retrieve registered metadata for a specified object. 1075 * 1076 * @since 4.6.0 1077 * 1078 * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user) 1079 * @param int $object_id ID of the object the metadata is for. 1080 * @param string $meta_key Optional. Registered metadata key. If not specified, retrieve all registered 1081 * metadata for the specified object. 1082 * @param bool $single Optional. If true, return only the first value associated 1083 * with the specified meta key. If false, return an array of values. Default false. 1084 * @param string $object_subtype The subtype of the object's type to request metadata for. (e.g. custom post type) 1085 * 1086 * @return mixed|WP_Error 1087 */ 1088 function get_registered_metadata( $object_type = 'post', $object_id, $meta_key = '', $single = false, $object_subtype = 'all' ) { 1089 global $wp_meta_manager; 1090 if ( ! empty( $meta_key ) && ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 1091 return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered.' ) ); 1092 } 1093 1094 if ( 'post' === $object_type && $object_subtype !== get_post_type( $object_id ) ) { 1095 return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered for this subtype.' ) ); 1096 } 1097 1098 $data = get_metadata( $object_type, $object_id, $meta_key, $single ); 1099 1100 // If a meta key was specified, return the value associated with that key. 1101 if ( ! empty( $meta_key ) ) { 1102 return $data; 1103 } 1104 1105 $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); 1106 $registered_data = array(); 1107 1108 foreach( $meta_keys as $k => $v ) { 1109 if ( isset( $data[ $k ] ) ) { 1110 $registered_data[ $k ] = $data[ $k ]; 1111 } 1112 } 1113 1114 return $registered_data; 1115 } 1116 1117 1118 function _wp_initialize_meta_manager() { 1119 if ( empty( $GLOBALS['wp_meta_manager'] ) ) { 1120 $GLOBALS['wp_meta_manager'] = new WP_Meta_Manager(); 1121 } 987 1122 } -
src/wp-settings.php
diff --git a/src/wp-settings.php b/src/wp-settings.php index a4bb370..768362a 100644
a b 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' ); -
new file tests/phpunit/tests/meta/registerMeta.php
diff --git a/tests/phpunit/tests/meta/registerMeta.php b/tests/phpunit/tests/meta/registerMeta.php new file mode 100644 index 0000000..1601041
- + 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_without_sanitize_callback_registers_meta_key() { 37 register_meta( 'post', 'flight_number', array() ); 38 $this->assertTrue( registered_meta_key_exists( 'post', 'flight_number' ) ); 39 } 40 41 public function test_register_meta_for_a_category() { 42 register_meta( 'taxonomy', 'category_icon', array( 'object_subtype' => 'category' ) ); 43 $this->assertTrue( registered_meta_key_exists( 'taxonomy', 'category_icon', 'category' ) ); 44 } 45 46 public function test_register_meta_for_a_comment() { 47 register_meta( 'comment', 'comment_rating', array( 'object_subtype' => 'comment' ) ); 48 $this->assertTrue( registered_meta_key_exists( 'comment', 'comment_rating', 'comment' ) ); 49 } 50 51 public function test_register_meta_with_sanitize_callback_registers_meta_key() { 52 register_meta( 'post', 'flight_number', array( 'sanitize_callback' => 'esc_html' ) ); 53 $this->assertTrue( registered_meta_key_exists( 'post', 'flight_number' ) ); 54 } 55 56 public function test_register_meta_valid_object_type_with_valid_subtype() { 57 register_meta( 'post', 'longitude', array( 'object_subtype' => 'post' ) ); 58 $this->assertTrue( registered_meta_key_exists( 'post', 'longitude', 'post' ) ); 59 } 60 61 public function test_register_meta_valid_object_type_with_invalid_subtype() { 62 register_meta( 'post', 'latitude', array( 'object_subtype' => 'invalid-type' ) ); 63 $this->assertFalse( registered_meta_key_exists( 'post', 'latitude', 'invalid-type' ) ); 64 } 65 66 public function test_register_meta_with_old_sanitize_callback_parameter() { 67 register_meta( 'post', 'old_sanitized_key', array( $this, '_old_sanitize_meta_cb' ) ); 68 $meta = sanitize_meta( 'old_sanitized_key', 'unsanitized', 'post' ); 69 70 $this->assertEquals( 'old_sanitized_key sanitized', $meta ); 71 } 72 73 public function test_register_meta_with_new_sanitize_callback_parameter() { 74 register_meta( 'post', 'new_sanitized_key', array( 'sanitize_callback' => array( $this, '_new_sanitize_meta_cb' ) ) ); 75 $meta = sanitize_meta( 'new_sanitized_key', 'unsanitized', 'post' ); 76 77 $this->assertEquals( 'new_sanitized_key sanitized', $meta ); 78 } 79 }