0

My Site has 2 Custom Post Types with a 2 Taxonomies. One taxonomy is “Location” which is 2 level / hierarchical (Country, City). My goal is to get our Post Types & Taxonomies in a SEO Pretty Permalink structure. I have completed most of the Permalink structure but I am still getting 404’s errors on the Post / Slug Landing pages. I am halfway there and I have ran out of patience, I have tried dozens of solutions and they all seem to break one thing or another.

Post Types: Excursion, Stay-Dive

Taxonomies: Location, Excursion-Category

Taxonomy Pages:

Working - /location/%LocationCountry%/

Working - /location/%LocationCountry%/%LocationCity%/

Post Type Pages:

Working - /stay-dive/%LocationCountry%/

Working - /stay-dive/%LocationCountry%/%LocationCity%/

Not Working /stay-dive/%LocationCountry%/%LocationCity%/Slug - Not Working

Working - /excursion/%LocationCountry%/

Not Working - /excursion/%LocationCountry%/%LocationCity%/

Not Working - /excursion/%LocationCountry%/%LocationCity%/Slug

Working - /excursion/%excursion-category%/

Not Working - /excursion/%excursion-category%/%LocationCountry%/

Not Working - /excursion/%excursion-category%/%LocationCountry%/%LocationCity%/

Taxonomy Code:

    // excursion category
register_taxonomy('pdm_excursion_category', array('pdm_excursion'), array(
    'labels' => array(
        'name'                       => _x('Categories', 'taxonomy general name', 'pdm'),
        'singular_name'              => _x('Category', 'taxonomy singular name', 'pdm'),
        'menu_name'                  => __('Categories', 'pdm'),
        'all_items'                  => __('All Categories', 'pdm'),
        'edit_item'                  => __('Edit Category', 'pdm'),
        'view_item'                  => __('View Category', 'pdm'),
        'update_item'                => __('Update Category', 'pdm'),
        'add_new_item'               => __('Add New Category', 'pdm'),
        'new_item_name'              => __('New Category Name', 'pdm'),
        'parent_item'                => __('Parent Category', 'pdm'),
        'parent_item_colon'          => __('Parent Category:', 'pdm'),
        'search_items'               => __('Search Categories', 'pdm'),
        'popular_items'              => __('Popular Categories', 'pdm'),
        'separate_items_with_commas' => __('Separate categories with commas', 'pdm'),
        'add_or_remove_items'        => __('Add or remove categories', 'pdm'),
        'choose_from_most_used'      => __('Choose from the most used categories', 'pdm'),
        'not_found'                  => __('No categories found.', 'pdm'),
    ),
    'show_ui'           => true,
    'show_admin_column' => true,
    'hierarchical'      => true,
    'query_var'         => true,
    'rewrite'           => array('slug' => 'excursions', 'with_front' => true, 'hierarchical' => false),
));

// location
register_taxonomy('pdm_location', array('pdm_hotel', 'pdm_excursion', 'pdm_dive_site'), array(
    'labels' => array(
        'name'                       => _x('Locations', 'taxonomy general name', 'pdm'),
        'singular_name'              => _x('Location', 'taxonomy singular name', 'pdm'),
        'menu_name'                  => __('Locations', 'pdm'),
        'all_items'                  => __('All Locations', 'pdm'),
        'edit_item'                  => __('Edit Location', 'pdm'),
        'view_item'                  => __('View Location', 'pdm'),
        'update_item'                => __('Update Location', 'pdm'),
        'add_new_item'               => __('Add New Location', 'pdm'),
        'new_item_name'              => __('New Location Name', 'pdm'),
        'parent_item'                => __('Parent Location', 'pdm'),
        'parent_item_colon'          => __('Parent Location:', 'pdm'),
        'search_items'               => __('Search Locations', 'pdm'),
        'popular_items'              => __('Popular Locations', 'pdm'),
        'separate_items_with_commas' => __('Separate locations with commas', 'pdm'),
        'add_or_remove_items'        => __('Add or remove locations', 'pdm'),
        'choose_from_most_used'      => __('Choose from the most used locations', 'pdm'),
        'not_found'                  => __('No locations found.', 'pdm'),
    ),
    'show_ui'       => true,
    'show_admin_column' => true,
    'hierarchical'      => true,
    'query_var'         => true,
    'rewrite'           => array('slug' => 'location', 'with_front' => false, 'hierarchical' => true),
));

