Wordpress - Creating multiple versions of the same single-customtype.php depending on selected taxonomy categories

I have registered a custom post type 'Clients' and a taxonomy for this post type for categorizing posts. There are currently 3 categories for a Client: 'Logo Project', 'Video Project' and 'Web Design' project.

Some Clients may belong to multiple categories.

On the Edit Page for a Clients post, I have a Flexible field layout builder that let's you generate 'blocks' of content for each category type (logo, web, video...). Each block will have unique fields relevant to each category (video upload tools for video, image galleries for logo etc..)

My issue is, that while I can display relevant content on taxonomy category pages (only show web-design for all Clients that are in the web design category...), once the user clicks to view this Client, the single-clients.php page has no way of ONLY displaying Web Design content and filtering out other 'Content blocks' in cases where a Client has > 1 content block.

Ideally I need multiple versions of the clients single template:

something like:

1) single-clients-web.php
2) single-clients-logo.php
3) single-clients-video.php
4) single-clients.php (shows all project blocks as it does now)


OR

somehow take a referral ID and write a conditional that if the user clicked on the client from the web design category page, the single page they are directed to only shows the web design fields.

-

migrated from stackoverflow.comNov 30 '12 at 14:54

This question came from our site for professional and enthusiast programmers.

Will each client be assigned to only one category? –  Nikola Ivanov Nikolov Nov 29 '12 at 21:09
No. Some clients might be placed into multiple categories. For example, if Logo, Web and Video services were provided for this client, they would be placed into all 3 of those categories. –  Alex Nov 29 '12 at 21:16

Okay, the following code should do the trick for you:

function get_clients_correct_template($single_template) { global$post;

if ( 'clients' == $post->post_type ) {$_template = false;
// Get all the terms for this post
$categories = wp_get_post_terms($post->ID, 'clients_categories' );
if ( $categories && ! is_wp_error($categories ) ) {
global $wp; // I guessed that the client category that's in the URL will be in the query, but it's not, so we have to get it from$wp->matched_query
if ( preg_match( '~clients_categories=[\w|\d|-]*&?~', $wp->matched_query ) ) {$slug = preg_replace( '~.*?clients_categories=([\w|\d|-]*)&?.*?$~', '\1',$wp->matched_query );
// See if the slug we found matches a slug of one of the client's categories
foreach ( $categories as$cat ) {
if ( $cat->slug ==$slug ) {
$_template = locate_template( array( "single-clients-{$slug}.php" ), false );
break;
}
}
}
// If we haven't found a template yet, just assign the first found template
if ( ! $_template ) {$_template = locate_template( array( "single-clients-{$categories[0]->slug}.php" ), false ); }$single_template = $_template ?$_template : $single_template; } } return$single_template;
}
// This is pre WP 3.4
// This is post WP 3.4

// Fixes the permalinks for the "clients" post type
function clients_custom_permalink($permalink,$post_id, $leavename) { if ( strpos($permalink, 'client/' ) === FALSE || ! ( $post = get_post($post_id ) ) || get_post_type( $post_id ) != 'clients' ) { return$permalink;
}

// Get taxonomy terms
$terms = wp_get_object_terms($post->ID, 'clients_categories' );
if ( ! is_wp_error( $terms ) && ! empty($terms ) && is_object( $terms[0] ) ) {$taxonomy_slug = false;
if ( is_tax( 'clients_categories' ) ) {
$term = get_queried_object();$taxonomy_slug = $term->slug; } else {$taxonomy_slug = $terms[0]->slug; } } else {$taxonomy_slug = 'no-category';
}
$replace_count = 1; return preg_replace( '~client/~',$taxonomy_slug . '/', $permalink,$replace_count );
}

// Fixes the URL's for taxonomy archives
function clients_categories_custom_permalink($permalink,$term, $taxonomy) { if ($taxonomy != 'clients_categories' ) {
return $permalink; } return home_url( "/{$term->slug}/" );
}

