945 | | function sanitize_meta( $meta_key, $meta_value, $meta_type ) { |
| 948 | function sanitize_meta( $meta_key, $meta_value, $object_type, $object_subtype = '' ) { |
| 949 | if ( ! empty( $object_subtype ) ) { |
| 950 | /** |
| 951 | * Filters the sanitization of a specific meta key of a specific meta type and subtype. |
| 952 | * |
| 953 | * The dynamic portions of the hook name, `$meta_type`, `$meta_subtype`, |
| 954 | * and `$meta_key`, refer to the metadata object type (comment, post, or user) |
| 955 | * the object subtype, and the meta key value, respectively. |
| 956 | * |
| 957 | * @since 4.6.0 |
| 958 | * |
| 959 | * @param mixed $meta_value Meta value to sanitize. |
| 960 | * @param string $meta_key Meta key. |
| 961 | * @param string $object_type Object type. |
| 962 | * @param string $object_subtype Object subtype. |
| 963 | */ |
| 964 | $meta_value = apply_filters( "sanitize_{$object_type}_{$object_subtype}_meta_{$meta_key}", $meta_value, $meta_key, $object_type, $object_subtype ); |
| 965 | } |
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. |
| 994 | * @param string $object_type Type of object this meta is registered to. |
| 995 | * @param string $meta_key Meta key to register. |
| 996 | * @param array $args { |
| 997 | * Data used to describe the meta key when registered. |
| 998 | * |
| 999 | * @type string $sanitize_callback A function or method to call when sanitizing `$meta_key` data. |
| 1000 | * @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. |
| 1001 | * @type string $object_subtype A subtype; e.g. if the object type is "post", the post type. |
| 1002 | * @type string $type The type of data associated with this meta key. |
| 1003 | * @type string $description A description of the data attached to this meta key. |
| 1004 | * @type bool $show_in_rest Whether data associated with this meta key can be considered public. |
| 1005 | * |
| 1006 | * @return bool True if the meta key was successfully registered in the global array, false if not. |
| 1007 | * Registering a meta key with distinct sanitize and auth callbacks will fire those |
| 1008 | * callbacks, but will not add to the global registry as it requires a subtype. |
| 1009 | * } |
985 | | if ( is_callable( $auth_callback ) ) |
986 | | add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 ); |
| 1018 | if ( ! in_array( $object_type, array( 'post', 'comment', 'user', 'term' ) ) ) { |
| 1019 | _doing_it_wrong( __FUNCTION__, sprintf( __( 'Invalid object type: %s.' ), $object_type ), '4.6.0' ); |
| 1020 | } |
| 1021 | |
| 1022 | $defaults = array( |
| 1023 | 'sanitize_callback' => null, |
| 1024 | 'auth_callback' => null, |
| 1025 | 'object_subtype' => '', |
| 1026 | 'type' => 'string', |
| 1027 | 'description' => '', |
| 1028 | 'show_in_rest' => false, |
| 1029 | ); |
| 1030 | |
| 1031 | $passed_args = array_slice( func_get_args(), 2 ); |
| 1032 | |
| 1033 | // There used to be individual args for sanitize and auth callbacks |
| 1034 | $has_old_sanitize_cb = $has_old_auth_cb = false; |
| 1035 | |
| 1036 | if ( is_callable( $passed_args[0] ) ) { |
| 1037 | $args->sanitize_callback = $passed_args[0]; |
| 1038 | $has_old_sanitize_cb = true; |
| 1039 | } else { |
| 1040 | $args = $passed_args[0]; |
| 1041 | } |
| 1042 | |
| 1043 | if ( isset( $passed_args[1] ) && is_callable( $passed_args[1] ) ) { |
| 1044 | $args->auth_callback = $passed_args[1]; |
| 1045 | $has_old_auth_cb = true; |
| 1046 | } |
| 1047 | |
| 1048 | $args = wp_parse_args( $args, $defaults ); |
| 1049 | |
| 1050 | // Whitelist args to reserve the right to add/change them later. |
| 1051 | // You remove it, you buy it. |
| 1052 | add_filter( 'register_meta_args', '_wp_register_meta_args_whitelist', 10, 2 ) |
| 1053 | |
| 1054 | /** |
| 1055 | * Filters the registration arguments when registering meta. |
| 1056 | * |
| 1057 | * @since 4.6.0 |
| 1058 | * |
| 1059 | * @param array $args Array of meta registration arguments. |
| 1060 | * @param array $defaults Array of default arguments. |
| 1061 | * @param string $object_type Object type. |
| 1062 | * @param string $meta_key Meta key. |
| 1063 | */ |
| 1064 | $args = apply_filters( 'register_meta_args', $args, $defaults, $object_type, $meta_key ); |
| 1065 | |
| 1066 | // Object subtype is required if using the args style of registration |
| 1067 | if ( ! $has_old_sanitize_cb && empty( $args['object_subtype'] ) ) { |
| 1068 | return false; |
| 1069 | } |
| 1070 | |
| 1071 | // Back-compat: old sanitize and auth callbacks applied to all of an object type |
| 1072 | if ( $has_old_sanitize_cb ) { |
| 1073 | add_filter( "sanitize_{$object_type}_meta_{$meta_key}", $args->sanitize_callback, 10, 3 ); |
| 1074 | } elseif ( is_callable( $args->sanitize_callback ) ) { |
| 1075 | add_filter( "sanitize_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args->sanitize_callback, 10, 3 ); |
| 1076 | } |
| 1077 | |
| 1078 | // If `auth_callback` is not provided, fall back to `is_protected_meta()`. |
| 1079 | if ( empty( $args->auth_callback ) ) { |
| 1080 | if ( is_protected_meta( $meta_key, $object_type ) ) { |
| 1081 | $args->auth_callback = '__return_false'; |
| 1082 | } else { |
| 1083 | $args->auth_callback = '__return_true'; |
| 1084 | } |
| 1085 | } |
| 1086 | |
| 1087 | if ( $has_old_auth_cb ) { |
| 1088 | add_filter( "auth_{$object_type}_meta_{$meta_key}", $args->auth_callback, 10, 3 ); |
| 1089 | } elseif ( is_callable( $args->auth_callback ) ) { |
| 1090 | add_filter( "auth_{$object_type}_{$object_subtype}_meta_{$meta_key}", $args->auth_callback, 10, 3 ); |
| 1091 | } |
| 1092 | |
| 1093 | $object_subtype = $args['object_subtype']; |
| 1094 | |
| 1095 | // Global registry only contains meta keys registered in the new way with a subtype. |
| 1096 | if ( ! empty( $object_subtype ) ) { |
| 1097 | $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] = $args; |
| 1098 | |
| 1099 | return true; |
| 1100 | } |
| 1101 | |
| 1102 | return false; |
| 1104 | |
| 1105 | /** |
| 1106 | * Checks if a meta key is registered. |
| 1107 | * |
| 1108 | * @since 4.6.0 |
| 1109 | * |
| 1110 | * @param string $object_type The type of object. |
| 1111 | * @param string $object_subtype The subtype of the object type. |
| 1112 | * @param string $meta_key The meta key. |
| 1113 | * |
| 1114 | * @return bool True if the meta key is registered to the object type and subtype. False if not. |
| 1115 | */ |
| 1116 | function registered_meta_key_exists( $object_type, $object_subtype, $meta_key ) { |
| 1117 | global $wp_meta_keys; |
| 1118 | |
| 1119 | if ( ! is_array( $wp_meta_keys ) ) { |
| 1120 | return false; |
| 1121 | } |
| 1122 | |
| 1123 | // Only specific core object types are supported. |
| 1124 | if ( ! in_array( $object_type, array( 'post', 'comment', 'user', 'term' ) ) ) { |
| 1125 | return false; |
| 1126 | } |
| 1127 | |
| 1128 | if ( ! isset( $wp_meta_keys[ $object_type ] ) ) { |
| 1129 | return false; |
| 1130 | } |
| 1131 | |
| 1132 | if ( ! isset( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) { |
| 1133 | return false; |
| 1134 | } |
| 1135 | |
| 1136 | if ( isset( $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] ) ) { |
| 1137 | return true; |
| 1138 | } |
| 1139 | |
| 1140 | return false; |
| 1141 | } |
| 1142 | |
| 1143 | /** |
| 1144 | * Unregisters a meta key from the list of registered keys. |
| 1145 | * |
| 1146 | * @since 4.6.0 |
| 1147 | * |
| 1148 | * @param string $object_type The type of object. |
| 1149 | * @param string $object_subtype The subtype of the object type. |
| 1150 | * @param string $meta_key The meta key. |
| 1151 | * |
| 1152 | * @return bool|WP_Error True if successful. WP_Error if the meta key is invalid. |
| 1153 | */ |
| 1154 | function unregister_meta_key( $object_type, $object_subtype, $meta_key ) { |
| 1155 | global $wp_meta_keys; |
| 1156 | |
| 1157 | if ( ! registered_meta_key_exists( $object_type, $object_subtype, $meta_key ) ) { |
| 1158 | return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key' ) ); |
| 1159 | } |
| 1160 | |
| 1161 | unset( $wp_meta_keys[ $object_type ][ $object_subtype ][ $meta_key ] ); |
| 1162 | |
| 1163 | return true; |
| 1164 | } |
| 1165 | |
| 1166 | /** |
| 1167 | * Retrieves a list of registered meta keys for an object type and optionally subtype. |
| 1168 | * |
| 1169 | * @since 4.6.0 |
| 1170 | * |
| 1171 | * @param string $object_type The type of object. Post, comment, user, term. |
| 1172 | * @param string $object_subtype Optional. A subtype of the object (e.g. custom post type). |
| 1173 | * |
| 1174 | * @return array List of registered meta keys. |
| 1175 | */ |
| 1176 | function get_registered_meta_keys( $object_type, $object_subtype = '' ) { |
| 1177 | global $wp_meta_keys; |
| 1178 | |
| 1179 | if ( ! isset( $wp_meta_keys[ $object_type ] ) ) { |
| 1180 | return array(); |
| 1181 | } |
| 1182 | |
| 1183 | if ( empty( $object_subtype ) && isset( $wp_meta_keys[ $object_type ] ) ) { |
| 1184 | return $wp_meta_keys[ $object_type ]; |
| 1185 | } |
| 1186 | |
| 1187 | if ( ! isset( $wp_meta_keys[ $object_type ][ $object_subtype ] ) ) { |
| 1188 | return array(); |
| 1189 | } |
| 1190 | |
| 1191 | return $wp_meta_keys[ $object_type ][ $object_subtype ]; |
| 1192 | } |
| 1193 | |
| 1194 | /** |
| 1195 | * Retrieves registered metadata for a specified object. |
| 1196 | * |
| 1197 | * @since 4.6.0 |
| 1198 | * |
| 1199 | * @param string $object_type Type of object to request metadata for. (e.g. comment, post, term, user) |
| 1200 | * @param string $object_subtype The subtype of the object's type to request metadata for. (e.g. custom post type) |
| 1201 | * @param int $object_id ID of the object the metadata is for. |
| 1202 | * @param string $meta_key Optional. Registered metadata key. If not specified, retrieve all registered |
| 1203 | * metadata for the specified object. |
| 1204 | * |
| 1205 | * @return mixed|WP_Error |
| 1206 | */ |
| 1207 | function get_registered_metadata( $object_type, $object_subtype, $object_id, $meta_key = '' ) { |
| 1208 | global $wp_meta_keys; |
| 1209 | |
| 1210 | if ( ! is_array( $wp_meta_keys ) ) { |
| 1211 | return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered.' ) ); |
| 1212 | } |
| 1213 | |
| 1214 | if ( ! in_array( $object_type, array( 'post', 'comment', 'user', 'term' ) ) ) { |
| 1215 | return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not a core object type.' ) ); |
| 1216 | } |
| 1217 | |
| 1218 | if ( ! empty( $meta_key ) ) { |
| 1219 | if ( ! registered_meta_key_exists( $object_type, $object_subtype, $meta_key ) ) { |
| 1220 | return new WP_Error( 'invalid_meta_key', __( 'Invalid meta key. Not registered.' ) ); |
| 1221 | } |
| 1222 | $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); |
| 1223 | $meta_key_data = $meta_keys[ $object_type ][ $object_subtype ][ $meta_key ]; |
| 1224 | |
| 1225 | $data = get_metadata( $object_type, $object_id, $meta_key, $meta_key_data->single ); |
| 1226 | |
| 1227 | return $data; |
| 1228 | } |
| 1229 | |
| 1230 | $data = get_metadata( $object_type, $object_id, $meta_key ); |
| 1231 | |
| 1232 | $meta_keys = get_registered_meta_keys( $object_type, $object_subtype ); |
| 1233 | $registered_data = array(); |
| 1234 | |
| 1235 | // Someday, array_filter() |
| 1236 | foreach ( $meta_keys as $k => $v ) { |
| 1237 | if ( isset( $data[ $k ] ) ) { |
| 1238 | $registered_data[ $k ] = $data[ $k ]; |
| 1239 | } |
| 1240 | } |
| 1241 | |
| 1242 | return $registered_data; |
| 1243 | } |
| 1244 | |
| 1245 | /** |
| 1246 | * Filter out `register_meta()` args based on a whitelist. |
| 1247 | * `register_meta()` args may change over time, so requiring the whitelist |
| 1248 | * to be explicitly turned off is a warranty seal of sorts. |
| 1249 | * |
| 1250 | * @access private |
| 1251 | * @since 4.6.0 |
| 1252 | * |
| 1253 | * @param array $args Arguments from `register_meta()`. |
| 1254 | * @param array $default_args Default arguments for `register_meta()`. |
| 1255 | * |
| 1256 | * @return array Filtered arguments. |
| 1257 | */ |
| 1258 | function _wp_register_meta_args_whitelist( $args, $default_args ) { |
| 1259 | $whitelist = array_keys( $defaults ); |
| 1260 | |
| 1261 | // In an anonymous function world, this would be better as an array_filter() |
| 1262 | foreach ( $args as $key => $value ) { |
| 1263 | if ( ! in_array( $key, $whitelist ) ) { |
| 1264 | unset( $args[ $key ] ); |
| 1265 | } |
| 1266 | } |
| 1267 | |
| 1268 | return $args; |
| 1269 | } |