Post Type Code:

// hotel
register_post_type('pdm_hotel' , array(
    'labels' => array(
        'name'               => _x('Stay & Dive Hotels', 'post type general name', 'pdm'),
        'singular_name'      => _x('Stay & Dive', 'post type singular name', 'pdm'),
        'menu_name'          => _x('Stay & Dive Hotels', 'admin menu', 'pdm'),
        'name_admin_bar'     => _x('Stay & Dive Hotel', 'add new on admin bar', 'pdm'),
        'add_new'            => _x('Add New', 'book', 'pdm'),
        'add_new_item'       => __('Add New Hotel', 'pdm'),
        'new_item'           => __('New Stay & Dive Hotel', 'pdm'),
        'edit_item'          => __('Edit Stay & Dive Hotel', 'pdm'),
        'view_item'          => __('View Stay & Dive Hotel', 'pdm'),
        'all_items'          => __('All Stay & Dive Hotels', 'pdm'),
        'search_items'       => __('Search Stay & Dive Hotels', 'pdm'),
        'parent_item_colon'  => __('Parent Stay & Dive Hotel:', 'pdm'),
        'not_found'          => __('No hotels found.', 'pdm'),
        'not_found_in_trash' => __('No hotels found in Trash.', 'pdm'),
    ),
    'public'             => true,
    'publicly_queryable' => true,
    'show_ui'            => true,
    'show_in_menu'       => true,
    'query_var'          => true,
    'rewrite'        => array('slug' => 'stay-dive/%pdm_location%/%pdm_location2%', 'with_front' => true),
    'capability_type'    => 'post',
    'has_archive'        => true,
    'hierarchical'       => false,
    'menu_position'      => 101,
    'menu_icon'          => 'dashicons-admin-home',
    'supports'           => array('title','editor','thumbnail'),
    'taxonomies'         => array('pdm_location'),
));

// excursions
register_post_type('pdm_excursion' , array(
    'labels' => array(
        'name'               => _x('Excursions', 'post type general name', 'pdm'),
        'singular_name'      => _x('Excursion', 'post type singular name', 'pdm'),
        'menu_name'          => _x('Excursions', 'admin menu', 'pdm'),
        'name_admin_bar'     => _x('Excursion', 'add new on admin bar', 'pdm'),
        'add_new'            => _x('Add New', 'book', 'pdm'),
        'add_new_item'       => __('Add New Excursion', 'pdm'),
        'new_item'           => __('New Excursion', 'pdm'),
        'edit_item'          => __('Edit Excursion', 'pdm'),
        'view_item'          => __('View Excursion', 'pdm'),
        'all_items'          => __('All Excursions', 'pdm'),
        'search_items'       => __('Search Excursions', 'pdm'),
        'parent_item_colon'  => __('Parent Excursion:', 'pdm'),
        'not_found'          => __('No excursions found.', 'pdm'),
        'not_found_in_trash' => __('No excursions found in Trash.', 'pdm'),
    ),
    'public'             => true,
    'publicly_queryable' => true,
    'show_ui'            => true,
    'show_in_menu'       => true,
    'query_var'          => true,
    'rewrite'        => array('slug' => 'excursion  /%pdm_excursion_category%/%pdm_location%/%pdm_location2%','with_front' => true),
    'capability_type'    => 'post',
    'has_archive'        => true,
    'hierarchical'       => false,
    'menu_position'      => 102,
    'menu_icon'          => 'dashicons-location',
    'supports'           => array('title','editor','thumbnail'),
    'taxonomies'         => array('pdm_location','pdm_excursion_category'),
));
  • 1
    It’s never going to work with just rewrites alone, as you have identical patterns that could be either a term or a post. You’ll need to hook into query parsing and do some manual disambiguation. – Milo Dec 11 '18 at 23:24
  • I determined I will use "excursions" for the taxonomy and "excursion" for the CPT will that work? – Enkode Dec 12 '18 at 0:48
