Make WordPress Core

Changeset 38698


Ignore:
Timestamp:
09/30/2016 10:39:32 PM (10 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.