CPT with its own category and tag url

First, we need to declare CPT.

Here in example I am creating with the name “command“.

Also I am adding category and tag support for this CPT.

The CPT will be public, searchable, will have archive page, feed page etc.

add_action( 'init', 'create_post_type' );

function create_post_type() {

    $post_array =   array(
        'name'              => __( 'Command' ),
        'singular_name'     => __( 'command' )

      );
    $post_args = array(
        'labels'                => $post_array,
        'menu_name'             => __( 'Command' ),
        'taxonomies'            => array('category','post_tag'),
        'public'                => true,
        'has_archive'           => true,
        'rewrite'               => array('slug' => 'command'),
        'publicly_queryable'    => true,
        'exclude_from_scratch'  =>false,
        'with_front'            => true,
        'feeds'                 => true,
        'supports'              => array( 'title','editor', 'author', 'thumbnail', 'excerpt', 'comments','revisions' ),
    );
  register_post_type( 'command',$post_args);

}

Now I am declaring rewrite rule to have the separate URL facility for CPT category and tag.

http://domain.net/command/category/catname
http://domain.net/command/tag/tagname

will be converted to the following URLS which are understandable by wordpress.

http://domain.net/?page_type=command&category_name=catname
http://domain.net/?page_type=command&tag=tagname

So that wordpress could understand them.

add_action('init', 'category_cpt_rewrites');

function category_cpt_rewrites() {
    $custom_post_types = array('command'); //some example post types
    foreach ( $custom_post_types as $post_type ) {
        $rule="^" . $post_type . '/category/(.+?)/?$';
        $rewrite="index.php?post_type=" . $post_type . '&category_name=$matches[1]';
        add_rewrite_rule($rule,$rewrite,'top');
    }
        foreach ( $custom_post_types as $post_type ) {
        $rule="^" . $post_type . '/tag/(.+?)/?$';
        $rewrite="index.php?post_type=" . $post_type . '&tag=$matches[1]';
        add_rewrite_rule($rule,$rewrite,'top');
    }


}

We will also rewrite for date based archive pages like this.

http://example.net/command/2016/05

will be converted to

http://example.net/?post_type=command&m=201605

the code is as followed.

add_action('init', 'date_cpt_rewrites');

function date_cpt_rewrites() {
    $custom_post_types = array('command'); //some example post types
    foreach ( $custom_post_types as $post_type ) {
        $rule="^" . $post_type . '/(\d+)/(\d+)/?$';
        $rewrite="index.php?post_type=" . $post_type . '&m=$matches[1]$matches[2]';
        add_rewrite_rule($rule,$rewrite,'top');
    }


}

Here we are making sure that our CPT “command” posts are available in other common archive also.
By default post type “post” is only shown on archive pages.

add_filter( 'pre_get_posts', 'my_get_posts' );

function my_get_posts( $query ) {

    if ( is_category() || is_tag() || is_search() || is_home() || is_front_page() || is_author() || is_archive() && $query->is_main_query() )
                $post_type = get_query_var('post_type');
                if($post_type) {
                    $post_type = $post_type;
                }else{
                    $post_type = array('post','command'); // replace cpt to your custom post type
                    $query->set( 'post_type', $post_type );
                }
    return $query;
}

So Here entire game is converting your desired URLS into wordpress understandable urls.