0

Found a git repo that had the solution: https://github.com/hemal21/WordPress-CPT-Hierarchical-Taxonomy-Permalinks/blob/master/cpt-hierarchical-tax-permalinks.php

I needed do a rewrite, Here is an example of working pretty permalink code:

    <?php
/**
 * WordPress Custom Post Type and Hierarchical Taxonomy Permalinks
 *
 * Ever wanted to have custom taxonomy permalinks that reflect parent/child relation?
 * Then this is for you. Still in development though.
 *
 * @version 1.0b
 * @author Kenth Hagström
 * @link http://www.facebook.com/keha76
 * @license GNU General Public License v2
 *
 * Last updated 19 sep 2013, 15:30(GMT+1)
 *
 * KNOWN BUGS:
 * - When a 'photo' is published without any taxonomy, the URL url.tld/photos/john does not work.
 * - The full URL url.tld/photos/family/kids/john/ has an unwanted trailing slash.
 *
 * These URL structures work:
 * url.tld/photos/ loads archive-photo.php
 * url.tld/photos/family/ loads taxonomy-album.php
 * url.tld/photos/family/kids/ loads taxonomy-album.php
 * url.tld/photos/family/kids/john loads single-photo.php
 * url.tld/photos/page/2 loads page 2 with archive-photo.php
 *
 * If you try this code, remember to flush your permalinks. Go to 'settings->permalinks' and it's done.
 *
**/
function keha_register_photo_tax_album() {

        $labels = array(
                'name'              => _x( 'Albums', 'taxonomy general name', 'blank' ),
                'singular_name'     => _x( 'Album', 'taxonomy singular name', 'blank' ),
                'search_items'      => __( 'Search Albums', 'blank' ),
                'all_items'         => __( 'All Albums', 'blank' ),
                'parent_item'       => __( 'Parent Album', 'blank' ),
                'parent_item_colon' => __( 'Parent Album:', 'blank' ),
                'edit_item'         => __( 'Edit Album', 'blank' ),
                'update_item'       => __( 'Update Album', 'blank' ),
                'add_new_item'      => __( 'Add New Album', 'blank' ),
                'new_item_name'     => __( 'New Album Name', 'blank' ),
                'menu_name'         => __( 'Albums', 'blank' ),
        );      

        $rewrite = array(
                'slug' => 'album',
                'with_front' => false,
                'hierarchical' => true
        );

        $args = array(
                'hierarchical' => true,
                'labels'       => $labels,
                'show_ui'      => true,
                'query_var'    => true,
                'rewrite'      => $rewrite
        );
        register_taxonomy( 'album', array( 'photo' ), $args );
}
add_action( 'init', 'keha_register_photo_tax_album' );

function keha_register_cpt_photo() {

        $labels = array(
                'name'               => __( 'Photos', 'blank' ),
                'singular_name'      => _x( 'Photo', 'Photo post type singular', 'blank' ),
                'add_new'            => __( 'Add New', 'blank' ),
                'add_new_item'       => __( 'Add New Photo', 'blank' ),
                'edit_item'          => __( 'Edit Photo', 'blank' ),
                'new_item'           => __( 'New Photo', 'blank' ),
                'all_items'          => __( 'All Photos', 'blank' ),
                'view_item'          => __( 'View Photo', 'blank' ),
                'search_items'       => __( 'Search Photos', 'blank' ),
                'not_found'          => __( 'No photos found', 'blank' ),
                'not_found_in_trash' => __( 'No photos found in Trash', 'blank' ),
                'parent_item_colon'  => '',
                'menu_name'          => __( 'Photos', 'blank' )
        );

        $rewrite = array(
                'slug' => 'photos',
                'hierarchical' => true,
                'with_front' => true
        );

        $args = array(
                'labels'               => $labels,
                'exclude_from_search'  => false,
                'publicly_queryable'   => true,
                'show_ui'              => true,
                'show_in_nav_menus'    => true,
                'show_in_menu'         => true,
                'show_in_admin_bar'    => true,
                'menu_position'        => 20,
                'menu_icon'            => null, // Handled from CSS
                'capability_type'      => 'post',
                'hierarchical'         => false,
                'public'               => true,
                'supports'             => array( 'title', 'editor', 'thumbnail' ),
                'taxonomies'           => array( 'album' ),
                'rewrite'              => $rewrite,
                'has_archive'          => true,
                'query_var'            => true,
                'can_export'           => true
        );

        register_post_type( 'photo', $args );
}
add_action( 'init', 'keha_register_cpt_photo' );

