From 4ad095496153ff08356488348c917737bf8531b2 Mon Sep 17 00:00:00 2001 From: ryan Date: Wed, 20 Jul 2011 22:04:35 +0000 Subject: [PATCH] Introduce register_meta(), get_metadata_by_mid(), and *_post_meta capabilities. fixes #17850 git-svn-id: http://svn.automattic.com/wordpress/trunk@18445 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/admin-ajax.php | 10 ++-- wp-admin/includes/meta-boxes.php | 6 +- wp-admin/includes/post.php | 20 ++----- wp-admin/includes/template.php | 4 +- wp-includes/capabilities.php | 17 ++++++ wp-includes/class-wp-xmlrpc-server.php | 22 ++++--- wp-includes/meta.php | 82 +++++++++++++++++++++++--- wp-includes/post-template.php | 2 +- 8 files changed, 118 insertions(+), 45 deletions(-) diff --git a/wp-admin/admin-ajax.php b/wp-admin/admin-ajax.php index ee9118294..173c271ac 100644 --- a/wp-admin/admin-ajax.php +++ b/wp-admin/admin-ajax.php @@ -393,10 +393,10 @@ case 'delete-link' : break; case 'delete-meta' : check_ajax_referer( "delete-meta_$id" ); - if ( !$meta = get_post_meta_by_id( $id ) ) + if ( !$meta = get_metadata_by_mid( 'post', $id ) ) die('1'); - if ( !current_user_can( 'edit_post', $meta->post_id ) || is_protected_meta( $meta->meta_key ) ) + if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $meta->post_id, $meta->meta_key ) ) die('-1'); if ( delete_meta( $meta->meta_id ) ) die('1'); @@ -849,7 +849,7 @@ case 'add-meta' : die(__('Please provide a custom field value.')); } - $meta = get_post_meta_by_id( $mid ); + $meta = get_metadata_by_mid( 'post', $mid ); $pid = (int) $meta->post_id; $meta = get_object_vars( $meta ); $x = new WP_Ajax_Response( array( @@ -869,9 +869,7 @@ case 'add-meta' : die(__('Please provide a custom field value.')); if ( !$meta = get_post_meta_by_id( $mid ) ) die('0'); // if meta doesn't exist - if ( !current_user_can( 'edit_post', $meta->post_id ) ) - die('-1'); - if ( is_protected_meta( $meta->meta_key ) ) + if ( is_protected_meta( $meta->meta_key, 'post' ) || !current_user_can( 'edit_post_meta', $meta->post_id, $meta->meta_key ) ) die('-1'); if ( $meta->meta_value != stripslashes($value) || $meta->meta_key != stripslashes($key) ) { if ( !$u = update_meta( $mid, $key, $value ) ) diff --git a/wp-admin/includes/meta-boxes.php b/wp-admin/includes/meta-boxes.php index 6d396ad77..918956211 100644 --- a/wp-admin/includes/meta-boxes.php +++ b/wp-admin/includes/meta-boxes.php @@ -425,7 +425,11 @@ function post_custom_meta_box($post) {
ID); -list_meta($metadata); +foreach ( $metadata as $key => $value ) { + if ( is_protected_meta( $metadata[ $key ][ 'meta_key' ], 'post' ) || ! current_user_can( 'edit_post_meta', $post->ID, $metadata[ $key ][ 'meta_key' ] ) ) + unset( $metadata[ $key ] ); +} +list_meta( $metadata ); meta_form(); ?>

use in your theme.'); ?>

