Ticket #35658: 35658-objects.3.diff
File 35658-objects.3.diff, 20.0 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..d5e1ca5
- + 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 $protected Whether the meta key can be publicly queryable. 91 * @return true|WP_Error 92 */ 93 public function register( $args ) { 94 95 $defaults = array( 96 'object_type' => null, 97 'object_subtype' => null, 98 'key' => null, 99 'protected' => true, 100 'show_in_rest' => false, 101 'sanitize_callback' => null, 102 'old_sanitize_callback' => null, 103 'auth_callback' => null, 104 'old_auth_callback' => null, 105 ); 106 107 if ( is_array( $args ) ) { 108 // Merge passed $args array with defaults 109 $args = array_merge( $defaults, $args ); 110 } elseif ( ! is_object( $args ) ) { 111 // No $args passed, use defaults 112 $args = $defaults; 113 } 114 115 // Force object 116 if ( ! is_object( $args ) ) { 117 $args = (object) $args; 118 } 119 120 // @todo validate object sub types to only those objects that support custom object types? 121 if ( empty( $args->object_subtype ) ) { 122 $args->object_subtype = 'all'; 123 } 124 125 // @todo validate object type as post, comment, user, term? 126 127 if ( empty( $args->object_type ) ) { 128 return new WP_Error( 'missing_object_type', __( 'The object type is required to register meta.' ) ); 129 } 130 131 if ( ! property_exists( $this, $args->object_type ) ) { 132 return new WP_Error( 'object_type_does_not_exist', __( sprintf( 'The object type "%s" does not exist.', esc_html( $args['object_type'] ) ) ) ); 133 } 134 135 // @todo This may not be necessary, what if post types are registered later? 136 if ( ! empty( $args->object_subtype ) && ! isset( $this->{$args->object_type}[ $args->object_subtype ] ) ) { 137 return new WP_Error( 'meta_subtype_does_not_exist', __( 'The meta subtype does not exist in the registry.' ) ); 138 } 139 140 if ( empty( $args->key ) ) { 141 return new WP_Error( 'meta_key_required', __( 'The meta key is required.' ) ); 142 } 143 144 if ( ! isset( $args->protected ) ) { 145 return new WP_Error( 'protected_required', __( 'The protected argument is required to register meta.' ) ); 146 } 147 148 if ( empty( $args->object_subtype ) ) { 149 $args->object_subtype = 'all'; 150 } 151 152 // If neither new or legacy `auth_callback` is provided, fallback to `is_protected_meta()`. 153 if ( empty( $args->auth_callback ) && empty( $args->old_auth_callback ) ) { 154 if ( is_protected_meta( $args->key, $args->object_type ) ) { 155 $args->auth_callback = '__return_false'; 156 } else { 157 $args->auth_callback = '__return_true'; 158 } 159 } 160 161 $this->setup_hooks( $args ); 162 163 $this->{$args->object_type}[ $args->object_subtype ][ $args->key ] = $args; 164 165 return true; 166 167 } 168 169 /** 170 * Setup hooks for sanitize and authentication checks 171 * 172 * @param object $args 173 */ 174 private function setup_hooks( $args ) { 175 176 $object_type = $args->object_type; 177 $object_subtype = $args->object_subtype; 178 $meta_key = $args->key; 179 180 // This legacy filter will fire for all subtypes of an object type. 181 if ( is_callable( $args->old_sanitize_callback ) ) { 182 add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args->old_sanitize_callback, 10, 3 ); 183 } 184 185 if ( is_callable( $args->sanitize_callback ) ) { 186 add_filter( "sanitize_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args->sanitize_callback, 10, 4 ); 187 } 188 189 // @todo the only core application of this filter is for the `post` object type. What about users, comments, terms? 190 // The auth here is to edit or add meta, not to view. 191 if ( is_callable( $args->old_auth_callback ) ) { 192 add_filter( "auth_{$object_type}_meta_{$meta_key}", $args->old_auth_callback, 10, 6 ); 193 } 194 195 // @todo sort above out before going further 196 if ( is_callable( $args->auth_callback ) ) { 197 add_filter( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args->auth_callback, 10, 7 ); 198 } 199 200 } 201 202 /** 203 * Retrieve a list of registered meta keys for an object type and subtype. 204 * 205 * @since 4.6.0 206 * 207 * @param string $object_type The type of object. Post, comment, user, term. 208 * @param string $object_subtype A subtype of the object. 209 * 210 * @return array List of registered meta keys. 211 */ 212 public function get_registered_meta_keys( $object_type = 'post', $object_subtype = 'all' ) { 213 214 if ( ! property_exists( $this, $object_type ) ) { 215 return array(); 216 } 217 218 if ( ! isset( $this->{$object_type}[ $object_subtype ] ) ) { 219 return array(); 220 } 221 222 return $this->{$object_type}[ $object_subtype ]; 223 224 } 225 226 /** 227 * Check if a meta key is registered. 228 * 229 * @since 4.6.0 230 * 231 * @param string $object_type 232 * @param string $meta_key 233 * @param string $object_subtype 234 * 235 * @return bool True if the meta key is registered to the object type and subtype. False if not. 236 */ 237 public function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = 'all' ) { 238 239 if ( ! property_exists( $this, $object_type ) ) { 240 return false; 241 } 242 243 if ( ! isset( $this->{$object_type}[ $object_subtype ] ) ) { 244 return false; 245 } 246 247 if ( ! isset( $this->{$object_type}[ $object_subtype ][ $meta_key ] ) ) { 248 return false; 249 } 250 251 return true; 252 253 } 254 255 /** 256 * Unregister a meta key from the list of registered keys. 257 * 258 * @since 4.6.0 259 * 260 * @param string $object_type The type of object. 261 * @param string $meta_key The meta key. 262 * @param string $object_subtype Optional. The subtype of the object type. 263 * 264 * @return bool|WP_Error True if successful. WP_Error if the meta key is invalid. 265 */ 266 public function unregister_meta_key( $object_type, $meta_key, $object_subtype = 'all' ) { 267 268 if ( ! $this->registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 269 return new WP_Error( 'meta_key_is_not_registered', __( 'Meta key is not registered.' ) ); 270 } 271 272 unset( $this->{$object_type}[ $object_subtype ][ $meta_key ] ); 273 274 return true; 275 276 } 277 278 } -
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..7e40bd3 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 $protected Whether data associated with this meta key can be considered protected. 1000 * } 1001 * @return true|WP_Error 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 ) { 977 1004 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'; 1005 global $wp_meta_manager; 1006 1007 $defaults = array( 1008 'object_type' => $object_type, 1009 'key' => $meta_key, 1010 ); 1011 1012 $passed_args = func_get_args(); 1013 1014 // Backwards compatibility for sanitize_callback 1015 if ( is_callable( $passed_args[2] ) ) { 1016 // Handle the old sanitize_callback callable argument 1017 $defaults['old_sanitize_callback'] = $passed_args[2]; 1018 1019 // No args passed 1020 $args = array(); 983 1021 } 984 1022 985 if ( is_callable( $auth_callback ) ) 986 add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 ); 1023 // Backwards compatibility for auth_callback 1024 if ( isset( $passed_args[3] ) && is_callable( $passed_args[3] ) ) { 1025 $defaults['old_auth_callback'] = $passed_args[3]; 1026 } 1027 1028 if ( $args && is_array( $args ) ) { 1029 // Merge passed $args array with defaults 1030 $args = array_merge( $defaults, $args ); 1031 } else { 1032 // No $args passed, use defaults 1033 $args = $defaults; 1034 } 1035 1036 return $wp_meta_manager->register( $args ); 1037 1038 } 1039 1040 /** 1041 * Check if a meta key is registered. 1042 * 1043 * @since 4.6.0 1044 * 1045 * @param string $object_type 1046 * @param string $meta_key 1047 * @param string $object_subtype 1048 * 1049 * @return bool True if the meta key is registered to the object type and subtype. False if not. 1050 */ 1051 function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = 'all' ) { 1052 global $wp_meta_manager; 1053 return $wp_meta_manager->registered_meta_key_exists( $object_type, $meta_key, $object_subtype ); 1054 } 1055 1056 /** 1057 * Unregister a meta key from the list of registered keys. 1058 * 1059 * @since 4.6.0 1060 * 1061 * @param string $object_type The type of object. 1062 * @param string $meta_key The meta key. 1063 * @param string $object_subtype Optional. The subtype of the object type. 1064 * 1065 * @return bool|WP_Error True if successful. WP_Error if the meta key is invalid. 1066 */ 1067 function unregister_meta_key( $object_type, $meta_key, $object_subtype = 'all' ) { 1068 global $wp_meta_manager; 1069 return $wp_meta_manager->unregister_meta_key( $object_type, $meta_key, $object_subtype ); 1070 } 1071 1072 /** 1073 * Retrieve registered metadata for a specified object. 1074 * 1075 * @since 4.6.0 1076 * 1077 * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user) 1078 * @param int $object_id ID of the object the metadata is for. 1079 * @param string $meta_key Optional. Registered metadata key. If not specified, retrieve all registered 1080 * metadata for the specified object. 1081 * @param bool $single Optional. If true, return only the first value associated 1082 * with the specified meta key. If false, return an array of values. Default false. 1083 * @param string $object_subtype The subtype of the object's type to request metadata for. (e.g. custom post type) 1084 * 1085 * @return mixed|WP_Error 1086 */ 1087 function get_registered_metadata( $object_type = 'post', $object_id, $meta_key = '', $single = false, $object_subtype = 'all' ) { 1088 global $wp_meta_manager; 1089 if ( ! empty( $meta_key ) && ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 1090 return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered.' ) ); 1091 } 1092 1093 if ( 'post' === $object_type && $object_subtype !== get_post_type( $object_id ) ) { 1094 return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered for this subtype.' ) ); 1095 } 1096 1097 $data = get_metadata( $object_type, $object_id, $meta_key, $single ); 1098 1099 // If a meta key was specified, return the value associated with that key. 1100 if ( ! empty( $meta_key ) ) { 1101 return $data; 1102 } 1103 1104 $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); 1105 $registered_data = array(); 1106 1107 foreach( $meta_keys as $k => $v ) { 1108 if ( isset( $data[ $k ] ) ) { 1109 $registered_data[ $k ] = $data[ $k ]; 1110 } 1111 } 1112 1113 return $registered_data; 1114 } 1115 1116 1117 function _wp_initialize_meta_manager() { 1118 if ( empty( $GLOBALS['wp_meta_manager'] ) ) { 1119 $GLOBALS['wp_meta_manager'] = new WP_Meta_Manager(); 1120 } 987 1121 } -
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 }