#17447 closed enhancement (fixed)
Add 'register_post_type_args' hook
Reported by: | mikeschinkel | Owned by: | SergeyBiryukov |
---|---|---|---|
Milestone: | 4.4 | Priority: | normal |
Severity: | normal | Version: | 3.1 |
Component: | Posts, Post Types | Keywords: | has-patch commit |
Focuses: | Cc: |
Description
I have two different use cases where I ideally would be able to hook the register_post_type()
function:
- To add custom attributes and custom
'supports'
values; current hooks don't allow adding support at the right time to be fully robust.
- To disable the default rewrite logic in order to support customized rewrite logic passed as custom attributes.
I've attached a patch that adds 'pre_register_post_type'
and 'register_post_type'
hooks to register_post_type()
.
Attachments (15)
Change History (75)
#1
follow-up:
↓ 2
@
14 years ago
current hooks don't allow adding support at the right time to be fully robust.
Could you describe that in more detail? In other words, what's wrong with add_post_type_support() ?
#2
in reply to:
↑ 1
@
14 years ago
Replying to scribu:
what's wrong with add_post_type_support() ?
Red-faced, didn't know about add_post_type_support()
.
However, that function doesn't allow someone to intercept all $args
passed to register_post_type()
and change some of them before the register_post_type()
operates on the $args
. One example would be to set $args->rewrite = false;
for all post types using a pre_register_post_type
hook, and then define the rewrites differently using the register_post_type
hook; this is exactly something I need right now for a project I'm working on.
A plugin developer may want to provide alternate rules for post type archives so it might want to set $args->has_archive = false;
using a pre_register_post_type
hook, and then define the post type archives differently using the register_post_type
hook. This is also something I need.
In addition a plugin developer may want to provide an admin console option that allows the end user to define all the visibility settings for the different post types; a pre_register_post_type
hook would enable that.
Another example is an $args->columns
which would include a keyed array of headers and callbacks and/or $args->column_headers
containing an array of headers and $args->column_callbacks
containing an array of callbacks. And yet another example would be to add $args->meta_boxes
which would include a keyed array of meta_box
args.
As stated, some of those examples are ones I currently would like to be able to streamline by specifying in the register_post_type()
call making it easier to define a full-features custom post type, and some of these examples of trying to keep WordPress from doing work to create data that is simply going to be thrown away.
#3
@
13 years ago
- Cc mikeschinkel@… added
- Keywords 2nd-opinion added
I'm bumping into the need for this again, and would love to get this reviewed? Please?
#5
@
13 years ago
I thought we had these already. Must have gotten added elsewhere:
do_action( 'registered_post_type', $post_type, $args );
#6
follow-up:
↓ 7
@
13 years ago
registered_post_type
and registered_taxonomy
were added in [18833].
#7
in reply to:
↑ 6
;
follow-up:
↓ 9
@
12 years ago
- Summary changed from Add register_post_type and pre_register_post_type hooks to Add 'register_post_type_args' hook
Replying to SergeyBiryukov:
registered_post_type
andregistered_taxonomy
were added in [18833].
Those are great, thanks.
But the real reason for my request here is the get hook-based access to the args so I'm going to change the title of this ticket and to add the patch I'd like to see.
This patch would allow a plugin to disable some of the the default processing in register_post_type() and replace it with its own.
#9
in reply to:
↑ 7
@
12 years ago
Replying to mikeschinkel:
Replying to SergeyBiryukov:
registered_post_type
andregistered_taxonomy
were added in [18833].
Those are great, thanks.
But the real reason for my request here is the get hook-based access to the args so I'm going to change the title of this ticket and to add the patch I'd like to see.
This patch would allow a plugin to disable some of the the default processing in register_post_type() and replace it with its own.
I agree: plugin authors need to be able to edit post type arguments on registering them. Currently, the only way to do it is by directly accessing $wp_post_types
(come to think of it, get_post_type_object()
should also work), which is not only undesirable but also quite inconvenient.
As far as your diff-file is concerned: the second one seems partially right. Naming the filter 'register_post_type_args' complies with the standards, and all necessary parameters are passed.
However... I'm wondering whether or not it would be better to apply the filter before calling wp_parse_args
. That way, you make sure that all values required for registering a post type are present. This is different from what the standard is for filtering arguments when fetching data, but in this case we're actually creating a post type object that has to have certain properties, as people (and WordPress) expect them to be there, e.g. the post type labels.
If we call the filter before wp_parse_args
we make sure that all required properties are available.
Returning false
on empty( $args )
is definitely not the way to go, a WP_Error
should be returned in that case.
#11
@
11 years ago
I couldn't believe that there wasn't a filter here. There are times it would be really useful. What needs to happen to get this committed?
#12
@
11 years ago
I also needed this today. Isnt' do_action( 'registered_post_type', $post_type, $args );
too late? You are required to re-do some of the processing that register_post_type()
does instead of modifying the $args
at the beginning of the function.
#15
follow-up:
↓ 16
@
11 years ago
I'm not sure I like this proposal. A more detailed justification and explanation would be in order. Letting this function be "pluggable" could make post types even more fragile than they are already, given this is a still slowly evolving API.
@
11 years ago
Revised 'register_post_type_args' based on current trunk and with hook documentation.
#16
in reply to:
↑ 15
@
11 years ago
Replying to nacin:
A more detailed justification and explanation would be in order.
Here are the use-cases I've identified from prior projects:
- Change the values for menu/post type visibility or just disable post types provided by a plugin/theme that are not needed for a specific site.
- Add new plugin/theme specific "supports" for default post types and custom post types that don't explicitly specify supports.
- Add new plugin/theme specific values to support plugin/theme added features. For example, 'my_exporter' value could be set to information that the My Exporter plugin uses to implement an export such as columns to include, column labels, WP_Query args for default export as well as meta fields to include.
- Disable default rewrite rule addition so customized rewrite rules could be added in a function called for the 'registered_post_type' hook.
- Disable default metabox callback registration so customized metabox callback registration could be performed in a function called for the 'registered_post_type' hook.
- Disable taxonomy registration for object so customized taxonomy registration for object could be performed in a function called for the 'registered_post_type' hook.
@
11 years ago
Revised 'register_post_type_args' based on current trunk and with hook documentation.
#17
@
11 years ago
Replying to nacin:
Letting this function be "pluggable" could make post types even more fragile than they are already
An alternate to adding this single hook would be to provide several smaller hooks; one for each of the concerns I mentioned above so as:
- Short-circuit/disable selected post type registrations.
- Default supports
- Rewrite rules
- Metabox callbacks
- Taxonomy Registration
The first three are the ones I have found most need for.
BTW, I'd be interested in understand circumstances where allowing modification of $args
would make post types more fragile. In Sunrise, we currently allow modification of $args
via a hook in our wrapper function that calls register_post_type()
so that a generic plugin can be used for many similar sites that need easy customization. If we are going to run into trouble with that I'd like to be able to anticipate what type of trouble.
#18
@
11 years ago
I've also needed to change some labels on post types registered by a plugin. This can be done by accessing the $wp_post_types
global, but I think a filter would be more elegant.
#19
@
11 years ago
+1
Here's my use case:
Using a 3rd party plugin that adds a CPT to WordPress... but the developer uses the built in 'post' capabilities -- which means it's difficult to have a user who can only edit that CPT (but not posts). It's easy for the dev and most plugin users, but doesn't use the WP capabilities system to allow the site owner to make those decisions.
In this case the 3rd party plugin had a filter wrapped around it's arguments before they were passed to register_post_type, but 99% of CPT plugins I've seen in the repo are not this considerate. Having this in core would be really useful to tweak 3rd party CPTs without having to fork the core plugin.
In addition, being able to change labels and other options while using a 'common' plugin (like Justin Tadlock's portfolio plugin) would increase standardization without hurting customizability. E.g., why fork the entire plugin just to rename them "Samples"?
As for fragility, anyone changing CPT arguments via a filter should know the risks - muck up the arguments and you'll break things, but that's the case with any core filter.
#20
follow-up:
↓ 21
@
11 years ago
Thanks to both of you for some good examples. I don't think it's unreasonable to add the ability to modify a post type registration; I just wonder if a single one-size-fits-all hook makes the most sense. Keeping this more fine-grained might make things a little more verbose, but also a bit more stable. Not sold either way, just throwing out some ideas:
- I'm not sure I love the idea of short-circuiting and preventing post type registration. I think we'd have to avoid this ability for built-in post types, at least for as long as WP falls flat on its face when this happens.
- The ability to control labels should probably be its own discrete filter. If we make some changes, get_post_type_labels() might be usable in a callback to re-process as needed.
- The ability to control the compiled capabilities should probably be its own discrete filter. If we make some changes, get_post_type_capabilities() might be usable in a callback to re-compile as needed.
- There exists register_taxonomy_for_object_type(), unregister_taxonomy_for_object_type(), add_meta_box(), remove_meta_box(), add_post_type_support(), remove_post_type_support().
- Rewriting and query variables could possibly be broken out.
#21
in reply to:
↑ 20
@
11 years ago
Replying to nacin:
I don't think it's unreasonable to add the ability to modify a post type registration; I just wonder if a single one-size-fits-all hook makes the most sense. Keeping this more fine-grained might make things a little more verbose, but also a bit more stable.
Sounds reasonable to me.
How would you like to see us move forward with this so we might be able to consider patches for core sooner than later? New tickets for each use-case?
Any (other) specific direction regarding what you'd want to see/not want to see in patches?
#22
follow-up:
↓ 24
@
11 years ago
I for one never imagined this would apply to built in post types -- just post types added by plugins and (shudder) themes.
I'm not tied to a specific implementation -- more the idea that the plugin that registers a post type is not necessarily the final word and other plugins should be able to tweak/extend an already registered post type. The discrete approach sounds like more work but probably is the better route - filter the data upon "read" versus on "write".
I'd love to contribute to this - it would be my first "code" contribution to core ;-)
#23
@
11 years ago
I think new patches on this ticket is fine. I'm open to proposals. Let's experiment with some things and see where it takes up. Labels is easiest, capabilities a bit harder. I could also go for a "generic" filter if it bypasses things for built-ins. (Filtering labels are definitely OK for those, though.)
@
11 years ago
Allows filtering of all args for custom types, but only label filtering for _builtin types.
@
11 years ago
Cleaned up (formatting & style) -- allows filtering of all args for custom types, but only label filtering for _builtin types.
#24
in reply to:
↑ 22
@
11 years ago
Replying to nickciske:
Nice first patch.
Several things.
- See DrewAPicture's comment about needing hook docs.
- Your patch doesn't allow short-circuiting of post type registration for non built-in types.
- Your patch doesn't pass in the sanitized version of the post type in
$args['name']
and then capture it after the args as the post type name as in my v2.x of the patch so you wouldn't be able to modify a post type name in case of a conflict (which is mostly moot, but sometimes if the plugin to fix is trivial enough it might be workable.)
That said, I'm starting to think that it won't be as simple as just bypassing '_builtins'
; for example one of your use-cases was the need to change capabilities; if we bypass builtins then capabilities for default post types can't be fine-tuned easily.
Maybe we should tackle each and every use-case instead of a more broad sweeping hook?
#25
@
11 years ago
I just uploaded a new patch that is very different from the others that uses a granular approach to allowing arguments to be modified. It's not what I'd consider ready to apply to core but instead meant for discussion on the approach.
#26
@
11 years ago
- Milestone changed from 3.9 to Future Release
Sounds like this ticket is still exploring approaches, and unfortunately the time has come to punt enhancements from 3.9.
@
11 years ago
Coarse-grained approach to filtering the arguments to register_post_type, which the filter applied before parsing with default arguments
@
11 years ago
Coarse-grained approach to filtering the arguments to register_post_type, which the filter applied before parsing with default arguments
#27
@
11 years ago
Sorry about the patch overload, it took me some time to realize I hadn't committed my latest changes.
I would argue that the coarse-grained approach is desirable here. It gives developers full control over registered post types, and prevents a huge amount of filters being added. My most important argument, however, is that there are no post type arguments that should be usable when calling register_post_type
but should not be modifiable by other plugins.
I've added a patch (a few, actually) that implements this: register-post-type-args-filter.17447.v3.diff
. It implements the filter register_post_type_args
, which filters the post type arguments.
- It applies the filter before calling
wp_parse_args
, which prevents removing required arguments via the filter (as any missing keys will simply be added via$defaults
). - The post type name is sanitized earlier on and passed to the filter as the second argument.
- The filter is only applied to non-built-in post types (i.e. custom post types, post types with
_builtin
false).
As far as post type labels are concerned: these are already filterable in register_post_type
, as it calls get_post_type_labels
which has been filterable (post_type_labels_{$post_type}
) since 3.5.
@MikeSchinkel
I don't think the post type name should be filterable. The post type name is the unique identifier of a post type, which means changing it effectively means registering an altogether different post type. Furthermore, I don't see a problem with bypassing built-in post types altogether at this point, as it's just too fragile. Core and many plugins rely on the default, unfiltered settings from the default post types. Changing capabilities for these post types, for example, would break a lot of sites.
At this point, I think we should move ahead with adding this to core, as this is just about as lean and safe as it will get without losing control over custom post types.
#29
@
11 years ago
I would really like to move forward with this ticket. Could somebody give a second opinion on this? I would love to see this in 4.0.
#32
@
10 years ago
Any new on this? I think there aren't trouble adding this filter, cause you could control every kind of post type adding the filter, so a dev could mod the post type args only if the post type isn't a built in one (for ex, you could control the $post_type on the register_post_type function, and this is only a method).
#33
@
10 years ago
Bump. Would still love to see this one added to core. We use plugins like WP Types all the time which have their own method for registering custom post types. We often have the need to filter the rewrite slug, which would be way easy to do with a register_post_type() args filter.
#35
@
9 years ago
- Keywords dev-feedback needs-docs needs-refresh removed
- Milestone changed from Future Release to 4.4
I could also go for a "generic" filter if it bypasses things for built-ins.
17447.diff is a refreshed version of the most recent patch after register_post_type()
was moved to wp-includes/post-functions.php
. Also includes a docblock for the filter.
#38
@
9 years ago
- Owner set to SergeyBiryukov
- Status changed from new to assigned
Sergey, up to you what we do here
#39
follow-up:
↓ 40
@
9 years ago
- Resolution set to fixed
- Status changed from assigned to closed
In 34242:
#40
in reply to:
↑ 39
;
follow-up:
↓ 42
@
9 years ago
- Keywords dev-feedback added
Replying to SergeyBiryukov:
Does not apply to built-in post types.
Thanks.
Except the built-ins are a primary use case.
For example, I might need "Post" to be labeled "Story" or "Article."
Or I might need to add additional "supports" attributes to "Post" and "Page."
#42
in reply to:
↑ 40
;
follow-up:
↓ 43
@
9 years ago
Replying to MikeSchinkel:
For example, I might need "Post" to be labeled "Story" or "Article."
There's the post_type_labels hook for that.
Or I might need to add additional "supports" attributes to "Post" and "Page."
You can use add_post_type_support
for that.
#43
in reply to:
↑ 42
@
9 years ago
Replying to swissspidy:
Replying to MikeSchinkel:
For example, I might need "Post" to be labeled "Story" or "Article."
There's the post_type_labels hook for that.
Or I might need to add additional "supports" attributes to "Post" and "Page."
You can use
add_post_type_support
for that.
Fair points. But those were just _some_ examples. Here are more:
- Setting
'public'
or any of the other visibility settings to befalse
(ortrue
) for "Post" or "Page." - Changing the
'menu_position'
,'menu_icon'
,'capabilities'
for "Post" or "Page." - Changing
'rewrite'
or'permalink_epmask'
for "Post" or "Page." - Making changes to
'attachment'
,'revision'
, or'nav_menu_item.'
Since a programming can actually make any changes they need to builtins without this hook, it seems like disabling access to builtins via the hooks hobbles the hook for uses which I originally requested the hook (even though I did not explicitly state that) but for with very little benefit.
If the overriding concern is that people will accidentally change builtins they did not intend to change then I would ask for an additional 'register_builtin_post_type_args'
hook to allow for explicit changes.
#44
follow-up:
↓ 45
@
9 years ago
I think it's worth considering whether built-ins and custom content types are really even on the same playing field. I'd argue they aren't, and that's why not allowing their args to be filterable at all makes the most sense.
Users, developers, and core alike all expect the built-in post types to work in very specific, defined ways, and opening those behaviors for interpretation is likely to lead to unexpected consequences in all kinds of contexts. Realistically, the fact that there is even a _builtin
argument in the first place should be an indication that core treats them differently for good reason. I don't think that's a significance that should be ignored.
#45
in reply to:
↑ 44
@
9 years ago
Replying to DrewAPicture:
the fact that there is even a
_builtin
argument in the first place should be an indication that core treats them differently for good reason. I don't think that's a significance that should be ignored.
I am not suggesting we ignore the significance, I am suggesting that professional programmers often need to modify the behavior based on client expectations and requirements. So having a separate explicitly named hook for built-ins that I just proposed explicitly acknowledges they are different yet still allows for professional programmers to address the needs of their clients.
#46
follow-ups:
↓ 47
↓ 48
@
9 years ago
professional programmers often need to modify the behavior based on client expectations and requirements
Professional programmers offer solutions to clients. Clients don't dictate specific modifications to register_post_type()
. Your two examples are already accomplished through filters. What other things to do you want to change, specifically? If your use cases are vague, then they aren't an emergency.
There are no plans to officially offer a filter for these args. If you want to change the global
value for $wp_post_types
, you can, and you'd be accomplishing the same thing. You're also voiding your warranty. Want to do it as soon as the post type is registered? Use the registered_post_type
action.
This isn't a "professional" vs "amateur" argument.
#47
in reply to:
↑ 46
@
9 years ago
Replying to wonderboymusic:
professional programmers often need to modify the behavior based on client expectations and requirements
Professional programmers offer solutions to clients. Clients don't dictate specific modifications to
register_post_type()
.
Of course not. But sometimes the best and most performant way to offer a specific solution might be through this hook acting on builtins.
What other things to do you want to change, specifically?
Listed above: https://core.trac.wordpress.org/ticket/17447#comment:43
A big reason to do this is to change values before the values trigger code to be run whose results have to be reverted. The code that ends up getting called that needs to be reverted at time includes calls to add_rewrite_rule()
, add_permastruct()
and register_taxonomy_for_object_type()
. Unraveling those functions after the fact, especially the first two, is a PITA and introduces potential bugs if you don't get it correct.
Also, for example, being able to add a property (i.e. 'x_newclarity'
named with 'x'
for extension and the rest after our company name) to the post type array that would get passed around with the return value of get_post_type_object()
so we can be sure it is always there. This would allow a developer to add, for example, metadata about generating reports for a post type or metadata for columns in the admin or metadata for customized export.
If your use cases are vague, then they aren't an emergency.
I would seem an emergency should to be something that would go in +x.x.1 patches, improvements to the platform to be in +x.1 releases.
And if we wait, we are likely to have to wait another 4 years more for the original purpose of this request to be addressed.
If tickets for legitimate needs were addressed more frequently, it would not be as important to emphasize this request now.
There are no plans to officially offer a filter for these args. If you want to change the
global
value for$wp_post_types
, you can, and you'd be accomplishing the same thing. You're also voiding your warranty. Want to do it as soon as the post type is registered? Use theregistered_post_type
action.
This is a case of "It's hard to know how people will leverage it before you make it available."
Why should you take a stance of "no" when addressing in core would be so trivial and the downside effectively moot? Asked another way, what harm are you trying to avoid?
This isn't a "professional" vs "amateur" argument.
You misinterpreted my statement to emphasize the word "professional"; if my wording misled you I apologize. I intended for you to instead focus on the word "client" as a use-case in contrast with "a plugin or theme meant for wide distribution."
#48
in reply to:
↑ 46
@
9 years ago
Replying to wonderboymusic:
What other things to do you want to change, specifically? If your use cases are vague, then they aren't an emergency.
Change rewrite parameters before generating the rewrite rules. Example: a multilingual plugin.
This isn't a "professional" vs "amateur" argument.
By bypassing built-in post types it kind of becomes one, because we're simply assuming that developers will necessarily explode everything. Yes, some of us will do things we shouldn't (that's where you should talk about html tags in shortcode arguments :D ), but is that a reason enough to limit all developers?
So, +1 on removing this built-in limitation.
#49
@
9 years ago
+1 to remove the limitation, there is so many ways to break everything already, but i don't see the world burning ;)
So big +1 to remove it, thanks.
#50
@
9 years ago
+1 this kind of limitations is really fustrating for the developers.
Since we are using this filter to change the native behaviour of the built-in post types then we know we can break things and at this point of customization we are aware of what we are doing.
This kind of manipulations aren't common. Everywhere else on WordPress the _builtin arg is only used to query the built in post types and taxonomies not to limit actions.
Thanks
#51
follow-up:
↓ 52
@
9 years ago
Since at least 3 others agree that we should allow the developer to choose if they need to modify the post type args for '_builtins'
I proactively added a patch that removed the limiting if()
statement: 17447.2.diff. Here is hoping that some core committers will understand our request and apply it.
#52
in reply to:
↑ 51
;
follow-up:
↓ 53
@
9 years ago
Replying to MikeSchinkel:
Are you sure about your patch? It seems to contain lots of things...
#53
in reply to:
↑ 52
@
9 years ago
Replying to GregLone:
Replying to MikeSchinkel:
Are you sure about your patch? It seems to contain lots of things...
Ugh. I'll reupload a fixed version. Thanks.
#54
@
9 years ago
I don't really have any more of a problem with making it available to built in post types than with any other dangerous thing that can be done, so long as people know there's no warranty (aka guarantee of back compat) if you go messing with that. Is that worth documenting somewhere, perhaps?
@MikeSchinkel Speaking of documentation, your patch could use an inline doc update. :)
#55
follow-up:
↓ 56
@
9 years ago
- Resolution set to fixed
- Status changed from reopened to closed
In 34451:
#56
in reply to:
↑ 55
@
9 years ago
Replying to helen:
I don't really have any more of a problem with making it available to built in post types than with any other dangerous thing that can be done, so long as people know there's no warranty (aka guarantee of back compat) if you go messing with that. Is that worth documenting somewhere, perhaps?
Thanks Helen!
@MikeSchinkel Speaking of documentation, your patch could use an inline doc update. :)
Yeah, sorry I missed that. :-(
Replying to SergeyBiryukov:
In 34451:
Thanks for the commit and for fixing the comment.
#57
@
9 years ago
- Keywords needs-patch added; has-patch dev-feedback removed
- Resolution fixed deleted
- Status changed from closed to reopened
You would have to be a fruitcake to do it, but the $args
parameter in register_post_type()
can actually be a query string as well as an array (thanks to wp_parse_args()
).
This somewhat complicates usage of the register_post_type_args
filter, which would be much less fragile if it only had to deal with an array.
#60
@
9 years ago
I was just about to raise this requirement myself as I have a desire to allow the has_archive
flag to be altered by the user. Obviously there's no problem with a user defined post type (one that's not yet registered) but it's a real challenge with a post type that is registered by another plugin.
I'm glad I didn't have to write the code that would have to fiddle about with rewrite rules to achieve this.
Now that I've written this comment I realize that I could probably have done my overriding registration first. But I'm happy to wait for the official version.
Adds 'pre_register_post_type' and 'register_post_type' hooks to register_post_type().