Use register_post_type() to modify an existing post type

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:

Read More

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.

Related posts

Leave a Reply

6 comments

  1. 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.

  2. 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 );
    
  3. 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 );
    
  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.

  5. 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 );
    
  6. 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.