WordPress.org

Make WordPress Core

Opened 3 years ago

Last modified 3 months ago

#19834 new feature request

More Robust Capabilities for Attachments

Reported by: walkinonwat3r Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: Media Keywords:
Focuses: Cc:

Description (last modified by scribu)

Attachments/files should have their own set of capabilities mirroring those of posts, in addition to upload_files. Specifically:

  • read_attachments
  • edit_attachments
  • edit_others_attachments
  • delete_attachments
  • delete_others_attachments

Currently, attachments rely on the edit_posts capability, which can create complications if you don't want your users to see the "Posts" sidebar item, or don't want them to be able to delete the attachments they upload.

Change History (30)

comment:2 in reply to: ↑ description ; follow-up: @DrewAPicture3 years ago

  • Cc xoodrew@… added
  • Keywords needs-patch added

Replying to walkinonwat3r:

-edit_attachments
-edit_others_attachments
-delete_attachments
-delete_others_attachments

I agree. Editing posts and editing attachments/media are mutually exclusive. It makes little sense to allow users caps to upload media but not edit it without having to grant them the ability to also edit posts. +1

comment:3 @ocean903 years ago

  • Description modified (diff)

comment:4 in reply to: ↑ 2 ; follow-up: @azaozz3 years ago

Replying to DrewAPicture:

Editing posts and editing attachments/media are mutually exclusive...

Attachments are posts too and have all capabilities as "normal" posts: post_content, taxonomies, meta, comments, etc. Think of them as built-in CPT. Also they are usually attached to a text (normal) post.

In that terms I'm not sure how editing attachments and posts are "mutually exclusive". A user that shouldn't be editing posts (i.e. not trusted) shouldn't be able to edit attachments either.

comment:5 in reply to: ↑ 4 ; follow-up: @DrewAPicture3 years ago

Replying to azaozz:

In that terms I'm not sure how editing attachments and posts are "mutually exclusive". A user that shouldn't be editing posts (i.e. not trusted) shouldn't be able to edit attachments either.

Well, let me give you a simple use case: News websites. Often, you'll have a photo editor or media person adding media to already-existing content. They don't need the ability to edit the written content but they DO need the ability to upload media and edit that media's metadata. And currently, you have to have the edit_posts cap to do that.

What I mean be mutually exclusive is that editing posts is not the same as editing pages is not the same as editing media. They may all be structurally treated as post types but they serve very different purposes.

comment:6 in reply to: ↑ 5 @azaozz3 years ago

Replying to DrewAPicture:

...Often, you'll have a photo editor or media person adding media to already-existing content. They don't need the ability to edit the written content but they DO need the ability to upload media and edit that media's metadata. And currently, you have to have the edit_posts cap to do that.

Not sure this can be achieved without some kind of (advanced) plugin. How would a user insert media in a post without being able to edit that post?

What I mean be mutually exclusive is that editing posts is not the same as editing pages is not the same as editing media. They may all be structurally treated as post types but they serve very different purposes.

Right. We are looking at that from different angles: from user trust/security point of view all of these require a "trusted user". Further granularity of permissions for different post types seems best handled by a plugin (as it is currently).

comment:7 follow-up: @DrewAPicture3 years ago

Replying to azaozz:

Replying to DrewAPicture:

...Often, you'll have a photo editor or media person adding media to already-existing content. They don't need the ability to edit the written content but they DO need the ability to upload media and edit that media's metadata. And currently, you have to have the edit_posts cap to do that.

Not sure this can be achieved without some kind of (advanced) plugin. How would a user insert media in a post without being able to edit that post?

In the case I outlined, content editors pull uploaded content from the Media Library, so the photo people upload the media with all associated EXIF data and that's all they have to do. But once they hit upload, they can't edit any of the associated metadata for that media without giving them edit_posts. That's the problem.

Right. We are looking at that from different angles: from user trust/security point of view all of these require a "trusted user". Further granularity of permissions for different post types seems best handled by a plugin (as it is currently).

This isn't about "further granularity", it's about "should already be there but isn't granularity". Users with the upload_files cap can upload files but not edit them without the edit_posts cap. If you're uploading to the Media Library outside of post edit, Post and Page permissions should have no bearing on whether you have the ability to edit the media you just uploaded (see: @walkinonwat3r's comment:ticket:19817:2). It would be akin to allowing users to submit posts for review but not allowing them to edit their posts after they click submit.

Last edited 3 years ago by DrewAPicture (previous) (diff)

