Custom Rewrite Rules

On this project we had a custom post type called “resource” and a taxonomy called “resource_type”. We wanted the following URLs:

  • /resource – CPT Archive for resource
  • /resource/ebooks – Tax archive for “ebook” term in the resource_type taxonomy
  • /resource/ebooks/sample-ebook – Single post in resource CPT

Some things to note below:

  • Line 71, the resource_type taxonomy has its rewrite slug set to resource.
  • Line 197, the resource CPT has its rewrite slug set to resource/%resource_type%.
  • Lines 210-212, registering the different rewrite rules.
  • Lines 220-230, filtering the post type link (singular) to change %resource_type% to an actual taxonomy term slug. Not shown is the ea_first_term() function that gets the terms and selects the first if multiple terms are attached to post.
  • Lines 236-240, filters the post type archive link, removing the %resource_type% so that it is just /resource.
<?php
/**
 * Core Functionality Plugin
 *
 * @package    CoreFunctionality
 * @since      1.0.0
 * @copyright  Copyright (c) 2017, Bill Erickson
 * @license    GPL-2.0+
 */
/**
 * Resources
 *
 * This file registers the resource custom post type
 * and setups the various functions and items it uses.
 *
 * @since 1.2.0
 */
class EA_Resource {
	/**
	 * Initialize all the things
	 *
	 * @since 1.2.0
	 */
	function __construct() {
		// Actions
		add_action( 'init',                   array( $this, 'tax_resource_type'  )    );
		add_action( 'init',                   array( $this, 'tax_resource_topic' )    );
		add_action( 'init',                   array( $this, 'tax_library_tag'    )    );
		add_action( 'init',                   array( $this, 'register_cpt'       )    );
		add_action( 'init',                   array( $this, 'rewrite_rules'      )    );
		add_filter( 'post_type_link',         array( $this, 'post_type_link'     ), 10, 2 );
		add_filter( 'post_type_archive_link', array( $this, 'post_type_archive_link' ), 10, 2 );
		add_action( 'pre_get_posts',           array( $this, 'archive_query' ) );
	}
	/**
	 * Register the Resource Type taxonomy
	 *
	 * @since 1.2.0
	 */
	function tax_resource_type() {
		$labels = array(
			'name'                       => 'Resource Types',
			'singular_name'              => 'Type',
			'search_items'               => 'Search Types',
			'popular_items'              => 'Popular Types',
			'all_items'                  => 'All Types',
			'parent_item'                => 'Parent Type',
			'parent_item_colon'          => 'Parent Type:',
			'edit_item'                  => 'Edit Type',
			'update_item'                => 'Update Type',
			'add_new_item'               => 'Add New Type',
			'new_item_name'              => 'New Type',
			'separate_items_with_commas' => 'Separate Types with commas',
			'add_or_remove_items'        => 'Add or remove Types',
			'choose_from_most_used'      => 'Choose from most used Types',
			'menu_name'                  => 'Types',
		);
		$args = array(
			'labels'            => $labels,
			'public'            => true,
			'show_in_nav_menus' => true,
			'show_ui'           => true,
			'show_tagcloud'     => false,
			'hierarchical'      => true,
			'rewrite'           => array( 'slug' => 'resource', 'with_front' => false ),
			'query_var'         => true,
			'show_admin_column' => true,
			// 'meta_box_cb'    => false,
		);
		register_taxonomy( 'resource_type', array( 'resource' ), $args );
	}
	/**
	 * Register the Resource Topic
	 *
	 * @since 1.2.0
	 */
	function tax_resource_topic() {
		$labels = array(
			'name'                       => 'Resource Topics',
			'singular_name'              => 'Topic',
			'search_items'               => 'Search Topics',
			'popular_items'              => 'Popular Topics',
			'all_items'                  => 'All Topics',
			'parent_item'                => 'Parent Topic',
			'parent_item_colon'          => 'Parent Topic:',
			'edit_item'                  => 'Edit Topic',
			'update_item'                => 'Update Topic',
			'add_new_item'               => 'Add New Topic',
			'new_item_name'              => 'New Topic',
			'separate_items_with_commas' => 'Separate Topics with commas',
			'add_or_remove_items'        => 'Add or remove Topics',
			'choose_from_most_used'      => 'Choose from most used Topics',
			'menu_name'                  => 'Topics',
		);
		$args = array(
			'labels'            => $labels,
			'public'            => true,
			'show_in_nav_menus' => true,
			'show_ui'           => true,
			'show_tagcloud'     => false,
			'hierarchical'      => true,
			'rewrite'           => array( 'slug' => 'resource-topic', 'with_front' => false ),
			'query_var'         => true,
			'show_admin_column' => true,
			// 'meta_box_cb'    => false,
		);
		register_taxonomy( 'resource_topic', array( 'resource' ), $args );
	}
	/**
	 * Register the Library Tag taxonomy
	 *
	 * @since 1.2.0
	 */
	function tax_library_tag() {
		$labels = array(
			'name'                       => 'Library Tags',
			'singular_name'              => 'Library Tag',
			'search_items'               => 'Search Tags',
			'popular_items'              => 'Popular Tags',
			'all_items'                  => 'All Tags',
			'parent_item'                => 'Parent Tag',
			'parent_item_colon'          => 'Parent Tag:',
			'edit_item'                  => 'Edit Tag',
			'update_item'                => 'Update Tag',
			'add_new_item'               => 'Add New Tag',
			'new_item_name'              => 'New Tag',
			'separate_items_with_commas' => 'Separate Tags with commas',
			'add_or_remove_items'        => 'Add or remove Tags',
			'choose_from_most_used'      => 'Choose from most used Tags',
			'menu_name'                  => 'Tags',
		);
		$args = array(
			'labels'            => $labels,
			'public'            => true,
			'show_in_nav_menus' => true,
			'show_ui'           => true,
			'show_tagcloud'     => false,
			'hierarchical'      => false,
			'rewrite'           => array( 'slug' => 'library-tag', 'with_front' => false ),
			'query_var'         => true,
			'show_admin_column' => true,
			// 'meta_box_cb'    => false,
		);
		register_taxonomy( 'library_tag', array( 'resource', 'learning' ), $args );
	}
	/**
	 * Register the custom post type
	 *
	 * @since 1.2.0
	 */
	function register_cpt() {
		$labels = array(
			'name'               => 'Resources',
			'singular_name'      => 'Resource',
			'add_new'            => 'Add New',
			'add_new_item'       => 'Add New Resource',
			'edit_item'          => 'Edit Resource',
			'new_item'           => 'New Resource',
			'view_item'          => 'View Resource',
			'search_items'       => 'Search Resources',
			'not_found'          => 'No Resources found',
			'not_found_in_trash' => 'No Resources found in Trash',
			'parent_item_colon'  => 'Parent Resource:',
			'menu_name'          => 'Resources',
		);
		$args = array(
			'labels'              => $labels,
			'hierarchical'        => false,
			'supports'            => array( 'title', 'editor', 'thumbnail', 'revisions', 'author', 'comments', 'discussion' ),
			'public'              => true,
			'show_ui'             => true,
			'show_in_menu'        => true,
			'show_in_nav_menus'   => true,
			'publicly_queryable'  => true,
			'exclude_from_search' => false,
			'has_archive'         => true,
			'query_var'           => true,
			'can_export'          => true,
			'rewrite'             => array( 'slug' => 'resource/%resource_type%', 'with_front' => false ),
			'menu_icon'           => 'dashicons-format-aside', // https://developer.wordpress.org/resource/dashicons/
		);
		register_post_type( 'resource', $args );
	}
	/**
	 * Rewrite Rules
	 *
	 */
	function rewrite_rules() {
		add_rewrite_rule( 'resource/page/?([0-9]{1,})/?$', 'index.php?post_type=resource&paged=$matches[1]', 'top' );
		add_rewrite_rule( 'resource/(.+)/page/?([0-9]{1,})/?$', 'index.php?resource_type=$matches[2]&paged=$matches[3]', 'top' );
		add_rewrite_rule( 'resource/?$', 'index.php?post_type=resource', 'top' );
	}
	/**
	 * Post Type Link
	 *
	 */
	function post_type_link( $link, $post ) {
		if( 'resource' != $post->post_type )
			return $link;
		$term = ea_first_term( 'resource_type', false, $post->ID );
		$slug = !empty( $term ) && ! is_wp_error( $term ) ? $term->slug : 'uncategorized';
		$link = str_replace( '%resource_type%', $slug, $link );
		return $link;
	}
	/**
	 * Post Type Archive Link
	 *
	 */
	function post_type_archive_link( $link, $post_type ) {
		if( 'resource' == $post_type )
			$link = str_replace( '/%resource_type%', '', $link );
		return $link;
	}
	/**
	 * Archive Query
	 *
	 */
	function archive_query( $query ) {
		if( $query->is_main_query() && ! is_admin() && ea_is_resource_library() ) {
			$query->set( 'posts_per_page', 20 );
			$tax_query = ea_get_tax_query();
			if( !empty( $tax_query ) )
				$query->set( 'tax_query', $tax_query );
		}
	}
}
new EA_Resource();
/**
 * Is Resource Library? conditional
 *
 */
function ea_is_resource_library() {
	return is_post_type_archive( 'resource' ) || is_tax( array( 'resource_type', 'resource_topic', 'library_tag' ) );
}

Bill Erickson

Bill Erickson is the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk