Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I'm trying to get permalinks working with custom taxonomies and custom post types. Following the instructions here I was able to get it almost working, but one small glitch.

The code to register the taxonomy looks like this:

$args = array( 
    'labels' => $labels,
    'public' => true,
    'show_in_nav_menus' => false,
    'show_ui' => true,
    'show_tagcloud' => true,
    'hierarchical' => true,
    'rewrite' => array('slug' => 'products', 'hierarchical' => true, 'with_front' => true),
    // 'rewrite' => true,
    'query_var' => true
);

register_taxonomy( 'tc_product_type', array('tc_products'), $args );

The code to register the post type:

$post_type_args = array(
    'labels'            => $labels,
    'singular_label'    => __('Product'),
    'public'            => true,
    'show_ui'           => true,
    'publicly_queryable'=> true,
    'query_var'         => true,
    'capability_type'   => 'post',
    'has_archive'       => true,
    'hierarchical'      => true,
    'rewrite'           => array('slug' => 'products/%taxonomy_name%/'),
    // 'rewrite'            => array('slug' => 'products', 'with_front' => false),
    'supports'          => $supports,
    'menu_position'     => 0,
    'taxonomies' => array('post_tag')
 );


register_post_type('tc_products',$post_type_args);

The permalinks themselves are created perfectly, and viewing the taxonomy pages works perfectly, but when viewing the post on the site, I get a 404. I dumped the WP_Query and it looks like it's using the last segment of the permalink URI as the tc_product_type, instead of the post slug (in the case the post slug is '77777-2'):

    WP_Query::__set_state(array(
   'query_vars' => 
  array (
    'tc_product_type' => '77777-2',
    'error' => '',
    'm' => 0,
    'p' => 0,
    'post_parent' => '',
    'subpost' => '',
    'subpost_id' => '',
    'attachment' => '',
    'attachment_id' => 0,
    'name' => '',
    'static' => '',
    'pagename' => '',
    'page_id' => 0,
    'second' => '',
    'minute' => '',
    'hour' => '',
    'day' => 0,
    'monthnum' => 0,
    'year' => 0,
    'w' => 0,
    'category_name' => '',
    'tag' => '',
    'cat' => '',
    'tag_id' => '',
    'author_name' => '',
    'feed' => '',
    'tb' => '',
    'paged' => 0,
    'comments_popup' => '',
    'meta_key' => '',
    'meta_value' => '',
    'preview' => '',
    's' => '',
    'sentence' => '',
    'fields' => '',
    'category__in' => 
    array (
    ),
    'category__not_in' => 
    array (
    ),
    'category__and' => 
    array (
    ),
    'post__in' => 
    array (
    ),
    'post__not_in' => 
    array (
    ),
    'tag__in' => 
    array (
    ),
    'tag__not_in' => 
    array (
    ),
    'tag__and' => 
    array (
    ),
    'tag_slug__in' => 
    array (
    ),
    'tag_slug__and' => 
    array (
    ),
    'ignore_sticky_posts' => false,
    'suppress_filters' => false,
    'cache_results' => true,
    'update_post_term_cache' => true,
    'update_post_meta_cache' => true,
    'post_type' => '',
    'posts_per_page' => 10,
    'nopaging' => false,
    'comments_per_page' => '50',
    'no_found_rows' => false,
    'taxonomy' => 'tc_product_type',
    'term' => '77777-2',
    'order' => 'DESC',
  ),
   'tax_query' => 
  WP_Tax_Query::__set_state(array(
     'queries' => 
    array (
      0 => 
      array (
        'taxonomy' => 'tc_product_type',
        'terms' => 
        array (
          0 => '77777-2',
        ),
        'include_children' => true,
        'field' => 'slug',
        'operator' => 'IN',
      ),
    ),
     'relation' => 'AND',
  )),
   'meta_query' => 
  WP_Meta_Query::__set_state(array(
     'queries' => 
    array (
    ),
     'relation' => NULL,
  )),
   'post_count' => 0,
   'current_post' => -1,
   'in_the_loop' => false,
   'comment_count' => 0,
   'current_comment' => -1,
   'found_posts' => '0',
   'max_num_pages' => 0,
   'max_num_comment_pages' => 0,
   'is_single' => false,
   'is_preview' => false,
   'is_page' => false,
   'is_archive' => false,
   'is_date' => false,
   'is_year' => false,
   'is_month' => false,
   'is_day' => false,
   'is_time' => false,
   'is_author' => false,
   'is_category' => false,
   'is_tag' => false,
   'is_tax' => false,
   'is_search' => false,
   'is_feed' => false,
   'is_comment_feed' => false,
   'is_trackback' => false,
   'is_home' => false,
   'is_404' => true,
   'is_comments_popup' => false,
   'is_paged' => false,
   'is_admin' => false,
   'is_attachment' => false,
   'is_singular' => false,
   'is_robots' => false,
   'is_posts_page' => false,
   'is_post_type_archive' => false,
   'query_vars_hash' => 'e63e67c24b4fac79b23b43e0704197c3',
   'query_vars_changed' => false,
   'thumbnails_cached' => false,
   'query' => 
  array (
    'tc_product_type' => 'cotton-candy/tasty-tubs-2/77777-2',
  ),
   'request' => ' SELECT SQL_CALC_FOUND_ROWS  tc_posts.* FROM tc_posts  WHERE 1=1  AND 0 = 1 AND tc_posts.post_type IN (\'post\', \'page\', \'attachment\', \'tc_testamonials\', \'tc_press\', \'tc_products\', \'tc_service\', \'tc_variant_group\', \'tc_variation_item\', \'tc_variation_rule\', \'tc_coupon\', \'tc_payment\', \'tc_order\', \'tc_contact\', \'tc_contact_address\', \'tc_project\', \'tc_activity\') AND (tc_posts.post_status = \'publish\' OR tc_posts.post_status = \'private\') GROUP BY tc_posts.ID ORDER BY tc_posts.post_date DESC LIMIT 0, 10',
   'posts' => 
  array (
  ),
   'queried_object' => NULL,
   'queried_object_id' => 0,
))

