Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Advanced WordPress Development: Capabilities (WordCamp Philly 2011)

nacin
November 05, 2011

Advanced WordPress Development: Capabilities (WordCamp Philly 2011)

Advanced WordPress Development: Capabilities, and tweaking them through unconventional means. WordCamp Philadelphia 2011.

nacin

November 05, 2011
Tweet

Other Decks in Technology

Transcript

  1. WordCamp Philadelphia 2011
    November 5, 2011

    View full-size slide

  2. Andrew Nacin
    Core Developer of WordPress
    Tech Ninja at Audrey Capital
    [email protected]
    @nacin on Twitter

    View full-size slide

  3. Advanced WordPress
    Development
    @nacin

    View full-size slide

  4. Capabilities
    and tweaking them through
    unconventional means
    @nacin

    View full-size slide

  5. What do you know?
    @nacin

    View full-size slide

  6. Modifying Roles and
    Capabilities in the DB
    get_role( ), add_role( ),
    add_cap( ), remove_cap( ), etc.
    @nacin

    View full-size slide

  7. Boring, and has
    drawbacks.
    @nacin

    View full-size slide

  8. Who has heard of
    current_user_can( )?
    What happens when you call it?
    @nacin

    View full-size slide

  9. current_user_can( ) :
    $user = wp_get_current_user( );
    return $user->has_cap( $args );
    (Core functions are often simplified in this talk.)
    @nacin

    View full-size slide

  10. What don't you know?
    @nacin

    View full-size slide

  11. Every call goes through
    very powerful filters
    user_has_cap
    map_meta_cap
    @nacin

    View full-size slide

  12. Why should I care?
    What can I use them for?
    Let's dig in.
    @nacin

    View full-size slide

  13. WP_User's has_cap( ) method:
    $required_caps = map_meta_cap( $args );
    // Multisite super admin has all caps, unless denied.
    if ( is_multisite( ) && is_super_admin( $user_id ) )
    return ! in_array( 'do_not_allow', $required_caps );
    $caps_user_has = apply_filters( 'user_has_cap',
    $caps_user_has, $required_caps, $args );
    // Must have all required caps
    foreach ( $caps_user_has as $cap )
    if ( empty( $caps_user_has[ $cap ] ) )
    return false;
    return true;

    View full-size slide

  14. WP_User's has_cap( ) method:
    $required_caps = map_meta_cap( $args );

    View full-size slide

  15. WP_User's has_cap( ) method:
    $required_caps = map_meta_cap( $args );
    // Multisite super admin has all caps, unless denied.
    if ( is_multisite( ) && is_super_admin( $user_id ) )
    return ! in_array( 'do_not_allow', $required_caps );

    View full-size slide

  16. WP_User's has_cap( ) method:
    $required_caps = map_meta_cap( $args );
    // Multisite super admin has all caps, unless denied.
    if ( is_multisite( ) && is_super_admin( $user_id ) )
    return ! in_array( 'do_not_allow', $required_caps );
    $caps_user_has = apply_filters( 'user_has_cap',
    $caps_user_has, $required_caps, $args );

    View full-size slide

  17. WP_User's has_cap( ) method:
    $required_caps = map_meta_cap( $caps );
    // Multisite super admin has all caps, unless denied.
    if ( is_multisite( ) && is_super_admin( $user_id ) )
    return ! in_array( 'do_not_allow', $required_caps );
    $caps_user_has = apply_filters( 'user_has_cap'
    $caps_user_has, $required_caps, $args );
    // Must have all required caps
    foreach ( $caps_user_has as $cap )
    if ( empty( $caps_user_has[ $cap ] ) )
    return false;
    return true;

    View full-size slide

  18. If you can edit pages, you can edit widgets:
    add_filter( 'user_has_cap', function( $caps ) {
    if ( ! empty( $caps[ 'edit_pages' ] )
    $caps[ 'edit_theme_options' ] = true;
    return $caps;
    } );

    View full-size slide

  19. Give secondary "administrators" less control:
    add_filter( 'user_has_cap',
    function( $caps, $required_caps, $args ) {
    $user_id = $args[1];
    $user = new WP_User( $user_id );
    if ( $user->user_email !=
    get_option( 'admin_email' ) )
    $caps[ 'manage_options' ] = false;
    return $caps;
    },
    10, 3 );

    View full-size slide

  20. Chapter 2
    What's a meta capability?
    @nacin

    View full-size slide

  21. You have standard,
    primitive capabilities
    @nacin

    View full-size slide

  22. edit_posts
    — Contributors, Authors, Editors have this.
    @nacin

    View full-size slide

  23. edit_posts
    — Contributors, Authors, Editors have this.
    edit_published_posts
    — Is the post published?
    — Authors, Editors have this.
    @nacin

    View full-size slide

  24. edit_posts
    — Contributors, Authors, Editors have this.
    edit_published_posts
    — Is the post published?
    — Authors, Editors have this.
    edit_private_posts
    — Is the post private?
    — Editors have this.
    @nacin

    View full-size slide

  25. edit_posts
    — Contributors, Authors, Editors have this.
    edit_published_posts
    — Is the post published?
    — Authors, Editors have this.
    edit_private_posts
    — Is the post private?
    — Editors have this.
    edit_others_posts
    — Are you not the post author?
    — Editors have this.
    @nacin

    View full-size slide

  26. Meta caps are singular, and roles
    should never be assigned them.
    — edit_post, delete_post, read_post
    —delete_user, edit_user
    @nacin

    View full-size slide

  27. Meta caps are singular, and roles
    should never be assigned them.
    — edit_post, delete_post, read_post
    —delete_user, edit_user
    Primitive caps are plural, and roles
    have these.
    — edit_posts, edit_published_posts
    —delete_users, edit_users
    @nacin

    View full-size slide

  28. Meta caps get converted to
    primitive caps based on
    context.
    @nacin

    View full-size slide

  29. If you do:
    current_user_can( 'edit_post', $post_id )
    meta capability ^ context ^
    map_meta_cap() translates this to, e.g.:
    array( 'edit_posts' )
    If the post is published and not by you:
    array( 'edit_published_posts',
    'edit_others_posts' )
    @nacin

    View full-size slide

  30. map_meta_cap( ) only
    determines what
    capabilities the user needs.
    @nacin

    View full-size slide

  31. WP_User's has_cap( ) method:
    $required_caps = map_meta_cap( $args );
    // Multisite super admin has all caps, unless denied.
    if ( is_multisite( ) && is_super_admin( $user_id ) )
    return ! in_array( 'do_not_allow', $required_caps );
    $caps_user_has = apply_filters( 'user_has_cap',
    $caps_user_has, $required_caps, $args );
    // Must have all required caps
    foreach ( $caps_user_has as $cap )
    if ( empty( $caps_user_has[ $cap ] ) )
    return false;
    return true;

    View full-size slide

  32. Don't let anyone delete users from the UI:
    // apply_filters( 'map_meta_cap', $required_caps,
    $queried_cap, $user_id, $args );
    add_filter( 'map_meta_cap',
    function( $required_caps, $queried_cap ) {
    if ( 'delete_user' == $queried_cap ||
    'delete_users' == $queried_cap )
    $required_caps[] = 'do_not_allow';
    return $required_caps;
    }, 10, 2 );

    View full-size slide

  33. Only administrators can delete published posts:
    add_filter( 'map_meta_cap',
    function( $required_caps, $queried_cap ) {
    if ( 'delete_post' == $queried_cap )
    $required_caps[] = 'manage_options';
    return $required_caps;
    }, 10, 2 );

    View full-size slide

  34. Don't allow file changes via the UI:
    add_filter( 'map_meta_cap',
    function( $required_caps, $queried_cap ) {
    if ( in_array( $queried_cap, array(
    'edit_themes', 'edit_plugins',
    'update_themes', 'update_plugins',
    'install_themes', 'install_plugins',
    'update_core' ) )
    $required_caps[] = 'do_not_allow';
    return $required_caps;
    }, 10, 2 );

    View full-size slide

  35. (That is built into core, by the way...)
    // deny edit_themes, edit_plugins
    define( 'DISALLOW_FILE_EDIT', true );
    // deny all file changes
    define( 'DISALLOW_FILE_MODS', true );

    View full-size slide

  36. Require editors to approve posts:
    add_filter( 'map_meta_cap',
    function( $required_caps, $queried_cap ) {
    if ( $queried_cap == 'publish_posts' )
    $required_caps[] = 'edit_others_posts';
    return $required_caps;
    }, 10, 2 );

    View full-size slide

  37. map_meta_cap( ) is an
    extensive, powerful
    function.
    wp-includes/capabilities.php
    @nacin

    View full-size slide

  38. // mapping for current_user_can( 'edit_post', $post_id )
    case 'edit_post' :
    if ( $user_id == $post_author->ID ) { // Are we the author?
    if ( 'publish' == $post->post_status )
    $caps[] = $post_type->cap->edit_published_posts;
    else
    $caps[] = $post_type->cap->edit_posts;
    } else {
    // The user is trying to edit someone else's post.
    $caps[] = $post_type->cap->edit_others_posts;
    // If the post is published, extra caps are required.
    if ( 'publish' == $post->post_status )
    $caps[] = $post_type->cap->edit_published_posts;
    elseif ( 'private' == $post->post_status )
    $caps[] = $post_type->cap->edit_private_posts;
    }
    . . .
    return apply_filters( 'map_meta_cap', $caps, ... );

    View full-size slide

  39. $post_type->cap->edit_posts;
    Oooh, post types.
    @nacin

    View full-size slide

  40. Chapter 3
    How can you leverage
    capabilities with post types?
    @nacin

    View full-size slide

  41. Where you are leveraging the same
    *_posts capabilities:
    register_post_type( 'book', array(
    . . .
    'capability_type' => 'post',
    // Implied for 'post' and 'page' :
    'map_meta_cap' => true,
    . . .
    );

    View full-size slide

  42. Where you are assigning *_books
    capabilities to users:
    register_post_type( 'book', array(
    . . .
    'capability_type' => 'book',
    // Map edit_book (and read, delete)
    'map_meta_cap' => true,
    . . .
    );

    View full-size slide

  43. Hey, plural forms too:
    register_post_type( 'story', array(
    . . .
    'capability_type' =>
    array( 'story', 'stories' )
    // Map edit_story (and read,
    delete) to edit_stories, etc.
    'map_meta_cap' => true,
    );

    View full-size slide

  44. Go crazy with full customizations:
    register_post_type( 'article', array(
    . . .
    'capabilities' => array(
    // primitive capabilities assigned to users
    'read' => 'read',
    'edit_posts' => 'edit_articles',
    'publish_posts' => 'edit_articles',
    // lock them down once published
    'edit_published_posts' => 'do_not_allow',
    'delete_posts' => 'do_not_allow',
    'delete_others_posts' => 'do_not_allow',
    'delete_published_posts' => 'do_not_allow',
    // meta capabilities
    'edit_post' => . . .

    View full-size slide

  45. Review
    user_has_cap filter
    Explicitly granting or denying users
    a capability.
    map_meta_cap filter
    Translating a capability into the
    capabilities required, depending on
    the context.
    @nacin

    View full-size slide

  46. And finally:
    register_post_type( )
    You can customize mapping and
    capabilities when registering a post type.
    map_meta_cap( )
    Read it. It's worth it.
    get_post_type_capabilities( )
    Read the documentation in
    wp-includes/post.php.
    @nacin

    View full-size slide

  47. Thanks! Questions?
    @nacin

    View full-size slide