39

There are lots of situations where a theme or plugin registers a post type and you want to modify it. There is of course add_post_type_support() and remove_post_type_support(), but those don't give access to the full list of arguments that register_post_type() takes. In particular, maybe I want to disable a post type archive, hide the admin UI, hide from search, etc. while leaving the rest of the post type settings alone.

The Codex page for register_post_type() dangles this in front of me:

Description

Create or modify a post type.

But in the past, when I've try to do this, it hasn't seemed to work. Is this function really for modifying post types, and if so, can you simply redeclare a couple arguments and leave the rest alone?

Seeing that there isn't even a deregister_post_type() function, I don't understand how it can be done.

6 Answers 6

21

Is this function really for modifying post types

Yes.

and if so, can you simply redeclare a couple arguments and leave the rest alone?

No. If you want to modify arguments to a post type, you need to use get_post_type_object to get the post type object, modify what you want in it, then re-register it using your modified type as the new $args parameter.

3
  • Would making two consecutive calls with modified arguments to the same register_post_type be correct? I assume so by your "Yes.", and it doesn't dumps any errors and has the desired effect. The real case is the second option I present in this answer: wordpress.stackexchange.com/a/74331/12615
    – brasofilo
    Commented Nov 29, 2012 at 14:54
  • Yes, that works, but it seems like if you're having to do that, then you need to add some filters or something else to prevent having to repeatedly register the same post type over and over again. Basically, get the arguments sorted out first, then register it.
    – Otto
    Commented Nov 29, 2012 at 19:13
  • I just thought about it because of the hook provided just before the plugin's register_post_type. In reality, there's no need. It was a "for the records" question, thanks for the feedback.
    – brasofilo
    Commented Nov 29, 2012 at 19:22
57

After some research I found none of these answers are up to date.

As of December 8, 2015 WordPress includes a new filter, register_post_type_args, which lets you hook into the arguments of a registered post type.

function wp1482371_custom_post_type_args( $args, $post_type ) {
    if ( $post_type == "animal-species" ) {
        $args['rewrite'] = array(
            'slug' => 'animal'
        );
    }

    return $args;
}
add_filter( 'register_post_type_args', 'wp1482371_custom_post_type_args', 20, 2 );
7
  • 6
    This is the right way to do this now. Commented Sep 15, 2016 at 23:47
  • 6
    This should the the accepted answer
    – klewis
    Commented Nov 18, 2016 at 14:20
  • What if you need to update it after it has been registered in runtime? Eg: after init Commented Jun 27, 2019 at 19:40
  • @LucasBustamante It does not matter. Just call the 'add_filter' line during your plugin/theme, not in an action. The filter will be called during every register_post_type function. The only scenario where my code will not work is if the post type is not being registered correctly. All post types should be registered during the init hook. From the codex: "register_post_type will not work if called before 'init', and aspects of the newly created or modified post type will work incorrectly if called later." If you still need help I suggest posting more details in a new question. Commented Jun 28, 2019 at 2:57
  • so, this code will change the 'slug-of-post', as in 'sitename/projects/slug-of-post' ??
    – Krys
    Commented Oct 16, 2020 at 6:24
9

Here's an example of how to use the 'registered_post_type' filter to modify a post type in another plugin.

A plugin I was using didn't include a menu_icon in it's definition, so I wanted to add one of my own.

<?php
/**
 * Add a menu icon to the WP-VeriteCo Timeline CPT
 *
 * The timeline plugin doesn't have a menu icon, so we hook into 'registered_post_type'
 * and add our own.
 *
 * @param  string $post_type the name of the post type
 * @param  object $args the post type args
 */
function wpse_65075_modify_timeline_menu_icon( $post_type, $args ) {
    // Make sure we're only editing the post type we want
    if ( 'timeline' != $post_type )
        return;

    // Set menu icon
    $args->menu_icon = get_stylesheet_directory_uri() . '/img/admin/menu-timeline.png';

    // Modify post type object
    global $wp_post_types;
    $wp_post_types[$post_type] = $args;
}
add_action( 'registered_post_type', 'wpse_65075_modify_timeline_menu_icon', 10, 2 );
1
  • This is a much cleaner way to do it in most cases; however, it should be noted that this filter is too late to get picked up by rewrites so the accepted answer must be used instead in those situations.
    – mrwweb
    Commented Mar 17, 2015 at 22:44
4

Hook into 'registered_post_type' after the other code has registered it. It is called at the end of register_post_type(). You get two arguments: $post_type and $args.
Now you can change anything for this post type. Inspect $GLOBALS['wp_post_types'] for some options.

2
  • Thanks for pointing me toward that hook. That answers the (more important) question about how to modify a post type, but what about the description of register_post_type() that includes "modify?" Is that just wrong? Should I hop on my internet horse and vanquish it from the Codex this moment?
    – mrwweb
    Commented Sep 13, 2012 at 16:32
  • 2
    $wp_post_types[$post_type] = $args; … suggests that you should be able to change the properties. Add an example of the failing code to your question.
    – fuxia
    Commented Sep 13, 2012 at 16:36
1

I faced the same thing with The Events Calendar plugin.

I added the below code to function.php to modify the tribe_organizer post type

function tribe_modify_organizer() {
 //New arguments
    $tribe_organizer_args = get_post_type_object('tribe_organizer'); // get the post type to modify
    $tribe_organizer_args-> taxonomies = array('post_tag' , 'tribe_events_cat'); // add taxonomies support
    $tribe_organizer_args-> exclude_from_search = false; // show in search result
 //re-register the same post type includeing the new args
    register_post_type( 'tribe_organizer', $tribe_organizer_args );
}
add_action( 'init', 'tribe_modify_organizer', 100 );
1
  • Great sample, thanks!
    – Philipp
    Commented Aug 25, 2020 at 11:25
0

I dont know if this is ugly, but you could alter the GLOBAL placeholder "on the fly" whenever you need to manipulate a single argument. This is how we use a non-public post type contents to be acceptable in admin menu. We hook close before and close after the menu renders:

function entex_theme_make_contents_public(){
    $GLOBALS['wp_post_types']['contents']->public = true;
}
add_action('admin_menu', 'entex_theme_make_contents_public', 10);

function entex_theme_make_contents_private_again(){
    $GLOBALS['wp_post_types']['contents']->public = '';
}
add_action('admin_menu', 'entex_theme_make_contents_private_again', 12);

In our case, we want the Admin Menu Post List plugin to accept our post type, as they call return get_post_types(array('public' => true)); inside their hook with priority 11 ...

Developers -Please make a comment if this could couse any issues.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.