4

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'
);
  • 1
    You are using your filter wrongly. This is very important info that should have been in your original post. I'm not being rude, but it is really frustrating if we go in circles just to find out that very important info was left out – Pieter Goosen Nov 22 '15 at 7:09
  • Please move solution you worked out into a separate answer. :) That is more in line with site's mechanics. – Rarst Nov 22 '15 at 12:40
  • @pieter-goosen Now I am analyzing your answer here: wordpress.stackexchange.com/a/156325/25187. – Iurie Malai Nov 22 '15 at 16:39
6

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

  • Doesn't work :(. From the FunctionReference/has term: "Check if the current post has any of the given terms", so, this will work only on single posts? – Iurie Malai Nov 22 '15 at 6:55
  • That works on single pages, what is the issue. Doesn't work is really broad – Pieter Goosen Nov 22 '15 at 6:57
  • I mean the page 'example.com/advert-category/services/' doesn't change the template. – Iurie Malai Nov 22 '15 at 7:00
  • Check my update. Hope this is what you are looking for – Pieter Goosen Nov 22 '15 at 16:44
  • Pieter, as always, an excellent answer! Thank you very much! – Iurie Malai Nov 22 '15 at 19:27
1

You have two problems in your function:

  • You are missing an argument in the "single_template" filter and therefore the filter is not returning what it should.
  • Also you are calling has_term() without specifying the taxonomy you are trying to search into.

Check this out:

function my_advert_single_template( $single_template ) {
    global $post;
    global $wpgo_global_column_layout;

    if ( $post->post_type == 'advert' || has_term( 'util-categorie', 'advert_category' ) ) {
        $wpgo_global_column_layout = "2-col-l";
    }

    return $single_template;
}
add_filter( 'single_template', 'my_advert_single_template' );
  • I fixed some errors in my old code (that was a testing variant, sorry, it seems that I don't woke up yet). And I tested your function, but it doesn't works for custom taxonomy pages, only for single posts. And I found a solution (see the update). – Iurie Malai Nov 22 '15 at 8:45
  • No worries! Glad you got it working. – Luis Sanz Nov 23 '15 at 11:04

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.