Am I missing something somewhere? How do I tell WP that the last segment is the page slug?

Edit: forgot something important. In the post linked to above, he creates the rewrite rules knowing that the page slug will always be at a particular segment in the permalink. This won't work in my case, as there will be posts under each taxonomy...meaning I won't know the exact position of the slug (except that it will be the end, of course). Is there a rewrite rule that would cover that scenario? How would it know whether the last segment is a taxonomy or post slug?

Edit 2: Adding a dump of the related rewrite rules:

array (
 'products/%taxonomy_name%/?$' => 'index.php?%taxonomy_name%$matches[1]',
 'products/%taxonomy_name%/feed/(feed|rdf|rss|rss2|atom)/?$' => 'index.php?%taxonomy_name%$matches[1]&feed=$matches[2]',
 'products/%taxonomy_name%/(feed|rdf|rss|rss2|atom)/?$' => 'index.php?%taxonomy_name%$matches[1]&feed=$matches[2]',
 'products/%taxonomy_name%/page/([0-9]{1,})/?$' => 'index.php?post_type=tc_products&paged=$matches[1]',

/*...more rules, then...*/

 'products/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$' => 'index.php?tc_product_type=$matches[1]&feed=$matches[2]',
 'products/(.+?)/(feed|rdf|rss|rss2|atom)/?$' => 'index.php?tc_product_type=$matches[1]&feed=$matches[2]',
 'products/(.+?)/page/?([0-9]{1,})/?$' => 'index.php?tc_product_type=$matches[1]&paged=$matches[2]',
 'products/(.+?)/?$' => 'index.php?tc_product_type=$matches[1]',

/*...more rules, then...*/


 'products/%taxonomy_name%/.+?/attachment/([^/]+)/?$' => 'index.php?attachment=$matches[1]',
 'products/%taxonomy_name%/.+?/attachment/([^/]+)/trackback/?$' => 'index.php?attachment=$matches[1]&tb=1',
 'products/%taxonomy_name%/.+?/attachment/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$' => 'index.php?attachment=$matches[1]&feed=$matches[2]',
 'products/%taxonomy_name%/.+?/attachment/([^/]+)/(feed|rdf|rss|rss2|atom)/?$' => 'index.php?attachment=$matches[1]&feed=$matches[2]',
 'products/%taxonomy_name%/.+?/attachment/([^/]+)/comment-page-([0-9]{1,})/?$' => 'index.php?attachment=$matches[1]&cpage=$matches[2]',
 'products/%taxonomy_name%/(.+?)/trackback/?$' => 'index.php?%taxonomy_name%$matches[1]&tc_products=$matches[2]&tb=1',
 'products/%taxonomy_name%/(.+?)/feed/(feed|rdf|rss|rss2|atom)/?$' => 'index.php?%taxonomy_name%$matches[1]&tc_products=$matches[2]&feed=$matches[3]',
 'products/%taxonomy_name%/(.+?)/(feed|rdf|rss|rss2|atom)/?$' => 'index.php?%taxonomy_name%$matches[1]&tc_products=$matches[2]&feed=$matches[3]',
 'products/%taxonomy_name%/(.+?)/page/?([0-9]{1,})/?$' => 'index.php?%taxonomy_name%$matches[1]&tc_products=$matches[2]&paged=$matches[3]',
 'products/%taxonomy_name%/(.+?)/comment-page-([0-9]{1,})/?$' => 'index.php?%taxonomy_name%$matches[1]&tc_products=$matches[2]&cpage=$matches[3]',
 'products/%taxonomy_name%/(.+?)(/[0-9]+)?/?$' => 'index.php?%taxonomy_name%$matches[1]&tc_products=$matches[2]&page=$matches[3]',
 'products/%taxonomy_name%/page/?([0-9]{1,})/?$' => 'index.php?%taxonomy_name%$matches[1]&paged=$matches[2]',
 'products/%taxonomy_name%/comment-page-([0-9]{1,})/?$' => 'index.php?%taxonomy_name%$matches[1]&cpage=$matches[2]',
/*...more rules...*/
)

It looks like it's matching this rule:

 'products/(.+?)/?$' => 'index.php?tc_product_type=$matches[1]',

Not sure how to make it match the others, or if the others are even valid rewrite rules.

share|improve this question
add comment

1 Answer

up vote 1 down vote accepted

Ok, I managed to get it working by hooking into the 'request' filter, then checking to see if the last segment is term or not. If it's not, change the $request var:

function alter_the_query( $request ) {
    $dummy_query = new WP_Query();  // the query isn't run if we don't pass any query vars
    $dummy_query->parse_query( $request );

    if ( !$dummy_query->is_admin && isset($request['tc_product_type']) ){       
        $lastSegment = basename($request['tc_product_type']);
        if(get_term_by('slug',$lastSegment,  'tc_product_type') === FALSE){
            $request['post_type'] = 'tc_products';
            $request['tc_products'] = $lastSegment;
            $request['name'] = $lastSegment;
        }
    }

    return $request;
}
add_filter( 'request', 'alter_the_query' );
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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