10. Single

This chapter is aptly named “Single” because the template theme file used to display a single post is called single.php. The single.php template is used anytime a user is on a post page (or nonhierarchical custom post type). Typically, the difference between the single and page template that powers a single page is additional metadata (dates, author, comment number) and the Comments section.

What you’re about to learn

• Additional Template Tags for pulling post data

• How to display author information

• How to enable commenting on a post

• How to display the comment form and styling the comments template

Post Page Layout

The post template page has a structure similar to the rest of the site (Figure 10.1). The header, footer, and sidebar are exactly the same as on the home page. The only area that’s different is the content area on the left. This is why it’s so important not to duplicate the code used to support the areas that are the same throughout the theme.

Image

Figure 10.1. The Post template page.

The content area starts with a featured image at the top. This file is used throughout the site, but here it’s cropped at a different size. Later, we’ll define the different sizes for all featured images.

Below the featured image is the title of the post, then the date and number of comments. This time the number of comments anchors to the Comments section below.

The content is pulled in with a single template tag, and that will display anything in the content editor, including text, images, videos, and more. Under the content are links to the categories and tags (taxonomy) this post is assigned to. The pagination for this section is different from the home page; this time it links only to the previous and next posts (based on date).

It’s important to pull in the author information, especially if your site has many contributors. While authors are not always users and users are not necessarily authors, we’ll power the Authors section with data from the user profiles. If you have a contributing author, it makes sense to create a user account for her. She won’t need login credentials and you can always lower her role as well.

The Comments section has many parts, but WordPress has a prebuilt comments template that we’ll be using. This makes it easy to generate all the HTML for this section, including the form. You’ll have the option to edit the template or create your own if you so choose.

The Loop

The Loop will remain identical to the one on the home page. The only difference is what goes inside it. Also, since we’re not running iterations of posts, we don’t have to worry about the actual duplicating of HTML structure. In this case, there will be only one post per loop.

Having a while here doesn’t hurt, but it’s not necessary because there’s only one post:

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
  <!-- PLACE EVERYTHING FROM FEATURED IMAGE TO COMMMENTS -->
