WordPress.org

Make WordPress Core

Changeset 39179


Ignore:
Timestamp:
11/09/2016 03:41:07 AM (4 years ago)
Author:
rmccue
Message:

Roles/Capabilities: Add meta-caps for comment, term, and user meta.

Additionally, use these meta-caps in the REST API endpoints.

Previously, register_meta()'s auth_callback had no effect for non-post meta. This introduces {add,edit,delete}_{comment,term,user}_meta meta-caps to match the existing post meta capabilities. These are currently only used in the REST API.

Props tharsheblows, boonebgorges.
Fixes #38303, fixes #38412.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/capabilities.php

    r39175 r39179  
    243243    case 'delete_post_meta':
    244244    case 'add_post_meta':
    245         $post = get_post( $args[0] );
    246         if ( ! $post ) {
    247             $caps[] = 'do_not_allow';
    248             break;
    249         }
    250 
    251         $post_type = get_post_type( $post );
    252 
    253         $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
    254 
    255         $meta_key = isset( $args[ 1 ] ) ? $args[ 1 ] : false;
    256 
    257         if ( $meta_key && ( has_filter( "auth_post_meta_{$meta_key}" ) || has_filter( "auth_post_{$post_type}_meta_{$meta_key}" ) ) ) {
    258             /**
    259              * Filters whether the user is allowed to add post meta to a post.
    260              *
    261              * The dynamic portion of the hook name, `$meta_key`, refers to the
    262              * meta key passed to map_meta_cap().
    263              *
    264              * @since 3.3.0
    265              *
    266              * @param bool   $allowed  Whether the user can add the post meta. Default false.
    267              * @param string $meta_key The meta key.
    268              * @param int    $post_id  Post ID.
    269              * @param int    $user_id  User ID.
    270              * @param string $cap      Capability name.
    271              * @param array  $caps     User capabilities.
    272              */
    273             $allowed = apply_filters( "auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps );
    274 
    275             /**
    276              * Filters whether the user is allowed to add post meta to a post of a given type.
    277              *
    278              * The dynamic portions of the hook name, `$meta_key` and `$post_type`,
    279              * refer to the meta key passed to map_meta_cap() and the post type, respectively.
    280              *
    281              * @since 4.6.0
    282              *
    283              * @param bool   $allowed  Whether the user can add the post meta. Default false.
    284              * @param string $meta_key The meta key.
    285              * @param int    $post_id  Post ID.
    286              * @param int    $user_id  User ID.
    287              * @param string $cap      Capability name.
    288              * @param array  $caps     User capabilities.
    289              */
    290             $allowed = apply_filters( "auth_post_{$post_type}_meta_{$meta_key}", $allowed, $meta_key, $post->ID, $user_id, $cap, $caps );
    291 
    292             if ( ! $allowed )
     245    case 'edit_comment_meta':
     246    case 'delete_comment_meta':
     247    case 'add_comment_meta':
     248    case 'edit_term_meta':
     249    case 'delete_term_meta':
     250    case 'add_term_meta':
     251    case 'edit_user_meta':
     252    case 'delete_user_meta':
     253    case 'add_user_meta':
     254        list( $_, $object_type, $_ ) = explode( '_', $cap );
     255        $object_id = (int) $args[0];
     256
     257        switch ( $object_type ) {
     258            case 'post':
     259                $post = get_post( $object_id );
     260                if ( ! $post ) {
     261                    break;
     262                }
     263
     264                $sub_type = get_post_type( $post );
     265                break;
     266
     267            case 'comment':
     268                $comment = get_comment( $object_id );
     269                if ( ! $comment ) {
     270                    break;
     271                }
     272
     273                $sub_type = empty( $comment->comment_type ) ? 'comment' : $comment->comment_type;
     274                break;
     275
     276            case 'term':
     277                $term = get_term( $object_id );
     278                if ( ! $term ) {
     279                    break;
     280                }
     281
     282                $sub_type = $term->taxonomy;
     283                break;
     284
     285            case 'user':
     286                $user = get_user_by( 'id', $object_id );
     287                if ( ! $user ) {
     288                    break;
     289                }
     290
     291                $sub_type = 'user';
     292                break;
     293        }
     294
     295        if ( empty( $sub_type ) ) {
     296            $caps[] = 'do_not_allow';
     297            break;
     298        }
     299
     300        $caps = map_meta_cap( "edit_{$object_type}", $user_id, $object_id );
     301
     302        $meta_key = isset( $args[1] ) ? $args[1] : false;
     303
     304        $has_filter = has_filter( "auth_{$object_type}_meta_{$meta_key}" ) || has_filter( "auth_{$object_type}_{$sub_type}_meta_{$meta_key}" );
     305        if ( $meta_key && $has_filter ) {
     306            /** This filter is documented in wp-includes/meta.php */
     307            $allowed = apply_filters( "auth_{$object_type}_meta_{$meta_key}", false, $meta_key, $object_id, $user_id, $cap, $caps );
     308
     309            /** This filter is documented in wp-includes/meta.php */
     310            $allowed = apply_filters( "auth_{$object_type}_{$sub_type}_meta_{$meta_key}", $allowed, $meta_key, $object_id, $user_id, $cap, $caps );
     311
     312            if ( ! $allowed ) {
    293313                $caps[] = $cap;
    294         } elseif ( $meta_key && is_protected_meta( $meta_key, 'post' ) ) {
     314            }
     315        } elseif ( $meta_key && is_protected_meta( $meta_key, $object_type ) ) {
    295316            $caps[] = $cap;
    296317        }
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php

    r39161 r39179  
    632632                return new WP_Error( 'rest_comment_failed_edit', __( 'Updating comment status failed.' ), array( 'status' => 500 ) );
    633633            }
    634         } else {
     634        } elseif ( ! empty( $prepared_args ) ) {
    635635            if ( is_wp_error( $prepared_args ) ) {
    636636                return $prepared_args;
  • trunk/src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php

    r39058 r39179  
    123123    public function update_value( $request, $object_id ) {
    124124        $fields = $this->get_registered_fields();
    125 
    126125        foreach ( $fields as $name => $args ) {
    127126            if ( ! array_key_exists( $name, $request ) ) {
     
    160159     */
    161160    protected function delete_meta_value( $object_id, $name ) {
    162         if ( ! current_user_can( 'delete_post_meta', $object_id, $name ) ) {
     161        $meta_type = $this->get_meta_type();
     162        if ( ! current_user_can( "delete_{$meta_type}_meta", $object_id, $name ) ) {
    163163            return new WP_Error(
    164164                'rest_cannot_delete',
     
    168168        }
    169169
    170         if ( ! delete_metadata( $this->get_meta_type(), $object_id, wp_slash( $name ) ) ) {
     170        if ( ! delete_metadata( $meta_type, $object_id, wp_slash( $name ) ) ) {
    171171            return new WP_Error(
    172172                'rest_meta_database_error',
     
    193193     */
    194194    protected function update_multi_meta_value( $object_id, $name, $values ) {
    195         if ( ! current_user_can( 'edit_post_meta', $object_id, $name ) ) {
     195        $meta_type = $this->get_meta_type();
     196        if ( ! current_user_can( "edit_{$meta_type}_meta", $object_id, $name ) ) {
    196197            return new WP_Error(
    197198                'rest_cannot_update',
     
    201202        }
    202203
    203         $current = get_metadata( $this->get_meta_type(), $object_id, $name, false );
     204        $current = get_metadata( $meta_type, $object_id, $name, false );
    204205
    205206        $to_remove = $current;
     
    228229
    229230        foreach ( $to_remove as $value ) {
    230             if ( ! delete_metadata( $this->get_meta_type(), $object_id, wp_slash( $name ), wp_slash( $value ) ) ) {
     231            if ( ! delete_metadata( $meta_type, $object_id, wp_slash( $name ), wp_slash( $value ) ) ) {
    231232                return new WP_Error(
    232233                    'rest_meta_database_error',
     
    238239
    239240        foreach ( $to_add as $value ) {
    240             if ( ! add_metadata( $this->get_meta_type(), $object_id, wp_slash( $name ), wp_slash( $value ) ) ) {
     241            if ( ! add_metadata( $meta_type, $object_id, wp_slash( $name ), wp_slash( $value ) ) ) {
    241242                return new WP_Error(
    242243                    'rest_meta_database_error',
     
    262263     */
    263264    protected function update_meta_value( $object_id, $name, $value ) {
    264         if ( ! current_user_can( 'edit_post_meta', $object_id, $name ) ) {
     265        $meta_type = $this->get_meta_type();
     266        if ( ! current_user_can(  "edit_{$meta_type}_meta", $object_id, $name ) ) {
    265267            return new WP_Error(
    266268                'rest_cannot_update',
     
    270272        }
    271273
    272         $meta_type  = $this->get_meta_type();
    273274        $meta_key   = wp_slash( $name );
    274275        $meta_value = wp_slash( $value );
  • trunk/tests/phpunit/tests/user/capabilities.php

    r39178 r39179  
    432432            $expected['add_post_meta'],
    433433            $expected['edit_comment'],
     434            $expected['edit_comment_meta'],
     435            $expected['delete_comment_meta'],
     436            $expected['add_comment_meta'],
    434437            $expected['edit_term'],
    435438            $expected['delete_term'],
    436439            $expected['assign_term'],
    437             $expected['delete_user']
     440            $expected['edit_term_meta'],
     441            $expected['delete_term_meta'],
     442            $expected['add_term_meta'],
     443            $expected['delete_user'],
     444            $expected['edit_user_meta'],
     445            $expected['delete_user_meta'],
     446            $expected['add_user_meta']
    438447        );
    439448
     
    16641673        $wp_roles->reinit();
    16651674    }
     1675
     1676    /**
     1677     * @ticket 38412
     1678     */
     1679    public function test_no_one_can_edit_user_meta_for_non_existent_term() {
     1680        wp_set_current_user( self::$super_admin->ID );
     1681        $this->assertFalse( current_user_can( 'edit_user_meta', 999999 ) );
     1682    }
     1683
     1684    /**
     1685     * @ticket 38412
     1686     */
     1687    public function test_user_can_edit_user_meta() {
     1688        wp_set_current_user( self::$users['administrator']->ID );
     1689        if ( is_multisite() ) {
     1690            grant_super_admin( self::$users['administrator']->ID );
     1691        }
     1692        $this->assertTrue( current_user_can( 'edit_user_meta', self::$users['subscriber']->ID, 'foo' ) );
     1693    }
     1694
     1695    /**
     1696     * @ticket 38412
     1697     */
     1698    public function test_user_cannot_edit_user_meta() {
     1699        wp_set_current_user( self::$users['editor']->ID );
     1700        $this->assertFalse( current_user_can( 'edit_user_meta', self::$users['subscriber']->ID, 'foo' ) );
     1701    }
     1702
     1703    /**
     1704     * @ticket 38412
     1705     */
     1706    public function test_no_one_can_delete_user_meta_for_non_existent_term() {
     1707        wp_set_current_user( self::$super_admin->ID );
     1708        $this->assertFalse( current_user_can( 'delete_user_meta', 999999, 'foo' ) );
     1709    }
     1710
     1711    /**
     1712     * @ticket 38412
     1713     */
     1714    public function test_user_can_delete_user_meta() {
     1715        wp_set_current_user( self::$users['administrator']->ID );
     1716        if ( is_multisite() ) {
     1717            grant_super_admin( self::$users['administrator']->ID );
     1718        }
     1719        $this->assertTrue( current_user_can( 'delete_user_meta', self::$users['subscriber']->ID, 'foo' ) );
     1720    }
     1721
     1722    /**
     1723     * @ticket 38412
     1724     */
     1725    public function test_user_cannot_delete_user_meta() {
     1726        wp_set_current_user( self::$users['editor']->ID );
     1727        $this->assertFalse( current_user_can( 'delete_user_meta', self::$users['subscriber']->ID, 'foo' ) );
     1728    }
     1729
     1730    /**
     1731     * @ticket 38412
     1732     */
     1733    public function test_no_one_can_add_user_meta_for_non_existent_term() {
     1734        wp_set_current_user( self::$super_admin->ID );
     1735        $this->assertFalse( current_user_can( 'add_user_meta', 999999, 'foo' ) );
     1736    }
     1737
     1738    /**
     1739     * @ticket 38412
     1740     */
     1741    public function test_user_can_add_user_meta() {
     1742        wp_set_current_user( self::$users['administrator']->ID );
     1743        if ( is_multisite() ) {
     1744            grant_super_admin( self::$users['administrator']->ID );
     1745        }
     1746        $this->assertTrue( current_user_can( 'add_user_meta', self::$users['subscriber']->ID, 'foo' ) );
     1747    }
     1748
     1749    /**
     1750     * @ticket 38412
     1751     */
     1752    public function test_user_cannot_add_user_meta() {
     1753        wp_set_current_user( self::$users['editor']->ID );
     1754        $this->assertFalse( current_user_can( 'add_user_meta', self::$users['subscriber']->ID, 'foo' ) );
     1755    }
    16661756}
Note: See TracChangeset for help on using the changeset viewer.