Ticket #35658: 35658.3.diff
File 35658.3.diff, 20.0 KB (added by , 8 years ago) |
---|
-
src/wp-includes/class-wp-meta-manager.php
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 * Registered meta of the post meta type (including pages and CPTs). 11 * 12 * @since 4.6.0 13 * @access private 14 * @var array 15 */ 16 private $post = array( 17 'all' => array() 18 ); 19 20 /** 21 * Registered meta of the taxonomy meta type. 22 * 23 * @since 4.6.0 24 * @access private 25 * @var array 26 */ 27 private $taxonomy = array( 28 'all' => array() 29 ); 30 31 /** 32 * Registered meta of the user meta type. 33 * 34 * @since 4.6.0 35 * @access private 36 * @var array 37 */ 38 private $user = array( 39 'all' => array() 40 ); 41 42 /** 43 * Registered meta of the comment meta type. 44 * 45 * @since 4.6.0 46 * @access private 47 * @var array 48 */ 49 private $comment = array( 50 'all' => array() 51 ); 52 53 /** 54 * @since 4.6.0 55 */ 56 function __construct() { 57 $post_types_without_meta = array( 'revision', 'nav_menu_item' ); 58 foreach ( get_post_types( null, 'names' ) as $post_type ) { 59 if ( in_array( $post_type, $post_types_without_meta ) ) { 60 continue; 61 } 62 $this->post[$post_type] = array(); 63 } 64 65 foreach ( get_taxonomies() as $taxonomy ) { 66 $this->taxonomy[$taxonomy] = array(); 67 } 68 69 foreach ( array( 'comment', 'ping' ) as $comment_type ) { 70 $this->comment[$comment_type] = array(); 71 } 72 } 73 74 /** 75 * Register a meta key. 76 * 77 * @since 4.6.0 78 * 79 * @param array $query { 80 * Array of meta data properties. 81 * 82 * @type string $object_type The meta type this key belongs to, e.g. `post`. 83 * @type string $object_subtype The meta subtype this key belongs to, e.g. `page`. 84 * @type string $key The meta key. 85 * @type array $schema The meta field's schema, according to JSON schema. 86 * @type array $public Whether the meta key should be publicly queryable. 87 * @return true|WP_Error 88 */ 89 public function register( $args ) { 90 if ( empty( $args['object_type'] ) ) { 91 return new WP_Error( 'missing_object_type', __( 'The object type is required to register meta.' ) ); 92 } 93 if ( ! property_exists( $this, $args['object_type'] ) ) { 94 return new WP_Error( 'object_type_does_not_exist', __( sprintf( 'The object type "%s" does not exist.', esc_html( $args['object_type'] ) ) ) ); 95 } 96 if ( ! empty( $args['object_subtype'] ) && ! isset( $this->{$args['object_type']}[$args['object_subtype'] ] ) ) { 97 return new WP_Error( 'meta_subtype_does_not_exist', __( 'The meta subtype does not exist in the registry.' ) ); 98 } 99 100 if ( empty( $args['key'] ) ) { 101 return new WP_Error( 'meta_key_required', __( 'The meta key is required.' ) ); 102 } 103 104 if ( ! isset( $args['schema'] ) ) { 105 return new WP_Error( 'schema_required', __( 'The JSON schema for the meta key is required.' ) ); 106 } 107 108 if ( ! isset( $args['public'] ) ) { 109 return new WP_Error( 'public_required', __( 'The public argument is required to register meta.' ) ); 110 } 111 112 if ( empty( $args['object_subtype'] ) ) { 113 $args['object_subtype'] = 'all'; 114 } 115 116 $this->{$args['object_type']}[$args['object_subtype']][$args['key']] = array( 117 'public' => $args['public'], 118 'schema' => $args['schema'], 119 ); 120 121 return true; 122 } 123 124 /** 125 * Retrieve a list of registered meta keys for an object type and subtype. 126 * 127 * @since 4.6.0 128 * 129 * @param string $object_type The type of object. Post, comment, user, term. 130 * @param string $object_subtype A subtype of the object. 131 * 132 * @return array List of registered meta keys. 133 */ 134 public function get_registered_meta_keys( $object_type = 'post', $object_subtype = 'all' ) { 135 if ( ! property_exists( $this, $object_type ) ) { 136 return array(); 137 } 138 139 if ( ! isset( $this->{$object_type}[ $object_subtype ] ) ) { 140 return array(); 141 } 142 143 return $this->{$object_type}[ $object_subtype ]; 144 } 145 146 /** 147 * Check if a meta key is registered. 148 * 149 * @since 4.6.0 150 * 151 * @param string $object_type 152 * @param string $meta_key 153 * @param string $object_subtype 154 * 155 * @return bool True if the meta key is registered to the object type and subtype. False if not. 156 */ 157 public function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = 'all' ) { 158 if ( ! property_exists( $this, $object_type ) ) { 159 return false; 160 } 161 162 if ( ! isset( $this->{$object_type}[ $object_subtype ] ) ) { 163 return false; 164 } 165 166 if ( ! isset( $this->{$object_type}[ $object_subtype ][ $meta_key ] ) ) { 167 return false; 168 } 169 170 return true; 171 } 172 173 /** 174 * Unregister a meta key from the list of registered keys. 175 * 176 * @since 4.6.0 177 * 178 * @param string $object_type The type of object. 179 * @param string $meta_key The meta key. 180 * @param string $object_subtype Optional. The subtype of the object type. 181 * 182 * @return bool|WP_Error True if successful. WP_Error if the meta key is invalid. 183 */ 184 public function unregister_meta_key( $object_type, $meta_key, $object_subtype = 'all' ) { 185 if ( ! $this->registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 186 return new WP_Error( 'meta_key_is_not_registered', __( 'Meta key is not registered.' ) ); 187 } 188 189 unset( $this->{$object_type}[ $object_subtype ][ $meta_key ] ); 190 191 return true; 192 } 193 } -
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.6.0 Added the `$object_subtype` parameter. 939 940 * 940 * @param string $meta_key Meta key 941 * @param mixed $meta_value Meta value to sanitize 942 * @param string $meta_type Type of meta 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. 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.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. 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, 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 ) { 1005 global $wp_meta_manager; 1006 // @todo validate object type as post, comment, user, term? 977 1007 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'; 1008 // @todo should this be an object similar to post types? 1009 $args = array( 1010 'sanitize_callback' => null, 1011 'old_sanitize_callback' => null, 1012 'auth_callback' => null, 1013 'old_auth_callback' => null, 1014 'object_subtype' => '', 1015 'public' => false, 1016 'schema' => false, 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 $error = $wp_meta_manager->register( array( 1055 'object_type' => $object_type, 1056 'object_subtype' => $object_subtype, 1057 'key' => $meta_key, 1058 'public' => $args['public'], 1059 'schema' => $args['schema'], 1060 ) ); 1061 1062 if ( is_wp_error( $error ) ) { 1063 return $error; 1064 } 1065 1066 // This legacy filter will fire for all subtypes of an object type. 1067 if ( is_callable( $args['old_sanitize_callback'] ) ) { 1068 add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args['old_sanitize_callback'], 10, 3 ); 1069 } 1070 1071 if ( is_callable( $args['sanitize_callback'] ) ) { 1072 add_filter( "sanitize_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args['sanitize_callback'], 10, 4 ); 1073 } 1074 1075 // If neither new or legacy `auth_callback` is provided, fallback to `is_protected_meta()`. 1076 if ( empty( $args['auth_callback'] ) && empty( $args['old_auth_callback'] ) ) { 1077 if ( is_protected_meta( $meta_key, $object_type ) ) { 1078 $args['auth_callback'] = '__return_false'; 1079 } else { 1080 $args['auth_callback'] = '__return_true'; 1081 } 1082 } 1083 1084 // @todo the only core application of this filter is for the `post` object type. What about users, comments, terms? 1085 // The auth here is to edit or add meta, not to view. 1086 if ( is_callable( $args['old_auth_callback'] ) ) { 1087 add_filter( "auth_{$object_type}_meta_{$meta_key}", $args['old_auth_callback'], 10, 6 ); 1088 } 1089 1090 // @todo sort above out before going further 1091 if ( is_callable( $args['auth_callback'] ) ) { 1092 add_filter( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args['auth_callback'], 10, 7 ); 1093 } 1094 1095 return true; 987 1096 } 1097 1098 /** 1099 * Check if a meta key is registered. 1100 * 1101 * @since 4.6.0 1102 * 1103 * @param string $object_type 1104 * @param string $meta_key 1105 * @param string $object_subtype 1106 * 1107 * @return bool True if the meta key is registered to the object type and subtype. False if not. 1108 */ 1109 function registered_meta_key_exists( $object_type, $meta_key, $object_subtype = 'all' ) { 1110 global $wp_meta_manager; 1111 return $wp_meta_manager->registered_meta_key_exists( $object_type, $meta_key, $object_subtype ); 1112 } 1113 1114 /** 1115 * Unregister a meta key from the list of registered keys. 1116 * 1117 * @since 4.6.0 1118 * 1119 * @param string $object_type The type of object. 1120 * @param string $meta_key The meta key. 1121 * @param string $object_subtype Optional. The subtype of the object type. 1122 * 1123 * @return bool|WP_Error True if successful. WP_Error if the meta key is invalid. 1124 */ 1125 function unregister_meta_key( $object_type, $meta_key, $object_subtype = 'all' ) { 1126 global $wp_meta_manager; 1127 return $wp_meta_manager->unregister_meta_key( $object_type, $meta_key, $object_subtype ); 1128 } 1129 1130 /** 1131 * Retrieve registered metadata for a specified object. 1132 * 1133 * @since 4.6.0 1134 * 1135 * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user) 1136 * @param int $object_id ID of the object the metadata is for. 1137 * @param string $meta_key Optional. Registered metadata key. If not specified, retrieve all registered 1138 * metadata for the specified object. 1139 * @param bool $single Optional. If true, return only the first value associated 1140 * with the specified meta key. If false, return an array of values. Default false. 1141 * @param string $object_subtype The subtype of the object's type to request metadata for. (e.g. custom post type) 1142 * 1143 * @return mixed|WP_Error 1144 */ 1145 function get_registered_metadata( $object_type = 'post', $object_id, $meta_key = '', $single = false, $object_subtype = 'all' ) { 1146 global $wp_meta_manager; 1147 if ( ! empty( $meta_key ) && ! registered_meta_key_exists( $object_type, $meta_key, $object_subtype ) ) { 1148 return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered.' ) ); 1149 } 1150 1151 if ( 'post' === $object_type && $object_subtype !== get_post_type( $object_id ) ) { 1152 return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered for this subtype.' ) ); 1153 } 1154 1155 $data = get_metadata( $object_type, $object_id, $meta_key, $single ); 1156 1157 // If a meta key was specified, return the value associated with that key. 1158 if ( ! empty( $meta_key ) ) { 1159 return $data; 1160 } 1161 1162 $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); 1163 $registered_data = array(); 1164 1165 foreach( $meta_keys as $k => $v ) { 1166 if ( isset( $data[ $k ] ) ) { 1167 $registered_data[ $k ] = $data[ $k ]; 1168 } 1169 } 1170 1171 return $registered_data; 1172 } 1173 1174 1175 function _wp_initialize_meta_manager() { 1176 if ( empty( $GLOBALS['wp_meta_manager'] ) ) { 1177 $GLOBALS['wp_meta_manager'] = new WP_Meta_Manager(); 1178 } 1179 } -
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_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 }