comment:8 follow-up: @mtwelve3 years ago

Another example is when using Media items with Custom Post Types

I have a CPT that requires files to be attached to it. The person in charge of this CPT doesn't need any access to Posts but even if I hide the menu items they will still be able to access those sections. Ideally I could give them the capability to just manage attachments.

Anything we can do to promote this problem!?

comment:9 in reply to: ↑ 8 @scribu3 years ago

Replying to mtwelve:

I have a CPT that requires files to be attached to it. The person in charge of this CPT doesn't need any access to Posts but even if I hide the menu items they will still be able to access those sections.

You can assign different capabilities for that CPT by using the 'capabilities' option from register_post_type().

In general, the capabilities for editing a CPT are already separate from those required to edit attachments, so this ticket doesn't really help you.

comment:10 @scribu3 years ago

In #20802 it was noted that there should also be a 'read_attachments' capability, just like we have a 'read' cap for posts.

comment:11 @scribu3 years ago

  • Description modified (diff)

comment:12 @joostdekeijzer3 years ago

  • Cc joost@… added

comment:13 follow-up: @joostdekeijzer3 years ago

Perhaps to 'promote' the issue:

In a default WordPress installation, a contributor can't set a "featured image". The 'Set featured image' window opens, but the users gets a 'You don't have permission to upload files.' message.

comment:14 @artychan3 years ago

I would also really like to see this added. I (and many others) use WordPress as a CMS for websites and rather than editing posts, contributors added to edit pages. In many of these cases, at the very least, they should have the ability to edit/delete their own media. However, even with custom roles/plugins/etc. I cannot give users the ability to edit/delete even their own media without giving them the related posts permissions.

Version 0, edited 3 years ago by artychan (next)

comment:15 in reply to: ↑ 7 ; follow-up: @azaozz3 years ago

Replying to DrewAPicture:

In the case I outlined, content editors pull uploaded content from the Media Library, so the photo people upload the media with all associated EXIF data and that's all they have to do. But once they hit upload, they can't edit any of the associated metadata for that media without giving them edit_posts. That's the problem.
...
This isn't about "further granularity"...

Lets go step by step:

  • The author writes a post.
  • The photo guy uploads a photo.
  • The editor (or the author) inserts the photo in the post.

So who decides on what goes in the attachment title, caption and description? The photo guy? Also after the new post is published does the photo guy need the right to edit title, caption and description?

That's where more granular permissions come in effect: you may want to give the photo guy permission to only edit "unattached" attachments, or only edit attachment meta, tags, etc.

comment:16 in reply to: ↑ 15 @mikeschinkel3 years ago

  • Cc mikeschinkel@… added

Replying to azaozz:

That's where more granular permissions come in effect: you may want to give the photo guy permission to only edit "unattached" attachments, or only edit attachment meta, tags, etc.

The current system works well for basic blogging but breaks down when requirements get really complex. I could envision literally thousands of capabilities that might be needed for a given scenario which would be overwhelming to manage.

Here's a potential solution: add a special capability called 'in_context' which would determine if a user "can" based on hooks rather than a matching of roles to capabilities? Here's what current_user_can() might look like:

function current_user_can( $capability  ) {
  $current_user = wp_get_current_user();

  if ( 'in_context' == $capability )
    return apply_filters( 'current_user_can_in_context', false, $current_user );

  if ( empty( $current_user ) )
    return false;

  $args = array_slice( func_get_args(), 1 );
  $args = array_merge( array( $capability ), $args );

  return call_user_func_array( array( $current_user, 'has_cap' ), $args );
}

Then for areas in core where you don't want to define a specific role you could wrap with an if (current_user_can('in_context')) { // do something... }, i.e.:

add_action( 'current_user_can_in_context', 'my_current_user_can_in_context', 10, 2 );
function my_current_user_can_in_context( $user_can, $current_user ) {
  global $pagenow;
  return is_admin() && 'upload.php' == $pagenow && 
    in_array( 'photo_editor', $current_user->roles );
}
if (current_user_can('in_context') ) {
  echo 'Yes you can!';
}

This would allow people to write hooks for all those weird special cases and still keep the list of core capabilities relatively clean.

Anyway, it's just an idea. It might have a lot problems I hadn't considered but if not, maybe it's a solution?

comment:17 @ardathksheyna3 years ago

  • Cc ardathksheyna added

comment:18 @dennisderoo3 years ago

  • Cc dennisderoo added

