Make WordPress Core

Opened 14 years ago

Closed 12 years ago

#16714 closed task (blessed) (fixed)

Introduce capabilities for adding new posts

Reported by: nacin's profile nacin Owned by: casben79's profile casben79
Milestone: 3.5 Priority: normal
Severity: normal Version:
Component: Role/Capability Keywords: needs-docs has-patch commit
Focuses: Cc:

Description

Many plugins need to be able to deny the creation of new items, particularly for CPT use cases. Unfortunately this is not easy to do.

I am suggesting a new cap for adding posts. Obviously, this has the potential to break quite a number of custom roles, but I think we can avoid that.

Instead, it would by default simply map to edit_posts. It wouldn't actually get assigned to any roles, so it's more or less a meta cap. (Only, without an $id, because it'd be a new post even pre-auto-draft in some cases.) But it then opens up the ability for this to be filtered by a plugin.

We could also potentially add this to the CPT capabilities array, but with the default being 'add_posts' => 'edit_posts'. Ultimately there are a few ways to implement this.

Ideally, the cap should be used for the admin menu, for post-new.php, for the 'Add New' button (no more clunky hiding it via CSS), XML-RPC, and the post handler for post-new.

Attachments (14)

16714.diff (27.0 KB) - added by casben79 13 years ago.
Initial Attempt
16714.2.diff (16.6 KB) - added by casben79 13 years ago.
Most of my neat formatting removed and create_links and co removed
16714.3.diff (1.3 KB) - added by nacin 12 years ago.
16714.4.diff (1.9 KB) - added by scribu 12 years ago.
add-new.diff (3.3 KB) - added by nacin 12 years ago.
16714.5.diff (4.7 KB) - added by ryan 12 years ago.
add-new.diff with some additions
16714-ut.diff (772 bytes) - added by ryan 12 years ago.
16714.6.diff (4.8 KB) - added by ryan 12 years ago.
Custom edit_posts should be used for create_posts if create_posts not specified
16714.7.diff (2.3 KB) - added by johnbillion 12 years ago.
16714.8.diff (687 bytes) - added by johnbillion 12 years ago.
16714.9.diff (1.3 KB) - added by johnbillion 12 years ago.
16714.10.diff (2.0 KB) - added by johnbillion 12 years ago.
16714.11.diff (4.9 KB) - added by nacin 12 years ago.
Remove the awkward meta cap, which isn't filterable anyway, because most references are to the post type object.
16714.12.diff (594 bytes) - added by nacin 12 years ago.

Download all attachments as: .zip

Change History (72)

#1 @johnjamesjacoby
14 years ago

+1 - The bbPress plugin and future BuddyPress versions will need to take advantage of something like this.

#2 @scribu
14 years ago

+1 as well.

#3 @scribu
14 years ago

Related: #16808

#4 @Bueltge
14 years ago

  • Cc frank@… added

+10
current it is many code for add own caps; a example

			foreach ( $snippet_roles as $snippet_role ) {
				$wp_roles->add_cap( $snippet_role, 'edit_' . $this->post_type_1 );
				$wp_roles->add_cap( $snippet_role, 'edit_' . $this->post_type_1 . 's' );
				$wp_roles->add_cap( $snippet_role, 'edit_others_' . $this->post_type_1 . 's' );
				$wp_roles->add_cap( $snippet_role, 'publish_' . $this->post_type_1 . 's' );
				$wp_roles->add_cap( $snippet_role, 'read_' . $this->post_type_1 );
				$wp_roles->add_cap( $snippet_role, 'read_private_' . $this->post_type_1 . 's' );
				$wp_roles->add_cap( $snippet_role, 'delete_' . $this->post_type_1 );
				$wp_roles->add_cap( $snippet_role, 'manage_' . $this->taxonomy_type_1 );
			}
			
			$wp_roles->add_cap( 'author', 'read_' . $this->post_type_1 );
			$wp_roles->add_cap( 'contributor', 'read_' . $this->post_type_1 );
			$wp_roles->add_cap( 'subscriber', 'read_' . $this->post_type_1 );

#5 @hakre
14 years ago

Introducing add_posts with defaulting to edit_posts sounds pretty straight forward to me. Should not only make the menu more modular.

#6 @scribu
14 years ago

The add_post capability could also be used instead of "> level_0" hack we use in the author dropdowns. See #16841

#7 @kevinB
14 years ago

  • Cc kevin@… added

+1

#8 @scribu
14 years ago

  • Keywords needs-patch added; dev-feedback removed
  • Milestone changed from Awaiting Review to 3.2

#9 @scribu
13 years ago

By the way, I think 'create_posts' would be a more intuitive name.

Last edited 13 years ago by scribu (previous) (diff)

#10 @casben79
13 years ago

  • Owner set to casben79
  • Status changed from new to accepted

Ill Take this one on if noone minds :)

