custom post types - Pretty Permalinks with CTP and TaxonomiesHierarchical

admin2025-06-05  4

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'),
));

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'),
));
Share Improve this question edited Dec 11, 2018 at 21:59 Enkode asked Dec 11, 2018 at 20:42 EnkodeEnkode 515 bronze badges 2
  • 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 Commented Dec 11, 2018 at 23:24
  • I determined I will use "excursions" for the taxonomy and "excursion" for the CPT will that work? – Enkode Commented Dec 12, 2018 at 0:48
Add a comment  | 

1 Answer 1

Reset to default 0

Found a git repo that had the solution: https://github/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/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/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;
}
转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1749093197a316305.html

最新回复(0)