WordPress tutorial: Single Post Template

In this tutorial you will learn how to create a single post template in WordPress. We will create an “Ultimate Guide” – where your post will be separated in sections and will have a Table of contents.

This is how the end result will look:

To follow through this tutorial it will be nice to have some knowledge of HTML, CSS and Javascript, but even if you don’t have such you will still be able to make it, as I will explain every step in detail.

Our starting point will be single.php file. Copy this file from your theme folder and rename it, adding the post type (post) and the slug of the post you want to create. The slug of our post will be ultimate guide, so the name of the file in this case will get – single-post-ultimate-guide.php. Now WordPress knows that this file is going to be the single post template of the post with slug ultimate-guide.

You can read more about Template Hierarchy in WordPress Theme Handbook. Custom template for single post in WordPress (single-{post-type}-{slug}.php) is possible after version 4.4, so if your version is earlier than this you will have to update it first.

Let’s have a look at the basic php structure of a single.php file:

<?php 
get_header(); 
the_title();
the_post_thumbnail();
the_content();
if ( comments_open() || get_comments_number() ) {
comments_template();
}
get_sidebar();  
get_footer(); 
?>

What you have here first is the header part of your website. It includes the beginning of the HTML document and navigation menus.

Then you have the post title – the_title(); and the_post_thumbnail(); – this is the Featured image, that you add to the post.

After that in the template comes the post content, that you enter in the visual editor.

And as last if the comments for this post are open it will show them using the standard WordPress comment template – via comments_template();

After the title, content and the featured image comes the sidebar of the theme, followed by the footer.

In your theme footer, except the footer that you see at the bottom of the page are also located the JavaScript files, that your theme uses and the ending tags of your HTML pages.

If you are going to create regularly such posts, you might considerate creating Custom Post Type, where you can add custom metaboxes for the content parts, but here I am going to show you how to style this post only. In a simple way, using mainly HTML, CSS and JavaScript and changing the default structure of the single.php for this post.

So, for our Ultimate guide post we will need the post title, the post content and header and footer sections:

<?php 
/**
 * Template for displaying Single Ultimate Guide post
 *
 */
get_header(); 
?>
<div class="page-wrap">
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<h1><?php the_title();?></h1>
<p><?php the_content(); ?></p>
<?php endwhile; endif; ?> 
</div>
<a class="scroll-top" href="#table-of-contents">Scroll to Contents</a>

This is going to be the main php structure of our file (single-post-ultimate-guide.php). Now we have to build the HTML structure. This we will do in WordPress visual editor. First write the Table of contents and a title for each section. Here is an example how the page will look:

Table of Contents:
1. Create a single-post_slug.php template in your theme folder
2. Editing the single post template file
3. Add your post Contents in WordPress visual editor
4. Add HTML structure
5. Style the elements with CSS
6. Add extra functionality with Javascript
7. Publish your post

1. Create a single-post_slug.php template in your theme folder
Here comes the post content of the 1st section – Create a single-post_slug.php template in your theme folder

2. Editing the single post template file
The post content of the 2nd section – Editing the single post template file.

After you are ready with your content, we will wrap each section with HTML tags as follows:

<div class="table-of-contents" id="table-of-contents">
<h2>Table of Contents:</h2>
<ol>
<li><a href="#create">1. Create a single-post_slug.php template in your theme folder</a></li>
<li><a href="#edit">2. Editing the single post template file</a></li>
<li><a href="#add-contents">3. Add your post Contents in WordPress visual editor</a></li>
<li><a href="#html">4. Add HTML structure</a></li>
<li><a href="#css">5. Style the elements with CSS</a></li>
<li><a href="#js">6. Add extra functionality with Javascript</a></li>
<li><a href="#publish">7. Publish your post</a></li>
</ol>
</div>

<div class="ultimate-guide-wrap">
<section id="create">
<h2>Create a single-post_slug.php template in your theme folder</h2>
<p>Here comes the post content of the 1st section - Create a single-post_slug.php template in your theme folder</p>
</section>
<section id="edit">
<h2>Editing the single post template file</h2>
<p>The post content of the 2nd section - Editing the single post template file.</p>
</section>
<section id="add-contents">
<h2>Title</h2>
<p>... content ...</p>
</section>
<section id="html">
<h2>Title</h2>
<p>... content ...</p>
</section>
<section id="css">
<h2>Title</h2>
<p>... content ...</p>
</section>
<section id="js">
<h2>Title</h2>
<p>... content ...</p>
</section>
<section id="publish">
<h2>Title</h2>
<p>... content ...</p>
</section>
</div>

Switch to Text input in the WordPress editor and paste the tags around your text so you get this structure.
Here we have the Table of contents listed as links, so when you click on a link it will scroll to the section that has the same id.

Now we are going to change the appearance of the post with CSS. We are going to style the following classes and elements:

.page-wrap
.page-wrap h1
.table-of-contents 
.table-of-contents-fixed
.table-of-contents h2
.table-of-contents ol
.table-of-contents li 
.table-of-contents a 
.table-of-contents a.active
.ultimate-guide-wrap 
.ultimate-guide-wrap section 
.ultimate-guide-wrap h2 
.ultimate-guide-wrap p 
.page-wrap .scroll-top
/* media query @media (max-width: 768px) */
@media (max-width: 768px) {
.ultimate-guide-wrap
.table-of-contents
.page-wrap .scroll-top
}