// Generates custom rewrite rules for recognizing the custom Permalink structure for both "clients" posts and "clients_categories" terms
function add_client_rewrite_rules( $wp_rewrite ) { static$did_rules = false;
if ( ! $did_rules ) {$additional_rules = array();
$terms = get_terms( 'clients_categories', array( 'hide_empty' => false ) ); if ($terms ) {
foreach ( $terms as$term ) {
// Add a rule for the taxonomy archives of the type "client-category-slug[/]" - the "/" is optional
$additional_rules[ "({$term->slug})/?$" ] = 'index.php?clients_categories=$matches[1]';
// Add a rule of the sort "client-category-slug/client-slug"
$additional_rules[ "({$term->slug})/([^/]*)" ] = 'index.php?clients_categories=$matches[1]&clients=$matches[2]';
// Add a rule of the sort "client-category-slug/parent-client-slug/client-slug"
$additional_rules[ "({$term->slug})/([^/]*)/([^/]*)" ] = 'index.php?clients_categories=$matches[1]&clients=$matches[3]';
}
$wp_rewrite->rules = array_merge($additional_rules, $wp_rewrite->rules ); }$did_rules = true;
}
}


As for a begining, I assumed that the slug of your custom post type is clients and the slug of your custom taxonomy is clients_cateogires - if any of those are incorrect, please find and replace those occurances in my code.

In the arguments for register_post_type() for your clients post type, you have to set rewrite to:

'rewrite' => array( 'slug' => 'clients', 'with_front' => false ),


Also in the arguments for register_taxonomy() you have to set rewrite to(any other slug will work as well):

'rewrite' => array( 'slug' => 'client-category', 'with_front' => false ),


So, the first function hooks to the single_template and clients_template filter hooks. You can read in detail about this hook here, but basically this hook allows you to change the template that is being loaded when a singular(page, post, custom post type post) post is being displayed. We hook to this function, so that we can load the appropriate template when a clients post is being loaded.

First we check that the post type of the current post is actually the target one(clients).

Then we get all categories associated with the current client. If there are no categories, we let WordPress load the default template.

If there are categories we first check to see if the queried URL contains a clients_categories slug. Initially I thought that WP would add the slug of the clients_categories that is part of the URL, but it seems that it doesn't. Instead I found that in the $matched_query property of the $wp object. If it matches a simple regular expression, we extract the slug and check it against the slugs of the categories that the current client is associated with. If one of them matches, we try to find a template single-clients-{$slug}.php. If we couldn't find the searched term, or the proper template for this term, we get the first category for this client and try to find the template for it(using it's slug). In the end if we have found an appropriate template, we set the $single_template variable to it, otherwise we preserver it's original value.

Now the second part replaces client/ from the clients permalink with the appropriate clients_categories slug for this client. Note that it also checks to see if we're on a term from the clients_categories taxonomy - if we are, it will use the slug of the current term. Otherwise it will add the slug of the first term that it finds.

The third part(clients_categories_custom_permalink()) fixes the URL's for the taxonomy archives - this way the "Web" category will be at http://example.com/web/.

The fourth part(add_client_rewrite_rules()) adds some custom rewrite rules - note, that for these to take effect, you have to go to Settings > Permalinks - so that WordPress knows what it should display when it encounters an URL like http://example.com/web/ or http://example.com/web/client-slug/.

Note that if you have a page with a slug that matches one of the slugs for your Clients Categories - you will most-likely see the taxonomy archive, instead of the page.

-
Wow man this looks great and looks like it was a lot of work. Much appreciated. I tested the code but I am getting a global error: Parse error: syntax error, unexpected 'break' (T_BREAK) in –  Alex Nov 29 '12 at 22:51
I'm also concerned too that although we have unique templates, each of the pages need to be indexed somehow...we can't just have an ever-changing single page that changes depending on where the user is coming from. If a post belongs to all 3 of the categories, there needs to be 3 total versions of that post, all indexable. So: domain.com/tax-category-webdesign/client-name/ domain.com/tax-category-logodesign/client-name –  Alex Nov 29 '12 at 23:18
About the error - it's the most common one for me - I was missing a ; on the line before break;. That's a proper concern, but wouldn't it be better if you simply have 3 clients for each category, instead of one for all 3? I mean it will be 1) easier and 2) each client will have it's unique URL. Although if you can make the different URL's link to the same client(so basically whatever term slug you use, it will end-up to the same client), then we might be able to make that work. –  Nikola Ivanov Nikolov Nov 30 '12 at 6:54
If we don't use this method, administrator will need to create multiple posts for one client such as: Client Logo Client Web Client Video Which will result in a lot of unorganized content. It'd be much easier to create one post on client, and when editing this post, be able to input content for each category - logo, web, video. –  Alex Nov 30 '12 at 17:01
I saw you updated. I can confirm that everything works now :) –  Alex Dec 3 '12 at 22:00