WordPress.org

Make WordPress Core

Changeset 38698


Ignore:
Timestamp:
09/30/2016 10:39:32 PM (3 years ago)
Author:
johnbillion
Message:

Taxonomy: Introduce more fine grained capabilities for managing taxonomy terms.

This introduces the singular edit_term, delete_term, and assign_term meta capabilities for terms, and switches the base capability name for tags from manage_categories to manage_post_tags and the corresponding edit_post_tags, delete_post_tags, and assign_post_tags.

All of these capabilities ultimately map to manage_categories so by default there is no change in the behaviour of the capabilities for categories, tags, or custom taxonomies. The map_meta_cap filter and the capabilities argument when registering a taxonomy now allow for control over editing, deleting, and assigning individual terms, as well as a separation of capabilities for tags from those of categories.

Fixes #35614
Props johnjamesjacoby for feedback

Location:
trunk
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/edit-tags.php

    r38647 r38698  
    109109    check_admin_referer( 'delete-tag_' . $tag_ID );
    110110
    111     if ( ! current_user_can( $tax->cap->delete_terms ) ) {
     111    if ( ! current_user_can( 'delete_term', $tag_ID ) ) {
    112112        wp_die(
    113113            '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
     
    169169    check_admin_referer( 'update-tag_' . $tag_ID );
    170170
    171     if ( ! current_user_can( $tax->cap->edit_terms ) ) {
     171    if ( ! current_user_can( 'edit_term', $tag_ID ) ) {
    172172        wp_die(
    173173            '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
     
    314314
    315315require_once( ABSPATH . 'wp-admin/admin-header.php' );
    316 
    317 if ( ! current_user_can( $tax->cap->edit_terms ) ) {
    318     wp_die(
    319         '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
    320         '<p>' . __( 'Sorry, you are not allowed to edit this item.' ) . '</p>',
    321         403
    322     );
    323 }
    324316
    325317/** Also used by the Edit Tag  form */
  • trunk/src/wp-admin/includes/ajax-actions.php

    r38666 r38698  
    595595    check_ajax_referer( "delete-tag_$tag_id" );
    596596
     597    if ( ! current_user_can( 'delete_term', $tag_id ) ) {
     598        wp_die( -1 );
     599    }
     600
    597601    $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
    598     $tax = get_taxonomy($taxonomy);
    599 
    600     if ( !current_user_can( $tax->cap->delete_terms ) )
    601         wp_die( -1 );
    602 
    603602    $tag = get_term( $tag_id, $taxonomy );
    604603    if ( !$tag || is_wp_error( $tag ) )
     
    797796        $action = 'add-link-category';
    798797    check_ajax_referer( $action );
    799     if ( !current_user_can( 'manage_categories' ) )
    800         wp_die( -1 );
     798    $tax = get_taxonomy( 'link_category' );
     799    if ( ! current_user_can( $tax->cap->manage_terms ) ) {
     800        wp_die( -1 );
     801    }
    801802    $names = explode(',', wp_unslash( $_POST['newcat'] ) );
    802803    $x = new WP_Ajax_Response();
     
    17041705        wp_die( 0 );
    17051706
    1706     if ( ! current_user_can( $tax->cap->edit_terms ) )
    1707         wp_die( -1 );
     1707    if ( ! isset( $_POST['tax_ID'] ) || ! ( $id = (int) $_POST['tax_ID'] ) ) {
     1708        wp_die( -1 );
     1709    }
     1710
     1711    if ( ! current_user_can( 'edit_term', $id ) ) {
     1712        wp_die( -1 );
     1713    }
    17081714
    17091715    $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
    1710 
    1711     if ( ! isset($_POST['tax_ID']) || ! ( $id = (int) $_POST['tax_ID'] ) )
    1712         wp_die( -1 );
    17131716
    17141717    $tag = get_term( $id, $taxonomy );
  • trunk/src/wp-admin/includes/class-wp-terms-list-table.php

    r38672 r38698  
    152152    protected function get_bulk_actions() {
    153153        $actions = array();
    154         $actions['delete'] = __( 'Delete' );
     154
     155        if ( current_user_can( get_taxonomy( $this->screen->taxonomy )->cap->delete_terms ) ) {
     156            $actions['delete'] = __( 'Delete' );
     157        }
    155158
    156159        return $actions;
     
    333336     */
    334337    public function column_cb( $tag ) {
    335         $default_term = get_option( 'default_' . $this->screen->taxonomy );
    336 
    337         if ( current_user_can( get_taxonomy( $this->screen->taxonomy )->cap->delete_terms ) && $tag->term_id != $default_term )
     338        if ( current_user_can( 'delete_term', $tag->term_id ) ) {
    338339            return '<label class="screen-reader-text" for="cb-select-' . $tag->term_id . '">' . sprintf( __( 'Select %s' ), $tag->name ) . '</label>'
    339340                . '<input type="checkbox" name="delete_tags[]" value="' . $tag->term_id . '" id="cb-select-' . $tag->term_id . '" />';
     341        }
    340342
    341343        return '&nbsp;';
     
    424426        $taxonomy = $this->screen->taxonomy;
    425427        $tax = get_taxonomy( $taxonomy );
    426         $default_term = get_option( 'default_' . $taxonomy );
    427 
    428428        $uri = wp_doing_ajax() ? wp_get_referer() : $_SERVER['REQUEST_URI'];
    429429
     
    435435
    436436        $actions = array();
    437         if ( current_user_can( $tax->cap->edit_terms ) ) {
     437        if ( current_user_can( 'edit_term', $tag->term_id ) ) {
    438438            $actions['edit'] = sprintf(
    439439                '<a href="%s" aria-label="%s">%s</a>',
     
    450450            );
    451451        }
    452         if ( current_user_can( $tax->cap->delete_terms ) && $tag->term_id != $default_term ) {
     452        if ( current_user_can( 'delete_term', $tag->term_id ) ) {
    453453            $actions['delete'] = sprintf(
    454454                '<a href="%s" class="delete-tag aria-button-if-js" aria-label="%s">%s</a>',
  • trunk/src/wp-admin/includes/meta-boxes.php

    r38672 r38698  
    435435    </div>
    436436    <p class="howto" id="new-tag-<?php echo $tax_name; ?>-desc"><?php echo $taxonomy->labels->separate_items_with_commas; ?></p>
     437    <?php elseif ( empty( $terms_to_edit ) ): ?>
     438        <p><?php echo $taxonomy->labels->no_terms; ?></p>
    437439    <?php endif; ?>
    438440    </div>
  • trunk/src/wp-admin/term.php

    r38069 r38698  
    3232
    3333if ( ! in_array( $taxonomy, get_taxonomies( array( 'show_ui' => true ) ) ) ||
    34      ! current_user_can( $tax->cap->manage_terms )
     34     ! current_user_can( 'edit_term', $tag->term_id )
    3535) {
    3636    wp_die(
    3737        '<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
    38         '<p>' . __( 'Sorry, you are not allowed to manage this item.' ) . '</p>',
     38        '<p>' . __( 'Sorry, you are not allowed to edit this item.' ) . '</p>',
    3939        403
    4040    );
  • trunk/src/wp-includes/admin-bar.php

    r38683 r38698  
    636636        } elseif ( ! empty( $current_object->taxonomy )
    637637            && ( $tax = get_taxonomy( $current_object->taxonomy ) )
    638             && current_user_can( $tax->cap->edit_terms )
     638            && current_user_can( 'edit_term', $current_object->term_id )
    639639            && $edit_term_link = get_edit_term_link( $current_object->term_id, $current_object->taxonomy ) )
    640640        {
  • trunk/src/wp-includes/capabilities.php

    r38695 r38698  
    403403        $caps[] = 'manage_options';
    404404        break;
     405    case 'edit_term':
     406    case 'delete_term':
     407    case 'assign_term':
     408        $term_id = $args[0];
     409        $term = get_term( $term_id );
     410        if ( ! $term || is_wp_error( $term ) ) {
     411            $caps[] = 'do_not_allow';
     412            break;
     413        }
     414
     415        $tax = get_taxonomy( $term->taxonomy );
     416        if ( ! $tax ) {
     417            $caps[] = 'do_not_allow';
     418            break;
     419        }
     420
     421        if ( 'delete_term' === $cap && ( $term->term_id == get_option( 'default_' . $term->taxonomy ) ) ) {
     422            $caps[] = 'do_not_allow';
     423            break;
     424        }
     425
     426        $taxo_cap = $cap . 's';
     427
     428        $caps = map_meta_cap( $tax->cap->$taxo_cap, $user_id, $term_id );
     429
     430        break;
     431    case 'manage_post_tags':
     432    case 'edit_categories':
     433    case 'edit_post_tags':
     434    case 'delete_categories':
     435    case 'delete_post_tags':
     436        $caps[] = 'manage_categories';
     437        break;
     438    case 'assign_categories':
     439    case 'assign_post_tags':
     440        $caps[] = 'edit_posts';
     441        break;
    405442    case 'create_sites':
    406443    case 'delete_sites':
  • trunk/src/wp-includes/class-wp-xmlrpc-server.php

    r38620 r38698  
    18871887        $taxonomy = get_taxonomy( $content_struct['taxonomy'] );
    18881888
    1889         if ( ! current_user_can( $taxonomy->cap->manage_terms ) )
     1889        if ( ! current_user_can( $taxonomy->cap->edit_terms ) ) {
    18901890            return new IXR_Error( 401, __( 'Sorry, you are not allowed to create terms in this taxonomy.' ) );
     1891        }
    18911892
    18921893        $taxonomy = (array) $taxonomy;
     
    19741975        $taxonomy = get_taxonomy( $content_struct['taxonomy'] );
    19751976
    1976         if ( ! current_user_can( $taxonomy->cap->edit_terms ) )
    1977             return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit terms in this taxonomy.' ) );
    1978 
    19791977        $taxonomy = (array) $taxonomy;
    19801978
     
    19891987        if ( ! $term )
    19901988            return new IXR_Error( 404, __( 'Invalid term ID.' ) );
     1989
     1990        if ( ! current_user_can( 'edit_term', $term_id ) ) {
     1991            return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit this term.' ) );
     1992        }
    19911993
    19921994        if ( isset( $content_struct['name'] ) ) {
     
    20692071
    20702072        $taxonomy = get_taxonomy( $taxonomy );
    2071 
    2072         if ( ! current_user_can( $taxonomy->cap->delete_terms ) )
    2073             return new IXR_Error( 401, __( 'Sorry, you are not allowed to delete terms in this taxonomy.' ) );
    2074 
    20752073        $term = get_term( $term_id, $taxonomy->name );
    20762074
     
    20802078        if ( ! $term )
    20812079            return new IXR_Error( 404, __( 'Invalid term ID.' ) );
     2080
     2081        if ( ! current_user_can( 'delete_term', $term_id ) ) {
     2082            return new IXR_Error( 401, __( 'Sorry, you are not allowed to delete this term.' ) );
     2083        }
    20822084
    20832085        $result = wp_delete_term( $term_id, $taxonomy->name );
     
    21412143        $taxonomy = get_taxonomy( $taxonomy );
    21422144
    2143         if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
    2144             return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign terms in this taxonomy.' ) );
    2145 
    21462145        $term = get_term( $term_id , $taxonomy->name, ARRAY_A );
    21472146
     
    21512150        if ( ! $term )
    21522151            return new IXR_Error( 404, __( 'Invalid term ID.' ) );
     2152
     2153        if ( ! current_user_can( 'assign_term', $term_id ) ) {
     2154            return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign this term.' ) );
     2155        }
    21532156
    21542157        return $this->_prepare_term( $term );
  • trunk/src/wp-includes/link-template.php

    r38645 r38698  
    931931
    932932    $tax = get_taxonomy( $term->taxonomy );
    933     if ( ! $tax || ! current_user_can( $tax->cap->edit_terms ) ) {
     933    if ( ! $tax || ! current_user_can( 'edit_term', $term->term_id ) ) {
    934934        return;
    935935    }
     
    985985
    986986    $tax = get_taxonomy( $term->taxonomy );
    987     if ( ! current_user_can( $tax->cap->edit_terms ) ) {
     987    if ( ! current_user_can( 'edit_term', $term->term_id ) ) {
    988988        return;
    989989    }
  • trunk/src/wp-includes/taxonomy.php

    r38677 r38698  
    6262        'show_admin_column' => true,
    6363        '_builtin' => true,
     64        'capabilities' => array(
     65            'manage_terms' => 'manage_categories',
     66            'edit_terms'   => 'edit_categories',
     67            'delete_terms' => 'delete_categories',
     68            'assign_terms' => 'assign_categories',
     69        ),
    6470    ) );
    6571
     
    7278        'show_admin_column' => true,
    7379        '_builtin' => true,
     80        'capabilities' => array(
     81            'manage_terms' => 'manage_post_tags',
     82            'edit_terms'   => 'edit_post_tags',
     83            'delete_terms' => 'delete_post_tags',
     84            'assign_terms' => 'assign_post_tags',
     85        ),
    7486    ) );
    7587
  • trunk/tests/phpunit/tests/user/capabilities.php

    r38697 r38698  
    224224            'delete_site'            => array( 'administrator' ),
    225225            'add_users'              => array( 'administrator' ),
     226
     227            'edit_categories'        => array( 'administrator', 'editor' ),
     228            'delete_categories'      => array( 'administrator', 'editor' ),
     229            'manage_post_tags'       => array( 'administrator', 'editor' ),
     230            'edit_post_tags'         => array( 'administrator', 'editor' ),
     231            'delete_post_tags'       => array( 'administrator', 'editor' ),
     232
     233            'assign_categories'      => array( 'administrator', 'editor', 'author', 'contributor' ),
     234            'assign_post_tags'       => array( 'administrator', 'editor', 'author', 'contributor' ),
    226235        );
    227236    }
     
    243252            'delete_site'            => array( 'administrator' ),
    244253            'add_users'              => array( 'administrator' ),
     254
     255            'edit_categories'        => array( 'administrator', 'editor' ),
     256            'delete_categories'      => array( 'administrator', 'editor' ),
     257            'manage_post_tags'       => array( 'administrator', 'editor' ),
     258            'edit_post_tags'         => array( 'administrator', 'editor' ),
     259            'delete_post_tags'       => array( 'administrator', 'editor' ),
     260
     261            'assign_categories'      => array( 'administrator', 'editor', 'author', 'contributor' ),
     262            'assign_post_tags'       => array( 'administrator', 'editor', 'author', 'contributor' ),
    245263        );
    246264    }
     
    400418            $expected['add_post_meta'],
    401419            $expected['edit_comment'],
     420            $expected['edit_term'],
     421            $expected['delete_term'],
     422            $expected['assign_term'],
    402423            $expected['delete_user']
    403424        );
     
    10771098            ), $caps, "Meta cap: {$meta_cap}" );
    10781099        }
     1100    }
     1101
     1102    /**
     1103     * @dataProvider dataTaxonomies
     1104     *
     1105     * @ticket 35614
     1106     */
     1107    public function test_default_taxonomy_term_cannot_be_deleted( $taxonomy ) {
     1108        if ( ! taxonomy_exists( $taxonomy ) ) {
     1109            register_taxonomy( $taxonomy, 'post' );
     1110        }
     1111
     1112        $tax  = get_taxonomy( $taxonomy );
     1113        $user = self::$users['administrator'];
     1114        $term = self::factory()->term->create_and_get( array(
     1115            'taxonomy' => $taxonomy,
     1116        ) );
     1117
     1118        update_option( "default_{$taxonomy}", $term->term_id );
     1119
     1120        $this->assertTrue( user_can( $user->ID, $tax->cap->delete_terms ) );
     1121        $this->assertFalse( user_can( $user->ID, 'delete_term', $term->term_id ) );
     1122    }
     1123
     1124    /**
     1125     * @dataProvider dataTaxonomies
     1126     *
     1127     * @ticket 35614
     1128     */
     1129    public function test_taxonomy_caps_map_correctly_to_their_meta_cap( $taxonomy ) {
     1130        if ( ! taxonomy_exists( $taxonomy ) ) {
     1131            register_taxonomy( $taxonomy, 'post' );
     1132        }
     1133
     1134        $tax  = get_taxonomy( $taxonomy );
     1135        $term = self::factory()->term->create_and_get( array(
     1136            'taxonomy' => $taxonomy,
     1137        ) );
     1138
     1139        foreach ( self::$users as $role => $user ) {
     1140            $this->assertSame(
     1141                user_can( $user->ID, 'edit_term', $term->term_id ),
     1142                user_can( $user->ID, $tax->cap->edit_terms ),
     1143                "Role: {$role}"
     1144            );
     1145            $this->assertSame(
     1146                user_can( $user->ID, 'delete_term', $term->term_id ),
     1147                user_can( $user->ID, $tax->cap->delete_terms ),
     1148                "Role: {$role}"
     1149            );
     1150            $this->assertSame(
     1151                user_can( $user->ID, 'assign_term', $term->term_id ),
     1152                user_can( $user->ID, $tax->cap->assign_terms ),
     1153                "Role: {$role}"
     1154            );
     1155        }
     1156
    10791157    }
    10801158
  • trunk/tests/phpunit/tests/xmlrpc/wp/deleteTerm.php

    r38078 r38698  
    4444        $this->assertInstanceOf( 'IXR_Error', $result );
    4545        $this->assertEquals( 401, $result->code );
    46         $this->assertEquals( __( 'Sorry, you are not allowed to delete terms in this taxonomy.' ), $result->message );
     46        $this->assertEquals( __( 'Sorry, you are not allowed to delete this term.' ), $result->message );
    4747    }
    4848
  • trunk/tests/phpunit/tests/xmlrpc/wp/editTerm.php

    r38078 r38698  
    5050        $this->assertInstanceOf( 'IXR_Error', $result );
    5151        $this->assertEquals( 401, $result->code );
    52         $this->assertEquals( __( 'Sorry, you are not allowed to edit terms in this taxonomy.' ), $result->message );
     52        $this->assertEquals( __( 'Sorry, you are not allowed to edit this term.' ), $result->message );
    5353    }
    5454
  • trunk/tests/phpunit/tests/xmlrpc/wp/getTerm.php

    r38078 r38698  
    4444        $this->assertInstanceOf( 'IXR_Error', $result );
    4545        $this->assertEquals( 401, $result->code );
    46         $this->assertEquals( __( 'Sorry, you are not allowed to assign terms in this taxonomy.' ), $result->message );
     46        $this->assertEquals( __( 'Sorry, you are not allowed to assign this term.' ), $result->message );
    4747    }
    4848
Note: See TracChangeset for help on using the changeset viewer.