I have a custom post type named ‘advert’ and a related custom taxonomy named ‘advert_category’, created by a 3rd party plugin. I run in a plugin an if
statement that must to set (as I expect) a specific theme layout for single adverts (example.com/advert/a-single-advert.html) and for custom taxonomy archive pages (example.com/advert-category/services/), but the second condition is_tax( 'advert_category' )
doesn’t work. What is wrong here?
My code:
function my_advert_single_template( ) {
global $post;
global $wpgo_global_column_layout;
if ( $post->post_type == 'advert' || is_tax( 'advert_category' ) ) {
$wpgo_global_column_layout = "2-col-l";
}
}
add_filter( 'single_template', 'my_advert_single_template' );
This is how the custom post type and the custom taxonomy are registered:
// register post type and taxonomy in order to allow default data insertion.
register_post_type( 'advert' );
register_taxonomy( 'advert_category', 'advert' );
$hid = wp_insert_post(array(
'post_type' => 'page',
'post_status' => 'publish',
'post_title' => 'Adverts',
'comment_status' => 'closed',
'ping_status' => 'closed',
'post_content' => "[adverts_list]"
));
$aid = wp_insert_post(array(
'post_type' => 'page',
'post_status' => 'publish',
'post_title' => 'Add',
'post_parent' => $hid,
'comment_status' => 'closed',
'ping_status' => 'closed',
'post_content' => "[adverts_add]"
));
$mid = wp_insert_post(array(
'post_type' => 'page',
'post_status' => 'publish',
'post_title' => 'Manage',
'post_parent' => $hid,
'comment_status' => 'closed',
'ping_status' => 'closed',
'post_content' => "[adverts_manage]"
));
wp_insert_term(
'Default',
'advert_category'
);
You hava a lot of issues here:
-
pre_get_posts
is not the correct hook to set templates. pre_get_posts
are used to alter the ain query query vars just before the SQL are build to run the main query’s query
-
A filter should always return something. Not doing this will have unexpected behavior, and forgetting about this can have you on a wild goose chase for hours debugging the issue.
-
Using globals to control theme features or to store any kind of data is bad practice and not very safe coding. WordPress has already made such a huge mess of globals, particularly naming conventions. Just check how newbies (that does not know WordPress) unknowingly use variable like $post
and $posts
as local variables. These are native globals uses by WordPress, and using them as local variables breaks the values of these globals.
Because of this, something on the page goes wrong, there are no errors, so you are stuck on a wild goose chase trying to debug something that you have unknowingly broke. Globals are pure evil and you should avoid using them. Just think, if you use the variable $wpgo_global_column_layout
for the query arguments of a custom query, you will break the value of the template that needs to be set, your template does not load because the value of $wpgo_global_column_layout
are not recognized as a valid template name, you are stuffed and don’t know why your template does not load as your code are 100% that should load a custom template
-
is_tax()
is the wrong check to use to check whether a post has a certain term or not, is_tax()
simply checks if you are on a taxonomy archive or not. You should be using has_term()
which do just that, checks if a certain post has a certain term
-
If you need to set a template for a taxonomy page, single_template
is the wrong hook, you should be using the taxonomy_template
hook or the more generic template_include
filter
-
In the line $post->post_type == 'advert' || is_tax( 'advert_category' )
, I suspect you are using the wrong operator. You should be using the AND
operator. I’m not going to explain this here as I already done something similar here. Note that, with the current setup, whenever you are viewing a post from the post type advert
, your condition will return true and fire whether or not the second condition (is_tax( 'advert_category' )
) fails.
-
If you need to target a term according to parent_child order, you simply need to check the term object’s $parent
property. A value of 0
means the term is a parent, any other value means that the term is a child/grandchild/grand-grandchild/etc term
Lets drop the crappy globals and set the templates properly. I do not know how your theme exactly sets templates through the $wpgo_global_column_layout
, but the following should work with priority. I have commented the code to make it easy to follow
FOR SINGLE PAGES:
add_filter( 'single_template', function ( $template )
{
// Remove all filters from the current filter
remove_all_filters( current_filter(), PHP_INT_MAX );
/**
* Get the current single post object. We will use get_queried_object
* as it is safer to use as $post
*
* @see https://wordpress.stackexchange.com/q/167706/31545
*/
$current_post = get_queried_object();
// Check if the current post belongs to the advert post type, if not, bail
if ( $current_post->post_type !== 'advert' )
return $template;
// Get the post terms
$terms = get_the_terms(
$current_post, // Current post object
'advert_category' // Taxonomy name
);
// If $terms are empty or throws a WP_Error object, bail
if ( !$terms || is_wp_error( $terms ) )
return $template
/**
* Get the first term and check if it is a top level term or not.
* Load template according to parent value
*
* NOTE, this only work correctly if the post has one term only
*/
if ( $terms[0]->parent == 0 ) {
$part="single-parent.php"; // Set the template to use for parent terms
} else {
$part="single-child.php"; // Set the child term template
}
// Check if the template exists, if not bail
$locate_template = locate_template( $part );
if ( !$locate_template )
return $template;
// We have reached this point, set our custom template
return $template = $locate_template;
}, PHP_INT_MAX + 1 );
FOR TAXONOMY PAGES:
add_filter( 'taxonomy_template', function ( $template )
{
// Remove all filters from the current filter
remove_all_filters( current_filter(), PHP_INT_MAX );
// Get the current term object. We will use get_queried_object
$current_term = get_queried_object();
// If the current term does not belong to advert post type, bail
if ( $current_term->taxonomy !== 'advert_category' )
return $template;
// Check if the term is top level or not and set template accordingly
if ( $current_term->parent == 0 ) {
$part="taxonomy-parent.php"; // Set the template to use for parent terms
} else {
$part="taxonomy-child.php"; // Set the child term template
}
// Check if the template exists, if not bail
$locate_template = locate_template( $part );
if ( !$locate_template )
return $template;
// We have reached this point, set our custom template
return $template = $locate_template;
}, PHP_INT_MAX + 1 );
Just one note, all the code is untested, so make sure to test it locally first with debug set to true. Also modify and abuse the code to suit your needs