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 a freelance WordPress developer and a contributing developer to the Genesis framework. For the past 14 years he has worked with attorneys, publishers, corporations, and non-profits, building custom websites tailored to their needs and goals.

Ready to upgrade your website?

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

Let's Talk