<?php endwhile; else: ?>
  <p><?php _e( 'The post you're looking for could not be found.' ); ?></p>
<?php endif; ?>

All the code that follows in this chapter will be placed in the loop above.

Article Header

The article header tag contains the featured image, title tag, and post metadata (Figure 10.2). Everything that follows will be placed in the <header> tag in the <article> tag.

Image

Figure 10.2. Article header.

Featured Image

Displaying a specific featured image based on its size requires some code that we haven’t written yet. We’ll look at how to do this in a later chapter, and at that time we’ll come back and replace this. For now, just so we know the theme is working, replace the featured <img> tag at the top of the template with:

<?php the_post_thumbnail(); ?>

This is exactly how we did it in The Loop on the home page.

Title

The title of the post is displayed with the the_title() template tag. It doesn’t need an <a> tag around it because, unlike on the home page, we’re not linking the title to the post. Inside the <h1> tags, replace the content with:

<?php the_title(); ?>

This outputs the following HTML:

<h1>Hello World</h1>

Post Metadata

For the post date and number of comments, grab the code straight from the index.php template. Nothing is changing here except that we’re linking to the comments below. I added an <a> tag around the comments number anchoring to the #comments div below:

<p>Posted <time datetime="<?php the_time('Y-m-d'), ?>" pubdate="pubdate">
        <?php the_time('M n'), ?></time> &#149; <a href="#comments"><?php
        comments_number( '0 comments', 'only 1 comment', '% comments' ); ?>
        </a></p>

The Template Tags the_time() and comments_number() are discussed in great detail in Chapter 8, “Home Page.”

Content

On the home page we didn’t actually pull in any content from the content editor (Figure 10.3). Each post had a title, date, comment count, and featured image. In later chapters we’ll take a closer look at conditionals like if statements and alternatives to the featured image on the home page. For example, if there’s no featured image on a post, you can either remove it from the list on the home page or pull in the excerpt.

Image

Figure 10.3. The content.

The excerpt is a shortened version of the content. You can either have the the_excerpt() Template Tag pull content that you define in the excerpt editor on the post, or pull the first bit of content in the content editor with images and special formatting stripped.

Since we’re on the Post page it only makes sense to show the full content. Some themes use the excerpt in the single.php template page to show what’s coming up in the next post:

<?php the_content(); ?>

This Template Tag or WordPress call displays all the content in the content editor. This includes, but is not limited to, text, HTML, images, graphics, videos, and even shortcodes (which we’ll discuss in later chapters).

Unless you’ve specifically stated otherwise, any content that’s not wrapped in HTML already will be wrapped in <p> tags. You can turn this off by disabling the wpautop filter in the functions.php file. However, most of the time the auto-wrapping comes in handy and is the default functionality in most themes.

Since we don’t have to worry about the HTML markup for each element in the content editor, all we do is place the the_content() function in the content div like so:

<div class="content">
  <?php the_content(); ?>
</div><!-- content -->

You can read more about the_content at http://wdgwp.com/the_content and about the_excerpt at http://wdgwp.com/the_excerpt.

Article Footer

The footer has several components, including the taxonomy, author information, and pagination (Figure 10.4).

Image

Figure 10.4. The article footer.

Taxonomy

It’s important to give users a way to continue reading through your site. Increasing time on site leads to better conversion, commenting, and sharing—and more return visits.

A nicely displayed list of categories and tags may prompt a visitor to click through to another page. Displaying the categories and tags is, not surprisingly, easy to do:

<div class="tax">
  <div class="alignleft">
    <p>Filed under: <!-- category list --></p>
  </div>
  <div class="alignright txtrt">
    <p><!-- tags list --></p>
  </div>
</div><!-- tax -->

The taxonomy <div> is structured pretty simply. All we have to do is call replace the commented-out code with the categories and tags calls. Replace <!-- category list --> with:

<?php the_category( ', ' ); ?>

The the_category() function accepts a few parameters. Here we’re going to pass only one, the separator. Since the the_category() function returns a list of category titles wrapped in <a> tags linking to the respective archive pages, we need to define what we want between each item on the list. In our case, we’ll have a comma-separated list so we’ll pass “, “. Notice the space after the comma: Without this there will be no space between each category. For more info on the_category(), go to http://wdgwp.com/the_category.

Next replace <!-- tags list --> with the_tags() function. This function accepts similar parameters to its cousin the_category(), but since the defaults are perfect for our use we don’t have to override them by passing any parameters. The one thing we want to avoid is having the <div> containing the tags ever be empty:

<?php if( get_the_tags() ) { ?>
    <div class="alignright txtrt">
      <p><?php the_tags(); ?></p>
    </div>
<?php } ?>

In this case we’ll wrap the div in an if statement. We’ll look at conditionals and if statements in greater detail later, but for now just know that we’re asking if the get_the_tags() function is returning a value. Many WordPress functions that start with get_ return a value you can use to test against or put into a variable. Here, removing the get_ calls a different but similar function that automatically outputs its values as HTML. You can read more about this at http://wdgwp.com/the_tags.

When all is said and done, the taxonomy div should be coded like this:

<div class="tax">
  <div class="alignleft">
    <p>Filed under: <?php the_category( ', ' ); ?></p>
  </div>
  <?php if( get_the_tags() ) { ?>
    <div class="alignright txtrt">
      <p><?php the_tags(); ?></p>
    </div>
  <?php } ?>
</div><!-- tax -->

You may be wondering why we didn’t put an if statement around the category call. Unlike a tag, a post must be assigned to at least one category. If you don’t choose a category, then the post will be auto-assigned to the default category. Tags are optional and we don’t want empty divs in our finished website, so we’ll make sure that the post has tags before we output the HTML.

Author

The author div has the author’s name at the top, linking to the respective archive page (a list of all the author’s posts), her Gravatar, description, and URL:

<div class="author">
  <h3>Written by: <!-- author name and archives link --></h3>
  <!-- Gravatar -->
  <p><!-- description --></p>
  <a href="<!-- author url -->" title="<!-- author's first name -->'s
        Website" target="_blank"><!-- author url --></a>
</div><!-- author -->

I’ve laid out the author div HTML structure above. We have a few different elements to display. The author name and archives link can actually be called with a single function. Replace <!-- author name and archives link --> with:

<?php the_author_posts_link(); ?>

Since every post needs an author and all authors have archive links, there’s no need to test for the existence of this content as we did with tags. This function automatically generates an <a> tag with a link to the archive and displays the author’s “display name.” See http://wdgwp.com/author_link.

The author’s avatar will actually be a Gravatar. Gravatar is short for “globally recognized avatar.” You can get a Gravatar by signing up at http://wdgwp.com/Gravatar. Once you have a Gravatar, anyone who has your e-mail address can request it to be displayed. In this case, the e-mail address associated with the user profile dictates whether or not she gets an image displayed next to her name. WordPress has a rather nice function used to retrieve the Gravatar of the user. Replace <!-- Gravatar --> with:

<?php echo get_avatar( get_the_author_meta( 'email' ), '50', 'Mystery Man',
        'Avatar of ' . get_the_author_meta( 'first_name' ) . '
        ' . get_the_author_meta( 'last_name' ) ); ?>

This single line of code performs several functions at once. First, it echoes the result of the get_avatar() function, which will return an <img> tag complete with a URL to the avatar. If the author doesn’t have a Gravatar set up, the image will default to the “Mystery Man” or other default setting.

The parameters are set by functions and specific values alike, as outlined below:

1. The ID or e-mail used to retrieve the avatar: get_the_author_meta( ‘email’ )

2. Size of the avatar: 50

3. Default avatar to use if Gravatar is missing: Mystery Man

4. Alt text for the <img> tag: ‘Avatar of ‘ . get_the_author_meta( ‘first_name’ ) . ‘ ‘ . get_the_author_meta( ‘last_name’ ) (adding values to functions)

All these functions output the following HTML:

<img alt='Avatar of Jesse Friedman' src='http://0.gravatar.com/avatar/09
        34fa64cc323b6a2e10dc37fc33fa64?s=50&amamp;d=Mystery+Man&amp;r=G'
        class='avatar avatar-50 photo' height='50' width='50' />

I know that was a lot to take in, but in the end all we’re doing is making calls to output HTML. The rest of the Authors section will be far less complex, I promise.

The author’s description, usually referred to as a bio, is defined in the user profile. Only text will be accepted in this field, so we’ll wrap it in a <p> tag. Replace <!-- description --> with:

<?php if( get_the_author_meta( 'description' ) ) { ?>
<p><?php the_author_meta( 'description' ); ?></p>
<?php } ?>

Once again we have to test for the existence of the description. We don’t want to force the author to put in a bio; that’s bad form. We just don’t want to output empty <p> tags if there’s no bio.

The the_author_meta() function outputs any number of details about the author of the current post. You can pass it several parameters; in this case, we’re requesting the description. Above, we used the get_the_author_meta() function to return the e-mail and first and last names of the author. For more info on these functions go to http://wdgwp.com/the_author_meta and http://wdgwp.com/get_the_author_meta.

Next we want to display the author’s URL. If the author is a contributor, it’s nice to link to the author’s site as a thank you. If you operate the site and are the author, you can put your Twitter or Facebook URL in place. Since we didn’t put the word “Website” between the <a></a> tags, anything placed in the author’s website field on the user profile page will go nicely here.

Replace the following HTML:

<a href="<!-- author url -->" title="<!-- author's first name -->'s Website"
        target="_blank"><!-- author url --></a>

with:

<?php if( get_the_author_meta( 'user_url' ) ) { ?>
<a href="<?php the_author_meta( 'user_url' ); ?>" title="<?php
        the_author_meta( 'first_name' ); ?>'s Website" target="_blank">
        <?php the_author_meta( 'user_url' ); ?></a>
<?php } ?>

At this point the code above should make sense to you. If not, please reread the last few pages. It’s important for you to be able to interpret code as it’s written. Anything that doesn’t make sense can be referenced in earlier examples of code or in the WordPress Codex.

The entire author div should now look like this:

<div class="author">
  <h3>Written by: <?php the_author_posts_link(); ?></h3>
  <?php echo get_avatar( get_the_author_meta( 'email' ), '50', 'Mystery Man',
        'Avatar of ' . get_the_author_meta( 'first_name' ) . '
        ' . get_the_author_meta( 'last_name' ) ); ?>
  <?php if( get_the_author_meta( 'description' ) ) { ?>
    <p><?php the_author_meta( 'description' ); ?> </p>
  <?php } ?>
  <?php if( get_the_author_meta( 'user_url' ) ) { ?>
    <a href="<?php the_author_meta( 'user_url' ); ?>" title="<?php
        the_author_meta('first_name' ); ?>'s Website" target="_blank">
        <?php the_author_meta( 'user_url' ); ?></a>
  <?php } ?>
</div><!-- author -->

The HTML below is an example of what will be output, assuming I’m the author of the post:

<div class="author">
  <h3>Written by: <a href="http://localhost/j2-theme/author/jfriedman/"
        title="Posts by Jesse Friedman" rel="author">Jesse Friedman</a></h3>
  <img alt='Avatar of Jesse Friedman' src='http://0.gravatar.com/avatar/
        0934fa64cc323b6a2e10dc37fc33fa64?s=50&amp;d=Mystery+Man&amp;r=G'
        class='avatar avatar-50 photo' height='50' width='50' />
 <p>I'm a professor, author, speaker and developer. I love WordPress,
        especially teaching it. </p>
  <a href="http://jesserfriedman.com" title="Jesse's Website"
        target="_blank">http://jesserfriedman.com</a>
</div><!-- author -->

Pagination

To help make it easy to continue browsing our site, we want to provide simple buttons leading to the previous and next posts. Unlike the pagination on the home page, where we link to archive pages, here we’ll be linking to specific posts. The Previous and Next buttons are easy to generate with WordPress functions.

Directly below the closing author </div> is the <nav> tag. In there is an unordered list. We’ll replace the content in the <li> tags with the following functions:

previous_post_link();
next_post_link();

These functions output an <a> tag with a link to the corresponding post and, by default, its title. For this theme we’ll replace the title of the post and have “< Previous Post” and “Next Post >” as the text on the buttons. To do this, we need to pass two parameters to the functions:

<ul>
  <?php previous_post_link( '<li>%link</li>', '&lt; Previous Post' ); ?>
  <?php next_post_link( '<li>%link</li>', 'Next Post &gt;' ); ?>
</ul>

The first parameter dictates the treatment of the link. We’re wrapping the %link with <li></li> tags because if there is no previous or next link, we don’t want empty HTML tags. You won’t have a previous or next link if you’re viewing the first or last posts in the blog, since there’s nothing to continue to. The second parameter is what actually goes in between the <a></a> tags. I’ve escaped the “<” and “>,” which is why you see “&lt;” and “&gt;”. For more information on these Template Tags go to http://wdgwp.com/previous_post_link and http://wdgwp.com/next_post_link.

The previous code outputs the following HTML:

<ul>
  <li><a href="http://localhost/j2-theme/hello-world/" rel="prev">&lt;
        Previous Post</a></li>

  <li><a href="http://localhost/j2-theme/hello-world-again-and-again/"
        rel="next">Next Post &gt;</a></li>
</ul>

Comments

The Comments section is a pretty heavy area (Figure 10.5). Coding every aspect of it can be difficult and time-consuming. A specific comment has the author’s avatar, name, website URL, comment, and reply link. Threaded comments require special thought, and there’s the Comments form itself to build. You have to perform special actions for logged-in versus other users, compare that against approved and unapproved comments, and more.

Image

Figure 10.5. Comments.

Luckily for us WordPress has a built-in comments template that generates all of this for us. The comments template is built into the WordPress core. If you want to create your own template you can pass the location of that template as a parameter in the comments_template() function, which we’re about to use. Either way, you need a comments.php file in your theme (as of WordPress 3.0). You can locate the default comments.php file wp-includes → theme-compat. If it isn’t there already, copy the comments.php into your theme folder:

<?php comments_template(); ?>

Drop the above function into the Comments section of the post template. We’re not going to pass any parameters to this function, but if you like you can pull your own comments template like this:

<?php comments_template( '/my-comments-template.php' ); ?>

The my-comments-template.php file would be placed in the theme directory with the rest of your files. For more information on the comments_template() function and creating your own comments template go to http://wdgwp.com/comments_template.


Note

In this theme only posts can be commented on. The comments capability and template can be implemented into a page template if you so choose. In addition, any of the Template Tags we’ve used for the post can be placed on a page template (with the exception of categories and tags, as we can’t assign pages to those taxonomies). You can create your own comments template to define exactly how the layout and functions work in your theme.


Calling the comments_template() displays all of the approved comments on the current post and includes the Comments form at the bottom, which has the following fields:

• Name

• Mail

• Website

• Comment

WordPress validates the form for you and submits the data. Once the comment is submitted, depending on the site settings, it may display immediately. Based on the default comments template, every comment can be “replied” to, creating a thread of comments. The depth of that thread will be defined by the comments settings in the admin.

The comments template outputs the following HTML on an example post with three comments, one of which is a reply. I’ve removed some irrelevant content to save space:

<h3 id="comments">3 Responses to &#8220;Hello world!&#8221;</h3>

<ol class="commentlist">
  <li class="comment even thread-even depth-1 parent" id="comment-1">
    <div id="div-comment-1" class="comment-body">
      <div class="comment-author vcard">
        <img alt='' src='http://0.gravatar.com/avatar/ad516503a11cd5ca435
        acc9bb6523536?s=32' class='avatar avatar-32 photo avatar-default'
        height='32' width='32' />
        <cite class="fn"><a href='http://wordpress.org/' rel='external
        nofollow' class='url'>Mr WordPress</a></cite>
        <span class="says">says:</span>
      </div>
      <div class="comment-meta commentmetadata">
        <a href="http://localhost/j2-theme/hello-world/#comment-1">May 4,
        2012 at 6:27 pm</a>
      </div>
      <p>Hi, this is a comment.<br />To delete a comment, just log in and
        view the post&#039;s comments. There you will have the option to edit
        or delete them.</p>
      <div class="reply">
        <a class='comment-reply-link' href='/j2-theme/hello-
        world/?replytocom=1#respond' onclick='return addComment.
        moveForm("div-comment-1", "1", "respond", "1")'>Reply</a>
      </div>
    </div>
    <ul class='children'>
      <li class="comment odd alt depth-2" id="comment-7">
        <div id="div-comment-7" class="comment-body">
          <div class="comment-author vcard">
            <img alt='' src='http://1.gravatar.com/avatar/bb9b1e9ed6ac9b3d73e
        35aa2a1eca8b7?s=32&amp;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516
        503a11cd5ca435acc9bb6523536%3Fs%3D32&amp;r=G' class='avatar avatar-32
        photo' height='32' width='32' />
            <cite class="fn"><a href='http://jesserfriedman.com' rel='external
        nofollow' class='url'>Jesse Friedman</a></cite>
            <span class="says">says:</span>
          </div>
          <div class="comment-meta commentmetadata">
            <a href="http://localhost/j2-theme/hello-world/#comment-7">May
        20, 2012 at 3:36 am</a>
          </div>
          <p>That&#8217;s a great point. Thanks for sharing.</p>
          <div class="reply">
            <a class='comment-reply-link' href='/j2-theme/hello-
        world/?replytocom=7#respond' onclick='return addComment.
        moveForm("div-comment-7", "7", "respond", "1")'>Reply</a>
          </div>
        </div>
      </li>
    </ul>
  </li>
  <li class="comment even thread-odd thread-alt depth-1" id="comment-8">
    <div id="div-comment-8" class="comment-body">
      <div class="comment-author vcard">
        <img alt='' src='http://0.gravatar.com/avatar/6a6c19fea4a3676970167c
        e51f39e6ee?s=32&amp;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad51650
        3a11cd5ca435acc9bb6523536%3Fs%3D32&amp;r=G' class='avatar avatar-32
        photo' height='32' width='32' />

        <cite class="fn"><a href='http://doe.com' rel='external nofollow'
        class='url'>John Doe</a></cite>
        <span class="says">says:</span>
      </div>
      <div class="comment-meta commentmetadata">
        <a href="http://localhost/j2-theme/hello-world/#comment-8">May 20,
        2012 at 3:37 am</a>
      </div>
      <p>I really agree with this post, it&#8217;s something I do everyday.</p>
      <div class="reply">
        <a class='comment-reply-link' href='/j2-theme/hello-world/
        ?replytocom=8#respond' onclick='return addComment.moveForm("div-
        comment-8", "8", "respond", "1")'>Reply</a>
      </div>
    </div>
  </li>
</ol>
<div id="respond">
  <h3>Leave a Reply</h3>
  <div id="cancel-comment-reply">
    <form action="http://localhost/j2-theme/wp-comments-post.php"
        method="post" id="commentform">
      <p><input type="text" name="author" id="author" value="John
        Doe" size="22" tabindex="1" aria-required='true' /><label
        for="author"><small>Name (required)</small></label></p>
      <p><input type="text" name="email" id="email" value="[email protected]"
        size="22" tabindex="2" aria-required='true' /><label for="email">
        <small>
Mail (will not be published) (required)</small></label></p>

      <p><input type="text" name="url" id="url" value="http://doe.com" size="22"
        tabindex="3" /><label for="url"><small>Website</small></label></p>

      <p><textarea name="comment" id="comment" cols="58" rows="10"
        tabindex="4"></ textarea></p>

      <p><input name="submit" type="submit" id="submit" tabindex="5"
        value="Submit Comment" /><input type='hidden' name='comment_post_ID'
        value='1' id='comment_post_ID' /><input type='hidden'
        name='comment_parent' id='comment_parent' value='0' /></p>

    </form>
  </div>
</div>

I know that was a lot of HTML to look through, but as you can see, many elements go into making the Comments section. Note that the comments are basically an ordered list and that threaded comments are list items inside list items. It’s very similar to a basic drop-down nav structure.

It may seem intimidating to create your own comments template, especially if you only need to make a small change. If, for example, your theme doesn’t have the commenter’s avatar displayed, it would make sense to customize the comments template and remove those avatars. However, this may be a bit advanced for you at the moment and, if that’s the case, you can use CSS to hide or alter elements. This isn’t exactly a best practice because we’re loading the avatars and hiding them, but it’s one solution to get you where you need to be.

What’s Next

Adding the Comments section to the post template was the last piece of the puzzle. In the next chapter, we’ll build the page template and talk about custom page templates that let the user admin decide how her page content will be displayed.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.255.187