Ticket #12706 (new feature request)
Custom post status bugs in the admin
Reported by: |
|
Owned by: |
|
---|---|---|---|
Priority: | normal | Milestone: | Future Release |
Component: | Post Types | Version: | |
Severity: | normal | Keywords: | has-patch westi-likes 3.4-early |
Cc: | sbressler@…, johnkolbert, johnbillion@…, kevinB, mikeschinkel@…, andreasnrb, piemanek@…, aesqe@…, ninnypants, mailings@…, danielbachhuber@…, r@…, clemsos, zack@…, bergius.tobias@…, knut@…, me@…, d@…, simon@…, gcorne@…, lightningspirit@…, sidewindernet, alexkingorg@…, batmoo@…, flexicon, sirzooro |
Description
Bug 1: Registering a post status via register_post_status() doesn't show the new status anywhere in the admin.
Bug 2: Post statuses should be registered to one or more post types.
Attachments
Change History
comment:1
ptahdunbar — 22 months ago
comment:4
ptahdunbar — 21 months ago
- Severity changed from blocker to normal
- Milestone changed from 3.0 to 3.1
Don't have time for this so I'm pushing it back for 3.1 unless someone can tackle it :)
- Type changed from defect (bug) to enhancement
I don't see this as a bug. We simply never completed the API here.
Very similar to how we started custom post types in 2.9 then went through it with 3.1.
Moving to enhancement... Will probably end up as a task though.
comment:6
johnkolbert — 21 months ago
- Cc johnkolbert added
Related and in progress: http://core.trac.wordpress.org/ticket/12567
comment:7
johnkolbert — 21 months ago
Just to let those know who are following this ticket, I just updated the diff file to this related trac ticket (http://core.trac.wordpress.org/ticket/12567) and would enjoy any feed back.
comment:10
nacin — 17 months ago
- Type changed from enhancement to task (blessed)
- Milestone changed from Awaiting Triage to 3.1
Someone is free to start working on this before I get to it.
I want post statuses to be registered to a post type. That's one thing that gets me.
We also have like 18 properties but still need more based on things I noticed when trying to utilize what was there. So we should figure out a way to properly handle everything.
comment:12
andreasnrb — 16 months ago
- Cc andreasnrb added
Think we need to do a write up of what the different options actually do. Supposed difference between public, private, protected. _builtin and internal etc. Public,private,protected makes custom post type with that status show up on its listings page.
The All(x) link always show the total count for the post type even with a unregistered post_status but the page display No post types found.
comment:13
nacin — 16 months ago
#14318 was previously closed as a duplicate.
comment:15
ptahdunbar — 15 months ago
Alright, let's get this ticket moving. There's a few args in the current version of register_post_status that either make no sense, are redundant, or ones that I just don't understand and could use some clarification.
Here's the new params for the register function:
register_post_status( $post_status, $post_type, $args = array() );
Parameters:
- $post_status (string) - Name of the post status.
- $post_type (mixed) - string or array of post types to assign to the post status.
- $args (array) - Optional.
Public args:
- label - A descriptive name for the post status. Defaults to $post_status
- label_count - Label used in the admin status links to display the post status' singular/plural count label. Defaults to label
- post_type - An array containing post types this post status is associated with. Defaults to 'any'.
- exclude_from_search - Whether to exclude posts with this post status from search results. Defaults to null.
- public - Whether posts of this type should be shown in the admin UI. Defaults to null.
- internal - Whether the post status is internal. Removes from any ui/query listing.
- protected - User must have edit permissions on the draft to preview. Defaults to null.
- private - Limited to viewing by the author of a post or someone who has caps to read private states. Defaults to null.
- publicly_queryable - Whether post status queries can be performed from the front page. Defaults to null.
- show_ui - Whether to show the post status in the admin UI. Defaults to null.
- edit_cap: changing the post status can be limited by capability. If set, users must have the declared capability to change change posts to this post status. Defaults to null.
Internal args: (Used by WP core built-in post statuses)
- _builtin - If this post status is a native or "built-in".
Args I left out: (can anyone explain the need for these?)
- show_in_admin_all
- show_in_admin_status_list
- show_in_admin_all_list (uses show_ui instead)
- single_view_cap
- capability_type
- hierarchical
- _edit_link
Functions that (most likely) need updates:
- get_available_post_statuses
- wp_edit_posts_query
- get_post_statuses
- get_page_statuses
- post_submit_meta_box
Files that need updates
- edit.php:261
- export.php:55,:132 (do we need a can_export arg?)
- query.php:2234
- script-loader.php & post.dev.js
See #12567
Thoughts?
comment:16
wpmuguru — 15 months ago
There shouldn't be a separate function for page statuses. Pages are now just another post type other than WordPress needs to support features from when they were distinct.
The post type already has a can_export flag. The post status should depend on the post type flag for this. Though, this raises the issue of conditionally showing the post status on the export screen when it only applies to specific post types.
comment:17
nacin — 15 months ago
get_page_statuses() is for back compat. I think get_page_statuses() and get_post_statuses() are only used in XML-RPC. They have hard-coded stati for that reason.
comment:18
follow-up:
↓ 19
kevinB — 15 months ago
Can we please default post_type to null? This is the standard approach for everything except the query variable, making
! empty ($status_obj->post_type)
sufficient to detect post_type customization in 3.0 and 3.1+
comment:19
in reply to:
↑ 18
;
follow-up:
↓ 20
ptahdunbar — 15 months ago
Replying to kevinB:
Can we please default post_type to null? This is the standard approach for everything except the query variable, making
! empty ($status_obj->post_type)sufficient to detect post_type customization in 3.0 and 3.1+
The post_type param is required as your registering a post status to a post type. Defaulting to null means that the post status shouldn't register.
comment:20
in reply to:
↑ 19
;
follow-up:
↓ 21
kevinB — 15 months ago
Replying to ptahdunbar:
Replying to kevinB:
Can we please default post_type to null? This is the standard approach for everything except the query variable, making
! empty ($status_obj->post_type)sufficient to detect post_type customization in 3.0 and 3.1+
The post_type param is required as your registering a post status to a post type. Defaulting to null means that the post status shouldn't register.
That breaks the API for plugins and themes which were written for WP 3.0. Why not make post_type part of the args array? Then calling code can associate the status with all post types if the property is defaulted null or not set.
comment:21
in reply to:
↑ 20
kevinB — 15 months ago
Replying to kevinB:
Replying to ptahdunbar:
The post_type param is required as your registering a post status to a post type. Defaulting to null means that the post status shouldn't register.
That breaks the API for plugins and themes which were written for WP 3.0. Why not make post_type part of the args array? Then calling code can associate the status with all post types if the property is defaulted null or not set.
By calling code, I mean consumers of the resulting status object.
-
attachment
custom-status-helper_1.0.zip
added
plugin to demonstrate custom stati "Approved" and "Secret". Corresponding roles of "Reviewer" and "Super Editor"
comment:23
kevinB — 15 months ago
Just uploaded a patch for the first issue. This is mostly comprehensive, supporting use of the following type of stati:
- private type, indicated by $status_obj->private. Some functionality as normal private, but a separate set of capability requirements which may include all or some of the following: "read_secret_posts", "edit_secret_posts", "delete_secret_posts", "set_secret_posts" (the "publish" equivalent). If a status-specific caps is not defined for some operation, the normal private status equivalent is used.
- pending type, indicated by $status_obj->moderation. Enables additional multi-step moderation, optionally with status-specific capabilities. A new filter is applied to allow plugins to customize the default moderation status for the main Submit button:
$moderation_status = apply_filters( 'post_moderation_status', 'pending', $post->ID );
Remaining Issues:
- I didn't touch xml-rpc or map_meta_cap (but see meta mapping in attached plugin for ideas)
- Custom public stati now have some backend support but no Edit Form UI integration. The complication-to-benefit ratio seems much higher here; at this point I'm not eager to push it.
- The js I moved into edit-form-advanced.php should be reviewed for optimal delivery method.
- I don't know the WP way to compress js files. post.js and inline-edit-post.js in this patch are a copy of uncompressed dev.js
Demo Plugin: I also attached a plugin to demonstrate two custom stati via the following roles:
- "Reviewer" - has edit_approved, delete_approved, set_approved, edit_others, delete_others for all post types
- "Super Editor" (name='super') - has read_secret, edit_secret, delete_secret, set_secret for all post types (in addition to regular editor caps)
The WP roles definitions will be added to your DB, but db-stored capabilities are only that of Contributor and Editor, respectively.
comment:24
kevinB — 15 months ago
For the second issue (statuses should be registered to one or more post types), I suggest following the pattern set for taxonomies:
function register_taxonomy_for_object_type( $taxonomy, $object_type) { global $wp_taxonomies; if ( !isset($wp_taxonomies[$taxonomy]) ) return false; if ( ! get_post_type_object($object_type) ) return false; $wp_taxonomies[$taxonomy]->object_type[] = $object_type; return true; }
I would be able to implement that type of solution early next week if nobody else has it done by then.
comment:25
nacin — 15 months ago
Hi kevinB, for compressed scripts, only edit the .dev.js versions, and omit the compressed versions. We will then handle compression on commit.
I've asked Ptah to review this patch as I know he is also working on a patch, so let's see what we can grab from each to continue.
comment:26
follow-up:
↓ 27
ptahdunbar — 15 months ago
I'm thinking we should group the arguments into patches instead of writing up one big diff.
register_post_status() needs a labels arg for all of these:
- name
- count
- caption
- published (maybe a better wording?)
- save_as (maybe a better wording?)
For the post_type arg, we need to be loop through the post_type arg and register_post_status_for_type()
- post_type
There also needs to be a new post_status arg in register_post_type() that calls register_post_status_for_type(). If the post_status arg isn't passed, it registers all the builtin post statuses to that post type.
We'll need a post_type_has_status() (similar to what johnkolbert wrote in #12567) and use that throughout post_submit_meta_box() to turn features on/off.
I'm not exactly 100% sure on how public, private, and protected work in terms of what functionality they add outside of what's in the post_submit_meta_box() metabox.
- public
- private
- protected
- internal
And finally post status capability. Can anyone elaborate how this should work?
comment:27
in reply to:
↑ 26
;
follow-up:
↓ 28
kevinB — 15 months ago
Replying to ptahdunbar:
I'm not exactly 100% sure on how public, private, and protected work in terms of what functionality they add outside of what's in the post_submit_meta_box() metabox.
- public
- private
- protected
- internal
public stati are published and readable by default to all logged and anonyomous users (an abstraction of the "publish" status).
private stati are published but readable based on possession of the appropriate capability (an abstraction of the "private" status).
protected means a status is not currently readable to any user on the front end, except for previews.
internal means never readable on the front end, post are not set to it by "normal" wp-admin UI, and is not included in wp-admin post filtering unless specified (show_in_admin_status_list)
My patch includes another proposed status type: moderation means a status is part of an editorial moderation process. Not readable on the front end, except for previews (an abstraction of the "pending" status).
And finally post status capability. Can anyone elaborate how this should work?
If the existing pattern is followed, capabilities for custom stati would be specified by setting
$type_object->cap->edit_{$status}_posts = ... $type_object->cap->delete_{$status}_posts = ...
... and if the status is of private type:
$type_object->cap->read_{$status}_posts = ...
In addition, there is a need for a "publish" capability specific to custom public, private and moderation stati:
$type_object->cap->set_{$status}_posts = ...
If there is sentiment for a different model such that $type_obj->status_cap is a status-keyed array property, now is the time. Thoughts?
comment:28
in reply to:
↑ 27
kevinB — 15 months ago
correction...
Replying to kevinB:
protected means a status is not currently readable to any user on the front end, except for previews.
internal means never readable on the front end, post are not set to it by "normal" wp-admin UI, and is not included in wp-admin post filtering unless specified (show_in_admin_status_list)
protected means not readable to any user on the front end, except for previews.
internal means not readable on the front end, posts are not set to it by "normal" wp-admin UI, and is not included in wp-admin post filtering unless specified (show_in_admin_status_list)
comment:29
kevinB — 15 months ago
The updated patch also fixes some core bugs which may deserve their own ticket. I included them as part of this patch because my overall custom stati solution depends on the fix, or vice versa:
- wp_list_filter() : 'or' argument does not work, always returns all members. This function is called by get_post_stati(), get_post_types() and get_taxonomies()
- Users lacking publish capability can change an existing post of any status to Privately Published status via Quick Edit
- On visibility or publish date change, js recaptions publish button as "Update Post" or "Update Page" (versus initial caption of "Update")
comment:30
kevinB — 15 months ago
A few other anomalies I noticed:
1) Contributors can "edit" their own privately published posts, but saving throws it Pending Review status. I'm guessing this is not intended, and can address it as part of #14122 unless someone objects.
2) Contributors can save a post password to a Pending Post via Quick Edit, but not via the full edit form. The post remains in Pending Review status but retains the password if it is published. What is the intended behavior?
3) Setting the post date to future recaptions the publish button to "Schedule" if visibility is set public. But for private visibility, it retains the "Update" caption. Wouldn't it be better to show "Schedule" regardless of visibility - as a visual cue that the privately published post is about to be unpublished until the selected date?
comment:31
kevinB — 15 months ago
I've scrutinized the patch quite extensively and believe it to be cleanly coded, logically consistent and functionally correct. If ptah, nacin and others have just not had time to look at it, no problem. But I'd like to know if you're seeing issues with it.
What else should I do to bring it toward commit eligibility? I know it seems like a big diff, but the changes all fit together toward the goal of custom stati in the post submit UI and a backend that makes those selections a reality.
#14122 would be easier to address if I knew whether my $status_obj->moderation property and status caps approach will fly.
I can explain the reasons for each change file by file, or further describe motivations and use cases. Would either of those be helpful?
-
attachment
custom-status-helper_1.1.zip
added
plugin to demonstrate custom stati "Approved" and "Secret". Corresponding roles of "Reviewer" and "Super Editor". v 1.1 adds registration of custom public status "Alternate" for post type and custom private status "Confidential" for page type.
comment:32
kevinB — 15 months ago
Just updated the patch and demo plugin to:
- support type-specific status registration
- fully support custom public stati in the post edit UI, Edit Posts listing and everywhere else
- support scheduled publishing to any public or private status. Previously, selection of private visibility forced post to be published immediately despite selection (and storage) of future date
Type-specific stati (governed by $status_obj->object_type array) can be registered in two ways:
- register_post_status now supports object_type in $args array; registers the status to all object types by default
- register_status_for_object_type( $post_status, $object_type ) - Add an already registered post status to an object type
Enforcement is via
// $post_type may be an individual value or an array $private_stati = get_post_stati( array( 'object_type' => $post_type, 'private' => true ) );
To make that work, I had to modify function wp_list_filter to support the array value intersection:
function wp_list_filter( $list, $args = array(), $operator = 'and' ) { if ( empty( $args ) ) return $list; $count = count( $args ); $filtered = array(); foreach ( $list as $key => $obj ) { $matched = array_intersect_assoc( (array) $obj, $args ); foreach( array_keys( $matched ) as $_key ) { if ( is_array( $args[$_key] ) ) { if ( ! array_intersect( $args[$_key], $matched[$_key] ) ) unset( $matched[$_key] ); } } $num_matched = count( $matched ); if ( ( 'and' == $operator && $num_matched == $count ) || ( 'or' == $operator && $num_matched ) ) { $filtered[$key] = $obj; } } return $filtered; }
get_post_stati() and get_taxonomies() cast object_type argument to array to ensure the special treatment.
Please let me know what needs further explanation.
-
attachment
Custom_Stati_Support.patch
added
comprehensive support for custom stati (public, private and moderation). RevC tightens code, fixes patch js bugs and a few core bugs (see comments). RevD registers and enforces type-specific stati, fleshes out custom public stati, allows scheduling to any public or private status. RevE is a 1-liner to include all readable stati in Recent Posts widget. RevF (15 Oct) fixes patch bugs related to sticky posts; supports custom public stati for sticky posts, term count, comment feed, archives, find posts, nav menu metabox & display
comment:33
kevinB — 15 months ago
Updated patch fixes patch bugs related to sticky posts, defaults recent posts query to public stati only, and adds custom public stati support for:
- sticky posts
- term count
- comment feed
- archives
- find posts
- nav menu metaboxes and display
Also adds filters to support adjustment of those included stati:
- 'posts_sticky_stati'
- 'term_count_stati'
- 'comment_feed_stati'
- 'getarchives_stati'
- 'find_posts_stati'
- 'nav_menu_stati'
Also adds filters for default stati in the posts query (to support plugins dealing with content permissions):
- 'posts_public_stati'
- 'posts_private_stati'
comment:34
in reply to:
↑ description
markmcwilliams — 15 months ago
Replying to ptahdunbar:
Registering a post status via register_post_status() doesn't show the new status anywhere in the admin. [...] Post statuses should be registered to one or more post types.
Got a BIG +1 from me, interesting stuff happening though!
comment:35
jane — 15 months ago
- Keywords has-patch dev-feedback added; needs-patch removed
There are just a few days left before freeze, so asking committers to take a look and see if it can be finished off for 3.1 or not.
comment:36
nacin — 15 months ago
- Keywords dev-feedback removed
- Type changed from task (blessed) to feature request
- Milestone changed from 3.1 to Future Release
This is a huge undertaking, but I don't think we should rush this into 3.1. This looks like a great starting point. I'll support it as a task for 3.2 and I would be willing to work through it once we branch.
comment:38
follow-up:
↓ 47
ryan_b — 12 months ago
One thing I should note, there should be an argument to hide a post status and an argument to limit what post types it can be used with, especially now that we have custom post types, maybe I want a status just for my custom post type. Or maybe I want a staus that can manually be selected it must be added by my plugin for whatever reason.
Just my 2 cents.
comment:39
ucfknight10 — 12 months ago
what is the status of this ticket? as in, any idea when it will be completed and implemented? i'm writing a plugin for a client that allows the author of the post to set an expiration date, so i've created a post status called "expire" using register_post_status, and i would like to see this ticket implemented into wordpress soon. so, any news?
*withdrawn*
comment:47
in reply to:
↑ 38
;
follow-up:
↓ 48
wlindley — 7 months ago
Replying to ryan_b:
...and an argument to limit what post types it can be used with, especially now that we have custom post types, maybe I want a status just for my custom post type...
Support. There needs to be an argument to register_post_status() whose value is an array of already-registered post_types to which the new post_status applies.
Alternately, register_post_type() could take an argument whose value is an array of already registered post_status values.
Furthermore, as of v3.1.3, the preamble to post.php contains eight calls to register_post_status, which are ignored by get_post_statuses() and get_page_statuses() -- which both are hard-coded, not to mention which line 109 says:
register_post_status( 'pending', array( 'label' => _x( 'Pending', 'post' ),
while line 589 disagrees, returning the label:
'pending' => __('Pending Review'),
Regardless, surely both get_post_statuses() and get_page_statuses() should simply return the data created by register_page_status() and register_post_type().
comment:48
in reply to:
↑ 47
nacin — 7 months ago
Replying to wlindley:
Regardless, surely both get_post_statuses() and get_page_statuses() should simply return the data created by register_page_status() and register_post_type().
I believe those are just used for XML-RPC. The function to fetch statuses would be get_post_stati().
comment:49
scribu — 7 months ago
Related: #17906
comment:52
simonwheatley — 4 months ago
Related: #18578 (didn't spot this when I submitted mine)
comment:58
kevinB — 2 months ago
The patch functionality (custom privacy and moderation statuses) is now implemented via plugin.
How is the status os this patch? Will this be implemented in 3.4? Do you need any help testing and implementing it? I can help with anything implementing this API, but I don't know where to start it. Can you please nacin or anyone else give me some directions? Thanks
comment:62
westi — 7 weeks ago
- Keywords westi-likes 3.4-early added
This has a lot of discussion and patch work that we should consider what we want to do API wise to improve post_status support in core and what we don't want to support.
comment:64
sirzooro — 4 weeks ago
Please also add new function post_status_exists( $post_status ) - sometimes it may be handy to check if particular post status is registered. You can also add 2nd param $post_type, to check if post status exists for given post type (optional param, defaults to all post types).
Related: #12567