i've found out the solution (hack) for this:

function crunchhack() {

    global $wp_post_types;
    $wp_post_types['attachment']->cap->edit_post = 'upload_files';

}
add_action( 'init', 'crunchhack' );

comment:19 follow-up: @barrykooij3 years ago

  • Cc b.kooij@… added

I would also really like to see custom capabilities for managing media.

In my case I've got a CPT with custom capabilities. The role only has permission to view/edit/delete these CPT items, but must also be able to manage media items (featured image, but also deleting previous uploaded images in the media library). The only option at the moment is granting the role access to editing posts, what I don't want to.

I've edited @dennisderoo code to let a role manage media items when he has the permission to upload files (upload_files):

public function fix_media_permissions() {
    global $wp_post_types;
    $wp_post_types['attachment']->cap->edit_post = 'upload_files';
    $wp_post_types['attachment']->cap->delete_posts = 'upload_files';
}
add_action( 'admin_init',  'fix_media_permissions' );

comment:20 @BandonRandon2 years ago

  • Cc BandonRandon added

+1 but not sure if attachment is the right prefix. It seems that edit_files and upload_files allows for everything except for delete files which appears to be done with delete_posts and delete_others_post so maybe the only real capability we need to add is delete_files

Whatever the solution it would be great to see this fixed not sure why I have to give my custom role (which doesn't have access to post) the capability of delete_post to delete files.

comment:21 @wesrice23 months ago

+1 for better capability association with media.

We know that technically speaking, attachments are posts, which from what I can tell is the reasoning for having to add a capability of 'edit_posts' for a user to be able to edit attachments to begin with.

However, attachments are a custom post type. They have different properties than the posts post type. Pages are a different post type and have separate capabilities, so why wouldn't attachments?

The existence of a custom capability for 'edit_files' is a logical assumption by developers that should be honored from a user experience perspective.

Also, a better naming convention of attachments vs files seems appropriate given the current state of WP.

comment:22 @rhurling16 months ago

This ticket seems to be related to #8234
Maybe Duplicate or something like that?

Either way +1 for the ticket, was just searching if there's a ticket for this

comment:23 @SergeyBiryukov16 months ago

#8234 was marked as a duplicate.

comment:24 in reply to: ↑ 13 @SergeyBiryukov14 months ago

Replying to joostdekeijzer:

In a default WordPress installation, a contributor can't set a "featured image". The 'Set featured image' window opens, but the users gets a 'You don't have permission to upload files.' message.

Related: #28327

comment:25 @ericlewis13 months ago

@azaozz, @drewapicture: if either of you would like to summarize the discussion and give some forward-looking direction for this ticket, that'd be great.

comment:26 @ericlewis13 months ago

  • Keywords needs-patch removed

comment:27 @Solinx10 months ago

Considering Wordpress aspires to become a real CMS, wouldn't it be time to fix this issue in 4.0?

comment:28 @joostdekeijzer5 months ago

I think there are currently two scenario's related to the attachment capabilities in this thread:

  1. The "Photo Editor" scenario
  2. The "Custom Post Type with attached media" scenario

Both will need some kind of *_attachment capabilities.

In the CPT scenario, there is no need for further granulation of the capabilities: the current set will be enough.

The PE scenario is more complicated and probably will need granulation but I guess it will always be an extension of the CPT scenario.

Would it be an idea to first add the *_attachment capabilities (for the CPT scenario) and later extend this when there is consensus on the PE scenario?

comment:29 in reply to: ↑ 19 @husobj3 months ago

Replying to barrykooij:

In my case I've got a CPT with custom capabilities. The role only has permission to view/edit/delete these CPT items, but must also be able to manage media items (featured image, but also deleting previous uploaded images in the media library). The only option at the moment is granting the role access to editing posts, what I don't want to.

I've just encountered this issue too.
I have a user who is allowed to edit a CPT, but not edit Posts.
They can add media as required to insert into their CPT posts, but they are not able to delete media.

It does seem a bit odd linking the capability to delete media to edit_posts.
If feels like media should have it's own delete capabilities or if attached to a CPT, inherit the capabilities of that rather than Posts.

comment:30 @Stagger Lee3 months ago

Can something of these help you ?

// Show only own items in media uploader
add_filter('ajax_query_attachments_args', 'sb_my_attachments_only');

function sb_my_attachments_only($query) {
if ($user_id = get_current_user_id()) {
if (!current_user_can('administrator')) {
$query['author'] = $user_id;
}
}

return $query;
}
function filter_my_attachments( $wp_query ) {
    if (is_admin() && ($wp_query->query_vars['post_type'] == 'attachment')) {
        if ( !current_user_can( 'activate_plugins' ) ) {
            global $current_user;
            $wp_query->set( 'author', $current_user->id );
        }
    }
}
add_filter('parse_query', 'filter_my_attachments' );
// Set a maximum upload count for users on a specific user role:
add_filter( 'wp_handle_upload_prefilter', 'limit_uploads_for_user_roles' );
 
function limit_uploads_for_user_roles( $file ) {
  $user = wp_get_current_user();
  // add the role you want to limit in the array
  $limit_roles = array('contributor');
  $filtered = apply_filters( 'limit_uploads_for_roles', $limit_roles, $user );
  if ( array_intersect( $limit_roles, $user->roles ) ) {
    $upload_count = get_user_meta( $user->ID, 'upload_count', true ) ? : 0;
    $limit = apply_filters( 'limit_uploads_for_user_roles_limit', 10, $user,$upload_count, $file );
    if ( ( $upload_count + 1 ) > $limit ) {
      $file['error'] = __('Upload limit has been reached for this account!','yourtxtdomain');
    } else {
      update_user_meta( $user->ID, 'upload_count', $upload_count + 1 );
    }
  }
  return $file;
}
// This action will fire when user delete attachment (countdown):
add_action('delete_attachment', 'decrease_limit_uploads_for_user');
function decrease_limit_uploads_for_user( $id ) {
   $user = wp_get_current_user();
   // add the role you want to limit in the array
   $limit_roles = array('contributor');
   $filtered = apply_filters( 'limit_uploads_for_roles', $limit_roles, $user );
   if ( array_intersect( $limit_roles, $user->roles ) ) {
     $post = get_post( $id);
     if ( $post->post_author != $user->ID ) return;
     $count = get_user_meta( $user->ID, 'upload_count', true ) ? : 0;
     if ( $count ) update_user_meta( $user->ID, 'upload_count', $count - 1 );
   }
}
// Limit user upload by KB size:
add_filter('wp_handle_upload_prefilter', 'f711_image_size_prevent');
function f711_image_size_prevent($file) {

    // get filesize of upload
    $size = $file['size'];
    $size = $size / 1024; // Calculate down to KB

    // get imagetype of upload
    $type = $file['type'];
    $is_image = strpos($type, 'image');

    // set sizelimit
    $limit = 700; // Your Filesize in KB

    // set imagelimit
    $imagelimit = 7;

    // set allowed imagetype
    $imagetype = 'image/jpeg';

    // query how many images the current user already uploaded
    global $current_user;
    $args = array(
        'orderby'         => 'post_date',
        'order'           => 'DESC',
        'numberposts'     => -1,
        'post_type'       => 'attachment',
        'author'          => $current_user->ID,
    );
    $attachmentsbyuser = get_posts( $args );

    if ( ( $size > $limit ) && ($is_image !== false) ) { // check if the image is small enough
        $file['error'] = 'Image files must be smaller than '.$limit.'KB';
    } elseif ( $type != $imagetype ) { // check if image type is allowed
        $file['error'] = 'Image must be ' . $imagetype . '.';
    } elseif ( count( $attachmentsbyuser ) >= $imagelimit ) { // check if the user has exceeded the image limit
        $file['error'] = 'Image limit of ' . $imagelimit . ' is exceeded for this user.';
    }
    return $file;

}
function ter_limit_image_uploads($file){
	$error_message = 'KB is to large. Please reduce the file size of your image to ' . TER_MAX_IMAGE_SIZE_KB . 'KB or less. Hosting space is limited and uploading large images will slow down your page loads. Use a tool such as http://toki-woki.net/p/Shrink-O-Matic/ to help you to resize your images. Target size: Width 1024px, file size 100KB-200KB';
	$size_in_kb = $file['size'] / 1024;
	if(preg_match('/image/',$file['type']))	if($size_in_kb > TER_MAX_IMAGE_SIZE_KB) $file['error'] = round($size_in_kb,2) . $error_message;
	return $file;	
}
add_filter('wp_handle_upload_prefilter','ter_limit_image_uploads');		//Limit uploaded image size

Tested and they work well.
Administrator is excluded from these rules.

Last edited 3 months ago by Stagger Lee (previous) (diff)
Note: See TracTickets for help on using tickets.