diff --git a/wp-admin/includes/post.php b/wp-admin/includes/post.php index d65e0e2a0..18c64530d 100644 --- a/wp-admin/includes/post.php +++ b/wp-admin/includes/post.php @@ -210,7 +210,7 @@ function edit_post( $post_data = null ) { continue; if ( $meta->post_id != $post_ID ) continue; - if ( is_protected_meta( $value['key'] ) ) + if ( is_protected_meta( $value['key'], 'post' ) || ! current_user_can( 'edit_post_meta', $post_ID, $value['key'] ) ) continue; update_meta( $key, $value['key'], $value['value'] ); } @@ -222,7 +222,7 @@ function edit_post( $post_data = null ) { continue; if ( $meta->post_id != $post_ID ) continue; - if ( is_protected_meta( $meta->meta_key ) ) + if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $post_ID, $meta->meta_key ) ) continue; delete_meta( $key ); } @@ -671,7 +671,7 @@ function add_meta( $post_ID ) { if ( is_string($metavalue) ) $metavalue = trim( $metavalue ); - if ( ('0' === $metavalue || !empty ( $metavalue ) ) && ((('#NONE#' != $metakeyselect) && !empty ( $metakeyselect) ) || !empty ( $metakeyinput) ) ) { + if ( ('0' === $metavalue || ! empty ( $metavalue ) ) && ((('#NONE#' != $metakeyselect) && !empty ( $metakeyselect) ) || !empty ( $metakeyinput) ) ) { // We have a key/value pair. If both the select and the // input for the key have data, the input takes precedence: @@ -681,16 +681,12 @@ function add_meta( $post_ID ) { if ( $metakeyinput) $metakey = $metakeyinput; // default - if ( is_protected_meta( $metakey ) ) + if ( is_protected_meta( $metakey, 'post' ) || ! current_user_can( 'add_post_meta', $post_ID, $metakey ) ) return false; - wp_cache_delete($post_ID, 'post_meta'); - $wpdb->insert( $wpdb->postmeta, array( 'post_id' => $post_ID, 'meta_key' => $metakey, 'meta_value' => $metavalue ) ); - $meta_id = $wpdb->insert_id; - do_action( 'added_postmeta', $meta_id, $post_ID, $metakey, $metavalue ); - - return $meta_id; + return add_post_meta($post_ID, $metakey, $metavalue); } + return false; } // add_meta @@ -771,7 +767,6 @@ function has_meta( $postid ) { return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, post_id FROM $wpdb->postmeta WHERE post_id = %d ORDER BY meta_key,meta_id", $postid), ARRAY_A ); - } /** @@ -789,9 +784,6 @@ function update_meta( $meta_id, $meta_key, $meta_value ) { $meta_key = stripslashes($meta_key); - if ( is_protected_meta( $meta_key ) ) - return false; - if ( '' === trim( $meta_value ) ) return false; diff --git a/wp-admin/includes/template.php b/wp-admin/includes/template.php index 23575bbe6..df8749238 100644 --- a/wp-admin/includes/template.php +++ b/wp-admin/includes/template.php @@ -466,7 +466,7 @@ function list_meta( $meta ) { function _list_meta_row( $entry, &$count ) { static $update_nonce = false; - if ( is_protected_meta( $entry['meta_key'] ) ) + if ( is_protected_meta( $entry['meta_key'], 'post' ) ) return; if ( !$update_nonce ) @@ -478,8 +478,6 @@ function _list_meta_row( $entry, &$count ) { $style = 'alternate'; else $style = ''; - if ('_' == $entry['meta_key'] { 0 } ) - $style .= ' hidden'; if ( is_serialized( $entry['meta_value'] ) ) { if ( is_serialized_string( $entry['meta_value'] ) ) { diff --git a/wp-includes/capabilities.php b/wp-includes/capabilities.php index 28e754155..446264ec1 100644 --- a/wp-includes/capabilities.php +++ b/wp-includes/capabilities.php @@ -951,6 +951,23 @@ function map_meta_cap( $cap, $user_id ) { else $caps[] = $post_type->cap->read_private_posts; break; + case 'edit_post_meta': + case 'delete_post_meta': + case 'add_post_meta': + $post = get_post( $args[0] ); + $post_type_object = get_post_type_object( $post->post_type ); + $caps = map_meta_cap( $post_type_object->cap->edit_post, $user_id, $post->ID ); + + $meta_key = isset( $args[ 1 ] ) ? $args[ 1 ] : false; + + if ( $meta_key && has_filter( "auth_post_meta_{$meta_key}" ) ) { + $allowed = apply_filters( "auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps ); + if ( ! $allowed ) + $caps[] = $cap; + } elseif ( $meta_key && is_protected_meta( $meta_key, 'post' ) ) { + $caps[] = $cap; + } + break; case 'edit_comment': $comment = get_comment( $args[0] ); $post = get_post( $comment->comment_post_ID ); diff --git a/wp-includes/class-wp-xmlrpc-server.php b/wp-includes/class-wp-xmlrpc-server.php index 9d92cecff..f7a26ae09 100644 --- a/wp-includes/class-wp-xmlrpc-server.php +++ b/wp-includes/class-wp-xmlrpc-server.php @@ -234,9 +234,8 @@ class wp_xmlrpc_server extends IXR_Server { foreach ( (array) has_meta($post_id) as $meta ) { // Don't expose protected fields. - if ( strpos($meta['meta_key'], '_wp_') === 0 ) { + if ( ! current_user_can( 'edit_post_meta', $post_id , $meta['meta_key'] ) ) continue; - } $custom_fields[] = array( "id" => $meta['meta_id'], @@ -262,18 +261,17 @@ class wp_xmlrpc_server extends IXR_Server { foreach ( (array) $fields as $meta ) { if ( isset($meta['id']) ) { $meta['id'] = (int) $meta['id']; - + $pmeta = get_metadata_by_mid( 'post', $meta['id'] ); if ( isset($meta['key']) ) { - update_meta($meta['id'], $meta['key'], $meta['value']); + if ( $meta['key'] != $pmeta->meta_key ) + continue; + if ( current_user_can( 'edit_post_meta', $post_id, $meta['key'] ) ) + update_meta( $meta['id'], $meta['key'], $meta['value'] ); + } elseif ( current_user_can( 'delete_post_meta', $post_id, $pmeta->meta_key ) ) { + delete_meta( $meta['id'] ); } - else { - delete_meta($meta['id']); - } - } - else { - $_POST['metakeyinput'] = $meta['key']; - $_POST['metavalue'] = $meta['value']; - add_meta($post_id); + } elseif ( current_user_can( 'add_post_meta', $post_id, $meta['key'] ) ) { + add_post_meta( $post_id, $meta['key'], $meta['value'] ); } } } diff --git a/wp-includes/meta.php b/wp-includes/meta.php index b24ae080f..051e0b45a 100644 --- a/wp-includes/meta.php +++ b/wp-includes/meta.php @@ -26,7 +26,7 @@ * @param bool $unique Optional, default is false. Whether the specified metadata key should be * unique for the object. If true, and the object already has a value for the specified * metadata key, no change will be made - * @return bool True on successful update, false on failure. + * @return bool The meta ID on successful update, false on failure. */ function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) { if ( !$meta_type || !$meta_key ) @@ -49,7 +49,7 @@ function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = $check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique ); if ( null !== $check ) - return (bool) $check; + return $check; if ( $unique && $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d", @@ -61,20 +61,25 @@ function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value ); - $wpdb->insert( $table, array( + $result = $wpdb->insert( $table, array( $column => $object_id, 'meta_key' => $meta_key, 'meta_value' => $meta_value ) ); + if ( ! $result ) + return false; + + $mid = (int) $wpdb->insert_id; + wp_cache_delete($object_id, $meta_type . '_meta'); // users cache stores usermeta that must be cleared. if ( 'user' == $meta_type ) clean_user_cache($object_id); - do_action( "added_{$meta_type}_meta", $wpdb->insert_id, $object_id, $meta_key, $_meta_value ); + do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value ); - return true; + return $mid; } /** @@ -146,6 +151,7 @@ function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_v do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value ); $wpdb->update( $table, $data, $where ); + wp_cache_delete($object_id, $meta_type . '_meta'); // users cache stores usermeta that must be cleared. if ( 'user' == $meta_type ) @@ -281,6 +287,40 @@ function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) { return array(); } +/** + * Get meta data by meta ID + * + * @since 3.3.0 + * + * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) + * @param int $meta_id ID for a specific meta row + * @return object Meta object or false. + */ +function get_metadata_by_mid( $meta_type, $meta_id ) { + global $wpdb; + + if ( ! $meta_type ) + return false; + + if ( !$meta_id = absint( $meta_id ) ) + return false; + + if ( ! $table = _get_meta_table($meta_type) ) + return false; + + $id_column = ( 'user' == $meta_type ) ? 'umeta_id' : 'meta_id'; + + $meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) ); + + if ( empty( $meta ) ) + return false; + + if ( isset( $meta->meta_value ) ) + $meta->meta_value = maybe_unserialize( $meta->meta_value ); + + return $meta; +} + /** * Update the metadata cache for the specified objects. * @@ -588,7 +628,7 @@ function _get_meta_table($type) { * @return bool True if the key is protected, false otherwise. */ function is_protected_meta( $meta_key, $meta_type = null ) { - $protected = ( '_' == $meta_key[0] ); + $protected = ( '_' == $meta_key[0] ); return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type ); } @@ -603,8 +643,34 @@ function is_protected_meta( $meta_key, $meta_type = null ) { * @param string $meta_type Type of meta * @return mixed Sanitized $meta_value */ -function sanitize_meta( $meta_key, $meta_value, $meta_type = null ) { - return apply_filters( 'sanitize_meta', $meta_value, $meta_key, $meta_type ); +function sanitize_meta( $meta_key, $meta_value, $meta_type ) { + return apply_filters( "sanitize_{$meta_type}_meta_{$meta_key}", $meta_value, $meta_key, $meta_type ); +} + +/** + * Register meta key + * + * @since 3.3.0 + * + * @param string $meta_type Type of meta + * @param string $meta_key Meta key + * @param string|array $sanitize_callback A function or method to call when sanitizing the value of $meta_key. + * @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. + * @param array $args Arguments + */ +function register_meta( $meta_type, $meta_key, $sanitize_callback, $auth_callback = null ) { + if ( is_callable( $sanitize_callback ) ) + add_filter( "sanitize_{$meta_type}_meta_{$meta_key}", $sanitize_callback, 10, 3 ); + + if ( empty( $auth_callback ) ) { + if ( is_protected_meta( $meta_key, $meta_type ) ) + $auth_callback = '__return_false'; + else + $auth_callback = '__return_true'; + } + + if ( is_callable( $auth_callback ) ) + add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 ); } ?> diff --git a/wp-includes/post-template.php b/wp-includes/post-template.php index d6a09783c..f5b75965d 100644 --- a/wp-includes/post-template.php +++ b/wp-includes/post-template.php @@ -737,7 +737,7 @@ function the_meta() { echo "