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 $template
contain? where do we choose the right slug with this code?
<?php
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;
}
?>
Thanks
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 iflocate_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
useswp_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 usewp_get_object_terms
directly and specify the orderby arg to ‘count’, ‘slug’, ‘term_group’, ‘term_order’, or ‘term_id’.