function keha_add_rewrite_rules() {
        add_rewrite_rule( '^photos/(.+?)/(.+?)/(.+?)$', 'index.php?album=$matches[1]&album=$matches[2]&photo=$matches[3]', 'top' );
        add_rewrite_rule( '^photos/(.+?)/(.+?)/$', 'index.php?photo=$matches[2]', 'top' );
        add_rewrite_rule( '^photos/(.+?)/(.+?)/(.+?)$', 'index.php?photo=$matches[3]', 'top' );
        add_rewrite_rule( '^photos/(.+?)/(.+?)/?$', 'index.php?album=$matches[2]', 'top' );
        add_rewrite_rule( '^photos/(.+?)$', 'index.php?album=$matches[1]', 'top' );
}
add_action('init', 'keha_add_rewrite_rules');

function keha_post_type_link( $post_link, $post, $leavename ) {

        global $wp_rewrite;

        $draft_or_pending = isset( $post->post_status ) && in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) );
        if ( $draft_or_pending and !$leavename ) {
                return $post_link;
        }

        if ( $post->post_type == 'photo' ) {

                $post_type_object = get_post_type_object( $post->post_type );
                $post_link = home_url() . '/' . $post_type_object->rewrite['slug'] . '/';
                $parent_dirs = '';
                if ( $terms = get_the_terms( $post->ID, 'album' ) ) {
                        foreach ( $terms as $term ) {
                                if ( $term->parent != 0 ) {
                                        $dirs = keha_get_taxonomy_parents( $term->term_id, 'album', false, '/', true );
                                } else {
                                        $dirs = $term->slug.'/';
                                }
                        }
                }
                $post_link = $post_link . $dirs . $post->post_name;
        }

        return $post_link;
}
add_filter( 'post_type_link', 'keha_post_type_link', 10, 3 );

/**
 * Custom function based on WordPress own get_category_parents()
 * @link http://core.trac.wordpress.org/browser/tags/3.6.1/wp-includes/category-template.php#L0
 *
 * @param integer $id
 * @param string $taxonomy
 * @param string $link
 * @param string $separator
 * @param string $nicename
 * @param array $visited
 * @return string
 */
function keha_get_taxonomy_parents( $id, $taxonomy = 'category', $link = false, $separator = '/', $nicename = false, $visited = array() ) {
        $chain = '';
        $parent = get_term( $id, $taxonomy, OBJECT, 'raw');
        if ( is_wp_error( $parent ) ) {
                return $parent;
        }

        if ( $nicename ){
                $name = $parent->slug;
        } else {
                $name = $parent->name;
        }

        if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array( $parent->parent, $visited ) ) {
                $visited[] = $parent->parent;
                $chain .= keha_get_taxonomy_parents( $parent->parent, $taxonomy, $link, $separator, $nicename, $visited );
        }

        if ( $link ) {
                $chain .= '<a href="' . get_term_link( $parent->term_id, $taxonomy ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $parent->name ) ) . '">'.$name.'</a>' . $separator;
        }else {
                $chain .= $name.$separator;
        }
        return $chain;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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