We will embed the styles and JavaScript needed for this post in the post template itself. This way the styles will only be loaded if viewing this post. So, in the same file – before get_footer(); add the following styles, surrounded by <style></style> tags, like so:

<style>
.page-wrap {
    display:block;
    width:100%;
    padding: 0 15px;
	
}
.page-wrap h1{
    text-align: center;
    font-size: 46px;
    font-weight: bold;
    width: 75%;
    padding: 0 15px 45px 15px;
    float: left;
}
.table-of-contents { 
    display: block;
    width: 25%;
    float: right;
    overflow-y: auto;
    height: 87%;
}
.table-of-contents-fixed { 
    position: fixed;
    top: 32px;
    right: 0;
}
.table-of-contents h2 {
    font-size: 20px;
    background-color: #ececec; 
    padding: 8px;
    text-align: center;
}
.table-of-contents ol {  
    -webkit-padding-start: 0;
}
.table-of-contents li { 
    margin: 15px 0;
    padding: 3px 3px 3px 20px;
    list-style: none;
}
.table-of-contents a { 
    padding: 5px;
    font-size: 20px;
}
.table-of-contents a.active {
    font-weight: bold;
}
.ultimate-guide-wrap { 
    display:block;
    width:75%;
    padding: 0 55px;
}
.ultimate-guide-wrap section { 
    padding: 5px 15px;
    font-size: 20px;
    line-height: 1.55;
    clear: left;
}
.ultimate-guide-wrap h2 { 
    border-bottom: 1px solid #000;
    padding: 5px 25px 10px 25px;
}
.ultimate-guide-wrap p { 
    padding: 15px;
    font-size: 20px;
    line-height: 1.55;
}
.page-wrap .scroll-top {
    display: none;
}
@media (max-width: 768px) {
.page-wrap h1 {
    width: 100%;
}
.ultimate-guide-wrap {
    display: inline-block;
    width: 100%;
    padding: 0 5%;
    line-height: 1.6;
}
.table-of-contents {
    width: 100%;
    height: 100%;
    position: relative;
    margin-bottom: 50px;
}
.page-wrap .scroll-top {
    display: block;
    position: fixed;
    bottom: 0;
    width: 100%;
    text-align: center;
    background: #FF9800;
    color: #fff;
    padding: 15px 0;
}
}
</style>

In the CSS styles we have specified how the post will look on mobile and tablet portrait view – screens up to 768 px width. If the screen is maximum 768 px – the width of the Table of Contents changes to 100% and its position to relative. The ultimate-guide-wrap width also changes to 100% and at the bottom of the page will appear button, that on click scrolls the post back to the Table of Contents. See the mobile preview in the video below:

The next step is adding the JavaScript for our animations and effects. You will need jQuery enqueued in WordPress for this to work. In general most of the themes include it by default, so you should be ok. If jQuery is not included in your theme, you can add it to your theme’s functions.php file using wp_enqueue_script( ‘jquery’); via wp_enqueue_scripts.

<script>
jQuery(document).ready(function() {
   var win      = jQuery(window),
    fixedElem     = jQuery('.table-of-contents'),
    eloffset = fixedElem.offset().top;
win.scroll(function() {
    if (eloffset < win.scrollTop()) {
        fixedElem.addClass("table-of-contents-fixed");
    } else {
        fixedElem.removeClass("table-of-contents-fixed");
    }
}); 

//Table of Contents navigation	 
var sections = jQuery('.page-wrap section'),
    contents = jQuery('.table-of-contents, section'),  
    top_height = jQuery('.page-wrap h1').offset().top; 

jQuery(window).on('scroll', function () {
  var cur_pos = jQuery(this).scrollTop();
  
  sections.each(function() {
    var top = jQuery(this).offset().top - top_height,
        bottom = top + jQuery(this).outerHeight();
		//if max-width: 768px
    if (window.matchMedia('(max-width: 768px)').matches){
		contents.find('a').on('click', function () {
		contents.find('a').removeClass('active'); 
			if(!jQuery(this).hasClass('active')){
		jQuery(this).addClass('active');  
			} 
		});
		//else
	} else {
    if (cur_pos >= top && cur_pos <= bottom) {
      contents.find('a').removeClass('active'); 
      contents.find('a[href="#'+jQuery(this).attr('id')+'"]').addClass('active');
    }
	}
  });
});

contents.find('a').on('click', function () {
  var el = jQuery(this),
      id = el.attr('href');
  
  jQuery('html,body').animate({
    scrollTop: jQuery(id).offset().top
  }, 500);
  
  return false;
});
//scroll to contents
jQuery('.scroll-top').on('click', function () {
  
  jQuery('html,body').animate({
    scrollTop: jQuery('#table-of-contents').offset().top
  }, 500);
  
  return false;
});
});
</script>

Here first we make that the Table of Contents (div .table-of-contents) gets fixed if we have reach it, scrolling down. This is accomplished by adding to it the class table-of-contents-fixed, which is positioned in the CSS as fixed.

Then we add the effect, that makes the name of the section in which we are scrolling bold in the Table of Contents and animates the scroll, when you click on a link in the Table of contents, or if you have an internal link in the content, that leads to another section of the post.

Download the file from this tutorial here

If you have any questions, feel free to ask them in the comments.