First draft diff attached.

Some cleaning up and readability while I was looking at the files

Also is there any use case for create_links?

Cheers
Ben

@casben79
13 years ago

Initial Attempt

#11 @scribu
13 years ago

I think it would be best if we completely ignore create_links and co.

Also, please refrain from doing whitespace cleanup that isn't directly related to this ticket, especially considering we don't have a standard for that yet:

http://wpdevel.wordpress.com/2011/04/04/to-the-directors-of-white-space/

#12 @kevinB
13 years ago

Is the post creation capability to be governed independent of post editing? If so, the admin menu for each post type will need to be displayed if the user has edit_posts OR create_posts. But the current API only supports one required cap per menu:

$menu[5] = array( __('Posts'), 'edit_posts', 'edit.php', '', 'open-if-no-js menu-top menu-icon-post', 'menu-posts', 'div' );
$menu[20] = array( __('Pages'), 'edit_pages', 'edit.php?post_type=page', '', 'menu-top menu-icon-page', 'menu-pages', 'div' );
$menu[$ptype_menu_position] = array( esc_attr( $ptype_obj->labels->menu_name ), $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype", '', 'menu-top menu-icon-' . $ptype_class, 'menu-posts-' . $ptype_for_id, $menu_icon );
foreach ( $menu as $id => $data ) {
	if ( ! current_user_can($data[1]) )
		$_wp_menu_nopriv[$data[2]] = true;

#13 @scribu
13 years ago

@casben79: Cool. By the way, you have some property changes that should be removed before uploading a patch.

@kevinB: That's a very good question.

#14 follow-up: @scribu
13 years ago

  • Keywords has-patch added; needs-patch removed

Actually, the way casben79 did it, create_posts requires you have the edit_posts capability, which seems logical to me, so it shouldn't be a problem.

#15 follow-up: @casben79
13 years ago

@kevinb: Interesting thought, this could be useful for plugin / theme authors as well.

//Guilty untill proven innocent?
    $_wp_menu_nopriv[$data[2]] = true;
    if( is_array( $data[1] ) ){
	foreach( $data[1] as $cap ){
	    if( current_user_can( $cap ) ){
		unset( $_wp_menu_nopriv[$data[2]] );
	    }
	}
    } else {
	if ( current_user_can($data[1]) )
		unset( $_wp_menu_nopriv[$data[2]] );
    }

And then:

$menu[5] = array( __('Posts'), array( 'edit_posts' , 'create_posts' ) , 'edit.php', '', 'open-if-no-js menu-top menu-icon-post', 'menu-posts', 'div' );

What do you think?

#16 in reply to: ↑ 14 @kevinB
13 years ago

Replying to scribu:

Actually, the way casben79 did it, create_posts requires you have the edit_posts capability, which seems logical to me, so it shouldn't be a problem.

I can imagine implementations that would appreciate enabling users to create a post via Quick Press or custom UI without being able to further edit the new draft. As I read it, the current patch actually does support that.

#17 @johnjamesjacoby
13 years ago

Don't forget there's a difference between 'edit_posts' and 'edit_others_posts'

Last edited 13 years ago by johnjamesjacoby (previous) (diff)

@casben79
13 years ago

Most of my neat formatting removed and create_links and co removed

#18 in reply to: ↑ 15 @kevinB
13 years ago

Replying to casben79:

@kevinb: Interesting thought, this could be useful for plugin / theme authors as well.

//Guilty untill proven innocent?
    $_wp_menu_nopriv[$data[2]] = true;
    if( is_array( $data[1] ) ){
	foreach( $data[1] as $cap ){
	    if( current_user_can( $cap ) ){
		unset( $_wp_menu_nopriv[$data[2]] );
	    }
	}
    } else {
	if ( current_user_can($data[1]) )
		unset( $_wp_menu_nopriv[$data[2]] );
    }

And then:

$menu[5] = array( __('Posts'), array( 'edit_posts' , 'create_posts' ) , 'edit.php', '', 'open-if-no-js menu-top menu-icon-post', 'menu-posts', 'div' );

What do you think?

I think supporting creation-only usage of the full post edit form would be nice. But that would take some work in post.php also. At the very least you would need to redirect back to the dashboard following post creation. But wouldn't there also be some complications (edit_posts cap checking) due to auto-creation of new posts?

As it stands in the patch now, a user with create_posts (but not edit_posts) sees no "Add New" menu link but can still access post-new.php by direct URL.

Version 1, edited 13 years ago by kevinB (previous) (next) (diff)

#19 @casben79
13 years ago

Using Members Plugin, Changed the administrator to HAVE create_posts and NOT edit_posts and got "You do not have sufficient permissions to access this page."

create_posts is literally mapping directly to edit_posts, with map_meta_cap filter it could be changed to almost anything.

#20 @ryan
13 years ago

  • Milestone changed from 3.2 to Future Release

#21 @johnbillion
13 years ago

  • Cc johnbillion@… added

#22 @markoheijnen
13 years ago

  • Cc marko@… added

#23 @pauldewouters
12 years ago

  • Cc pauldewouters added

#24 @nacin
12 years ago

  • Milestone changed from Future Release to 3.5

Need this for #21391.

#25 @nacin
12 years ago

16714.2.diff has some problems in map_meta_cap(). Rather than mapping to 'edit_posts', it should map to post_type_object->cap->edit_posts.

Bonus: It should instead map to cap->create_posts, and in get_post_type_capabilities(), cap->create_posts should be set to 'edit_' . $plural_base by default, essentially mapping it on the fly to edit_posts.

Both of these work only if we know the post type. So, we'll probably need to clarify that this can only be used like this:

if ( current_user_can( 'create_post', $post_type ) (or 'create_posts').

If used directly, as in $post_type_object->cap->create_posts, then $post_type isn't necessary. Attached is my thought process so far.

@nacin
12 years ago

#26 @nacin
12 years ago

  • Type changed from enhancement to task (blessed)

Since we need this, it gets saved by freeze. Would like someone to weigh in on 16714.3.diff. We don't really have a similar half-primitive, half-meta capability implementation in core, so the approach could use a critique.

#27 @scribu
12 years ago

I don't see why we need 'create_posts' in 'map_meta_cap'. We should just make sure that $post_type_object->cap->create_posts is always set.

#28 @scribu
12 years ago

Or just get rid of 'create_post', since it doesn't accept a post id, like 'edit_post' or 'delete_post'. Therefore, it shouldn't be singular.

Last edited 12 years ago by scribu (previous) (diff)

#29 @ryan
12 years ago

Looks good. I'm indifferent to whether create_post stays or goes.

@scribu
12 years ago

#30 @scribu
12 years ago

16714.4.diff gets rid of 'create_post' and uses 'create_posts' in wp-admin/menu.php.

Will be a little trickier for custom post type menus.

#31 @ryan
12 years ago

In [22060]:

Introduce create_posts meta capability. Props scribu, nacin, casben79. see #16714

#33 @johnbillion
12 years ago

  • Keywords needs-docs added

#34 @nacin
12 years ago

#21463 was marked as a duplicate.

#35 @nacin
12 years ago

In the end, we actually did not need this for #21391. media.php happens to be accessible without upload_files, but it's a fluke — the Media Library (including the list table at upload.php) is entirely disabled for users who cannot upload files.

@nacin
12 years ago

@ryan
12 years ago

add-new.diff with some additions

@ryan
12 years ago

@ryan
12 years ago

Custom edit_posts should be used for create_posts if create_posts not specified

#37 @ryan
12 years ago

  • Resolution set to fixed
  • Status changed from accepted to closed

#38 @johnbillion
12 years ago

  • Keywords needs-patch added; has-patch removed
  • Resolution fixed deleted
  • Status changed from closed to reopened

We're still using edit_posts instead of create_posts in a couple of places for CPTs. Patch incoming.

@johnbillion
12 years ago

#39 @johnbillion
12 years ago

  • Keywords has-patch added; needs-patch removed

16714.7.diff fixes two issues:

  • Users who have the 'edit_posts' capability but not the 'create_posts' capability still see the 'Add New Post' menu in the admin toolbar. This applies to the 'create_posts' meta capability for all post types.
  • Users who have the 'create_posts' meta capability but not the 'edit_posts' meta capability for a custom post type still see the 'Add New' submenu for the post type in the main menu.

#40 @nacin
12 years ago

  • Keywords commit added

#41 @nacin
12 years ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 22900:

Use create_posts whenever linking to post-new.php. props johnbillion. fixes #16714.

#42 @johnbillion
12 years ago

  • Keywords needs-patch added; has-patch commit removed
  • Resolution fixed deleted
  • Status changed from closed to reopened

Dammit, missed a couple more. Patch incoming.

@johnbillion
12 years ago

#43 @johnbillion
12 years ago

16714.8.diff fixes the cap check for the 'New Post' link in each item of the 'My Sites' menu.

Nacin and I are currently discussing a separate issue with 'create_pages' on IRC.

@johnbillion
12 years ago

#44 @johnbillion
12 years ago

16714.9.diff corrects the check for 'create_pages' in map_meta_cap() and uses this cap in the admin menu.

#45 @johnbillion
12 years ago

  • Keywords has-patch added; needs-patch removed

16714.10.diff adds 'create_post' cap checks into the XML-RPC API where necessary. Props to markoheijnen for pointing this out.

@nacin
12 years ago

Remove the awkward meta cap, which isn't filterable anyway, because most references are to the post type object.

#46 @nacin
12 years ago

In 22908:

Use the create_posts post type cap in more places. Remove the janky create_posts meta cap. see #16714.

#47 @nacin
12 years ago

  • Keywords close added

I'd like to just get a little testing/review on [22908].

@nacin
12 years ago

#48 @nacin
12 years ago

After all that, we should probably do 16714.12.diff... It's not actually necessary because the current cap checks for upload.php (the list table) and the menu items all use upload_files. Only media.php?action=edit&attachment_id= and post.php?action=edit&post= are accessible without upload_files, and not directly through the UI (best I can tell), as long as you can edit that attachment using the standard edit_post cap tree.

In that case, we do an upload_files check on media.php for "Add New". We don't for post.php — that was the point of create_posts. So, 16714.12.diff.

#49 @nacin
12 years ago

  • Keywords commit needs-unit-tests added; close removed

#50 @ryan
12 years ago

There's a unit test failure, even with .12.diff.

1) Tests_User_Capabilities::test_post_meta_caps
Failed asserting that false is true.

/.../unit-tests/trunk/Tests/User/Capabilities.php:490

#51 @nacin
12 years ago

In [UT1159]: Update capabilities test to reflect that create_posts is not a real cap, but rather an alias on the post type object.

#52 @nacin
12 years ago

[UT1160]: Basic tests for the attachment post type having a different capability for create_posts than edit_posts.

This test fails without the final patch here.

#53 @nacin
12 years ago

  • Keywords needs-unit-tests removed

#54 @ryan
12 years ago

Looks good.

#55 @ryan
12 years ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 22921:

Map the create_posts post type cap to upload_files for attachments.

Props nacin
fixes #16714

#56 follow-up: @mdgl
12 years ago

  • Resolution fixed deleted
  • Status changed from closed to reopened

You may also wish to check file index.php in the TwentyTwelve theme. This makes use of current_user_can('edit_posts') to output a different message so that suitably empowered users can quickly add a first post to their blog.

#57 in reply to: ↑ 56 @SergeyBiryukov
12 years ago

Replying to mdgl:

You may also wish to check file index.php in the TwentyTwelve theme.

create_posts meta capability is new in 3.5. I guess Twenty Twelve should be left as is, since it's also supposed to work with 3.4.

#58 @nacin
12 years ago

  • Resolution set to fixed
  • Status changed from reopened to closed

I agree, no reason to touch 3.5.

The idea of blocking someone from creating posts of the "post" post type is still very nascent anyway.

Note: See TracTickets for help on using tickets.