So we have constructed a front-page template that outputs our content in two defined loops rather than one “reverse-chronological” default loop.
But when we test, we see that too much content is being output in each article.
If we look at the screenshot on the page about the front-page template, we will see that we need the following in each article on the home page:
- Category
- Feature Image
- Post Title
To do this we will now edit the content.php file in the template-parts folder.
Maximizing Template Parts
This file is the default article output vehicle for most template files in underscores.
You will notice that there are more specific template-part files, though, for search, pages, and none (meaning search results, WP Pages, and when a loop query returns no results).
In other words, content.php gets called in the front-page, index, single, and archive templates.
Before modifying it, we should think about what we might want to see output in each of those situations. The screenshots suggest a few things, but I’ve added a couple additional forms below:
- Front Page: Category, Post Thumbnail (linked to single view), Post Title (linked to single view)
- Single Post View: Title (not linked), Content (which includes video), Tags & Categories, Custom Fields (country, director, year)
- Archive & Search: Title (linked to single view), Post Thumbnail (linked to single view), excerpt, Category
If we keep in mind what’s needed in different parts of the site, we might be able to write some very concise code. The key here will be the use of WordPress Conditional tags.
Our First Condition: Free With Underscores
Before we start editing, let’s be safe and duplicate content.php. Give the new file the name content-backup.php.
Now open the original content.php. When we do, we are confronted by the following code:
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <header class="entry-header"> <?php if ( is_singular() ) : the_title( '<h1 class="entry-title">', '</h1>' ); else : the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' ); endif; if ( 'post' === get_post_type() ) : ?> <div class="entry-meta"> <?php iff_posted_on(); iff_posted_by(); ?> </div><!-- .entry-meta --> <?php endif; ?> </header><!-- .entry-header --> <?php iff_post_thumbnail(); ?> <div class="entry-content"> <?php the_content( sprintf( wp_kses( /* translators: %s: Name of current post. Only visible to screen readers */ __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'iff' ), array( 'span' => array( 'class' => array(), ), ) ), get_the_title() ) ); wp_link_pages( array( 'before' => '<div class="page-links">' . esc_html__( 'Pages:', 'iff' ), 'after' => '</div>', ) ); ?> </div><!-- .entry-content --> <footer class="entry-footer"> <?php iff_entry_footer(); ?> </footer><!-- .entry-footer --> </article><!-- #post-<?php the_ID(); ?> -->
That might seem like a lot of code. However, if we focus on the HTML here, we see that this template part is outputting an article with three children (not counting the post-thumbnail, ie the feature image):
- a header (.entry-header)
- a div (.entry-content)
- a footer (.entry-footer)
Inside the .entry-header, the file tests to see if we’re on a single view of a post (ie the post on its own). If so, it outputs that post’s title in an H1. If we’re not on a single view of a post, the code outputs the post title (as an H2), but it’s wrapped in an anchor tag.
This means that almost every time the post title appears, it will be a link to the single view of the post.
This, then, is the essence of conditions: we can make tests of our our content and then have different output or formatting depending on what the tests say.
Obviously, however, we don’t want the title of a single post to link to that post when we’re already in single view. But on all other views, we do want those titles to link to the single post view.
If you test the front page of the site, you will see that the titles of articles are links. Click one of those links. This will take you to a single view of the post. Notice here (single view) that the title is not a link (because it would be redundant, as explained above).
Our Second Condition: Also Free With Underscores, But We Don’t Need it Here
The next condition in the content.php file is also in the .site-header. In this case, we don’t need that content at all, so delete the following code:
if ( 'post' === get_post_type() ) : ?> <div class="entry-meta"> <?php iff_posted_on(); iff_posted_by(); ?> </div><!-- .entry-meta --> <?php endif; ?>
Depending on what editor you’re using, you will now likely notice that the color of your code is now indicating a syntax error. The reason is that we next move into HTML, so be sure to close the PHP with a
?>
before continuing.
Test your page to make sure everything still works.
Our Third Condition: For the Post Thumbnail
As mentioned above, we will want the Post Thumbnail and the post excerpt to appear on all pages except the single view. On the single view, we will want the full content rather than the excerpt, and we will NOT want the Post Thumbnail because the content starts with the video (and the post thumbnail is just a screenshot of the video, so it’s redundant there).
Here we’ll take care of the post-thumbnail condition.
If you look just below the header code, you’ll see a function called yourthemename_post_thumbnail. ( Since I called my theme IFF, that function is called iff_post_thumbnail. )
If we were writing our theme completely from scratch, we would probably just use the default WordPress post_thumbnail function to output the feature image, then we would wrap it in an HTML anchor tag with an href value of the_permalink() passed via PHP.
However, underscores includes a number of functions that expand on the default WordPress functions, so we would do well to investigate.
A Detour into Underscores’ Included Functions
Before we do the next part, please install the Atom package goto definition and restart Atom.
Now, right-click on the iff_post_thumbnail function and choose Goto definition. This will take you to one place underscores defines extra functions: a file called template-tags.php inside the inc folder.
if ( ! function_exists( 'iff_post_thumbnail' ) ) : /** * Displays an optional post thumbnail. * * Wraps the post thumbnail in an anchor element on index views, or a div * element when on single views. */ function iff_post_thumbnail() { if ( post_password_required() || is_attachment() || ! has_post_thumbnail() ) { return; } if ( is_singular() ) : ?> <div class="post-thumbnail"> <?php the_post_thumbnail(); ?> </div><!-- .post-thumbnail --> <?php else : ?> <a class="post-thumbnail" href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1"> <?php the_post_thumbnail( 'post-thumbnail', array( 'alt' => the_title_attribute( array( 'echo' => false, ) ), ) ); ?> </a> <?php endif; // End is_singular(). } endif;
The comment at the top explains what’s going on here: in single view, the feature image is output in a DIV. In other views, it is output wrapped in a link to the single view.
We need to change this to the following behavior:
- in single post view, no feature image is output
- in any other view, feature images appear, wrapped in links to the single view
To do that is actually quite easy here.
First, remove the DIV with a class of post-thumbnail. We won’t need, anywhere on the site, a feature image that is NOT wrapped in a link to the single view.
In other words, we do not need to test if we are in a single view of a post. Rather, we need to test if we are NOT on a single view. Our condition, then, just became simpler, too: rather than an IF..ELSE condition, we will need only an IF.
To make the condition a negative one (ie not on a single view), put an EXCLAMATION MARK in front of the test, so is_singular() becomes ! is_singular() .
Be sure to remove the ELSE part of the condition, too.
This is the code we are left with (comment code omitted for brevity).
if ( ! function_exists( 'iff_post_thumbnail' ) ) : ion iff_post_thumbnail() { if ( post_password_required() || is_attachment() || ! has_post_thumbnail() ) { return; } if ( ! is_singular() ) : ?> <a class="post-thumbnail" href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1"> <?php the_post_thumbnail( 'post-thumbnail', array( 'alt' => the_title_attribute( array( 'echo' => false, ) ), ) ); ?> </a> <?php endif; // End is_singular(). } endif;
If you test your site now, you’ll see we have achieved three desired objectives:
- we no longer see who posted each article or the date of each
- on any page other than a single post view, the feature image appears, and clicking it takes you to the single view
- on single post views, the feature image does not appear
Another Condition: the_content or the_excerpt
Now, go back to content.php.
If we look in the div with a class of entry-content, we see that there is immediately a call to the_content(). For now, ignore that’s in the brackets of the_content.
Every time that content.php is called, it is outputting the full content of the article. We need to change that to this type of behavior:
- on all pages other than single views, we need to see the_excerpt
- on single views of a post, we need to see the_content
In other words, we have an IF..ELSE condition.
Duplicate the call to the_content(). Change the second one to the_excerpt().
// ORIGINAL CALL the_content( sprintf( wp_kses( /* translators: %s: Name of current post. Only visible to screen readers */ __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'iff' ), array( 'span' => array( 'class' => array(), ), ) ), get_the_title() ) ); // DUPLICATED and MODIFIED CALL the_excerpt( sprintf( wp_kses( /* translators: %s: Name of current post. Only visible to screen readers */ __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'iff' ), array( 'span' => array( 'class' => array(), ), ) ), get_the_title() ) );
Now make a IF block and and ELSE block, like the code below. You need to add only three lines (the if, the else, and the endif)
if ( is_single() ) : the_content( sprintf( wp_kses( /* translators: %s: Name of current post. Only visible to screen readers */ __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'iff' ), array( 'span' => array( 'class' => array(), ), ) ), get_the_title() ) ); else : the_excerpt( sprintf( wp_kses( /* translators: %s: Name of current post. Only visible to screen readers */ __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'iff' ), array( 'span' => array( 'class' => array(), ), ) ), get_the_title() ) ); endif;
Pretty cool. With the addition of a mere three lines of code, our content.php file has become very versatile.
Test your site now.
Then move on to the next part of the exercise, in which we will output data collected with the Advanced Custom Fields plugin.