locate_template with multiple categories?

in this example (from Wrox book), if a single-category-$slug.php file exists, it will be shown, otherwise it’s the single.php file. But if we have more than one category for each post (let’s consider that the array $templates will contain more than one result), what will $templatecontain? where do we choose the right slug with this code?


add_filter( 'single_template', 'boj_single_template' );

function boj_single_template( $template ) {
    global $wp_query;

    /* Check if viewing a singular post. */
    if ( is_singular( 'post' ) ) {

        /* Get the post ID. */
        $post_id = $wp_query->get_queried_object_id();

        /* Get the post categories. */
        $terms = get_the_terms( $post_id, 'category' );

        /* Loop through the categories, adding slugs as part of the file name. */
        $templates = array();
        foreach ( $terms as $term )
            $templates[] = "single-category-{$term->slug}.php";

        /* Check if the template exists. */
        $locate = locate_template( $templates );

        /* If a template was found, make it the new template. */
        if ( !empty( $locate ) )
            $template = $locate;

    /* Return the template file name. */
    return $template;



Solutions Collecting From Web of "locate_template with multiple categories?"

The code you posted is looping through all the categories that the post is assigned.

The foreach constructs a string representing every possible template file that it wants to check for and assigns them all to $template.

The locate_template() function will go through the $templates array and return the first one of them that actually exists. Thats what will be assigned to the $template variable.

If it turns out that none of the files exist, I believe locate_template() will return false. Your code there simply checks to see if locate_template() found any of the templates before assigning it to $template.

The whole function then returns the name of that template to the filter, which will load that template if you return an actual string, otherwise it will continue down the template hierarchy to the next type of template after ‘single’.

Edit: Additional information

get_the_terms uses wp_get_object_terms which by default will return the terms in ascending order by name so if a post is in multiple categories you will always be loading the template of the first term alphabetically. To change this behavior use wp_get_object_terms directly and specify the orderby arg to ‘count’, ‘slug’, ‘term_group’, ‘term_order’, or ‘term_id’.