Developing a WordPress Theme from Scratch Part 2: Pagination, Comments, Single Post, Functions, & Custom Posts

Developing a WordPress Theme from Scratch Part 2: Pagination, Comments, Single Post, Functions, & Custom Posts

In part one of the tutorial series Developing a WordPress Theme From Scratch, we learned what WordPress is, what it can do, and how to do the following:

  • Set up a local Apache, MySQL, PHP (*AMP) environment
  • Install WordPress on your local server
  • Take an existing static HTML & CSS site and make it into a custom WordPress theme
  • Divide your theme into sections (index.php, header.php, footer.php, sidebar.php, and content.php)
  • Use The Loop to make posts and pages
  • Migrate local WordPress site to a live server

We created this theme using Bootstrap, and more specifically the official generic blog template. While the theme could use custom CSS or any framework, I went with Bootstrap so that we can focus on creating the theme’s function without worrying about the style.

Here is what the theme looked like at the end of the last article:

Very simple, but it effectively demonstrates how to use the WordPress Loop to display content dynamically.

In this article, we’re going to go through more essential WordPress theming techniques.


  • Basic knowledge of HTML and CSS
  • Ability set up WordPress and make a basic theme (covered in part one)


  • Create individual post pages – single.php
  • Add pagination
  • Include comments
  • Learn how to use functions.php
  • Properly enqueue stylesheets and scripts
  • Create global custom fields
  • Create custom post types

First, I’m going to start off by adding individual blog posts and pagination.

Individual Post Pages

In the last article, we made header, footer, sidebar, content, and page files. Now we’re going to make single.php, which is an individual post page. It’s going to be an exact duplicate of page.php, except I’m going to change 'content' to 'content-single'.

<?php get_header(); ?>

	<div class="row">
		<div class="col-sm-12">

				if ( have_posts() ) : while ( have_posts() ) : the_post();
					get_template_part( 'content-single', get_post_format() );
				endwhile; endif; 

		</div> <!-- /.col -->
	</div> <!-- /.row -->

<?php get_footer(); ?>

Now you’ll create content-single.php, which is a duplicate of content.php.

<div class="blog-post">
	<h2 class="blog-post-title"><?php the_title(); ?></h2>
	<p class="blog-post-meta"><?php the_date(); ?> by <a href="#"><?php the_author(); ?></a></p>
 <?php the_content(); ?>
</div><!-- /.blog-post -->

So now you can see that index.php is pulling in content.php, and single.php is pulling in content-single.php.

Going back to the original content.php, we have the title of each article.

<h2 class="blog-post-title"><?php the_title(); ?</h2>

Using the_permalink(), we’re going to link to the single page.

<h2 class="blog-post-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>

Now you have a blog posts on the main page that are linking individual blog post page.

Finally, we’ll want to change the_content() to the_excerpt() on content.php. The excerpt will only show the first 55 words of your post, instead of the entire contents.

<?php the_excerpt(); ?>


In the original Bootstrap blog example, there is pagination to be able to click through multiple pages if you have many blog posts.

Currently, your index.php file looks like this.

<?php get_header(); ?>

	<div class="row">
		<div class="col-sm-8 blog-main">

			if ( have_posts() ) : while ( have_posts() ) : the_post();
				get_template_part( 'content', get_post_format() );
			endwhile; endif; ?>

		</div>	<!-- /.blog-main -->
		<?php get_sidebar(); ?>
	</div> 	<!-- /.row -->

<?php get_footer(); ?>

If you’ll notice, the loop has if and while, then later endif and endwhile. To insert pagination, we’ll have to put it after the endwhile but before the endif. This means that it won’t repeat for each loop, but will only show up once based on posts.

Pagination links are called like this:

<?php next_posts_link( 'Older posts' ); ?>
<?php previous_posts_link( 'Newer posts' ); ?>

In index.php, between endwhile; and endif;, I’m going to place this code.

	<ul class="pager">
		<li><?php next_posts_link( 'Previous' ); ?></li>
		<li><?php previous_posts_link( 'Next' ); ?></li>

By default, 10 posts will show up on a page before it will link to another page. For testing purposes, I’m going to go to Settings > Reading and change Blog pages show at most to 1.

Now we have functioning pagination.


One of the biggest advantages WordPress and server based content management systems have over static site generators is the ability to include comments without using a third party. (However, static site generators have many more advantages – I have an article on setting up Jekyll if you’re interested in learning how to use them.)

Comments seem complicated to set up, but it doesn’t have to be hard at all. First, we’re going to go back to single.php and enable the comments.

Right now, the code looks like this.

if ( have_posts() ) : while ( have_posts() ) : the_post();
	get_template_part( 'content-single', get_post_format() );
endwhile; endif; 

We’re going to change it to look like this.

if ( have_posts() ) : while ( have_posts() ) : the_post();
	get_template_part( 'content-single', get_post_format() );

	if ( comments_open() || get_comments_number() ) :

endwhile; endif; 

This is just telling the single post to display the comments template. Now we’ll create comments.php.

<?php if ( post_password_required() ) {
} ?>
	<div id="comments" class="comments-area">
		<?php if ( have_comments() ) : ?>
			<h3 class="comments-title">
				printf( _nx( 'One comment on “%2$s”', '%1$s comments on “%2$s”', get_comments_number(), 'comments title'),
					number_format_i18n( get_comments_number() ), get_the_title() );
			<ul class="comment-list">
				wp_list_comments( array(
					'short_ping'  => true,
					'avatar_size' => 50,
				) );
		<?php endif; ?>
		<?php if ( ! comments_open() && get_comments_number() && post_type_supports( get_post_type(), 'comments' ) ) : ?>
			<p class="no-comments">
				<?php _e( 'Comments are closed.' ); ?>
		<?php endif; ?>
		<?php comment_form(); ?>

Comments are not the simplest part of WordPress theming, but I’ve managed to reduce it down to a small enough code block.

First, we’re setting functionality to prevent users from posting comments if you’ve set your settings to password protected comments (post_password_required()). Then we’re creating a comments div, and if there are comments (have_comments()), it will display how many comments there are on the post (get_comments_number()), followed by the list of comments (wp_list_comments()). If the comments are closed (! comments_open()), it will let you know; at the end will be the form to submit a comment (comment_form()).

Without adding any styles, here is how the functioning single blog post looks.

Obviously the styles aren’t quite there yet, but I don’t want to focus on that in this article. Remove the list-style on the uls, add some padding and margins and possibly some borders and background colors, and you’ll have a much prettier comment setup.

Of course, you might want to show how many comments there are or link to the comments from the main page. You can do that with this code inserted into content.php.

<a href="<?php comments_link(); ?>">
	printf( _nx( 'One Comment', '%1$s Comments', get_comments_number(), 'comments title', 'textdomain' ), number_format_i18n( 						get_comments_number() ) ); ?>

Now that we have pagination, blog posts, and comments set up, we can move on to functions.

Using and Understanding the WordPress Functions File

Located in your theme directory, you can create a file called functions.php. You can use functions.php to add functionality and change defaults throughout WordPress. Plugins and custom functions are basically the same – any code you create can be made into a plugin, and vice versa. The only difference is that anything you place in your theme’s functions is only applied while that theme is actively selected.

I have a README on GitHub of useful WordPress functions, which might come in handy the more you use them.

functions.php seems complicated, but it’s mostly made up of a bunch of code blocks that, simplified, look like this:

function custom_function() {
add_action( 'action', 'custom_function');

So, we’re creating our custom function, and adding it in based on action references. Within this file, you can pretty much change or override anything in WordPress.

Let’s go ahead and make functions.php and place it in our theme directory.

Since it’s a PHP file, it needs to be begin with the opening PHP tag. It doesn’t need a closing tag; pure PHP files don’t need closing tags.


Eventually, you can insert these types of functions into your own custom plugin that can be used across many themes, but for now we’ll learn how to do it in the theme specific file.

Enqueue Scripts and Stylesheets

By the end of the last article, I was incorrectly linking to my CSS and JavaScript in the header and footer, respectively. This should be done through the functions file.

I’m going to make css, js and images directories in the root of my theme. So here’s what I have:

  • css
    • bootstrap.min.css
    • blog.css
  • js
    • bootstrap.min.js

Now here’s the first code block we’re going to put in functions.php:

// Add scripts and stylesheets
function startwordpress_scripts() {
	wp_enqueue_style( 'bootstrap', get_template_directory_uri() . '/css/bootstrap.min.css', array(), '3.3.6' );
	wp_enqueue_style( 'blog', get_template_directory_uri() . '/css/blog.css' );
	wp_enqueue_script( 'bootstrap', get_template_directory_uri() . '/js/bootstrap.min.js', array('jquery'), '3.3.6', true );

add_action( 'wp_enqueue_scripts', 'startwordpress_scripts' );

In order for these to properly be inserted into your theme, <?php wp_head(); ?> needs to be placed before the closing </head> tag, and <?php wp_footer(); ?> before the closing </body> tag.

By common WordPress convention, I’m naming my script after my theme (startwordpress_scripts()). wp_enqueue_style is for inserting CSS, and wp_enqueue_script for JS. After that, the array contains the ID, location of the file, an additional array with required depenedencies (such as jQuery), and the version number.

Now we have jQuery, Bootstrap CSS, Bootstrap JS, and custom CSS being properly loaded into the website.

Enqueue Google Fonts

The function to include the Google Fonts stylesheets is slightly different, based on the dynamic nature of the URL. Here is an example using Open Sans.

// Add Google Fonts
function startwordpress_google_fonts() {
				wp_register_style('OpenSans', ',600,700,800');
				wp_enqueue_style( 'OpenSans');

add_action('wp_print_styles', 'startwordpress_google_fonts');

Now I have Open Sans by Google Fonts linked in my page.

Fix the WordPress Title

If you’ll notice, we’re currently pulling in the title for the website with this code.

<title><?php echo get_bloginfo( 'name' ); ?></title>

This is not very intuitive – it means that whatever you have set as your website’s title will be the title tag for every page. However, we’re going to want each individual page to show the title of the article first, and also include a reference to the main site title.

Introduced in WordPress 4.1 is the ability to simply have WordPress take care of the title tag in an intuitive way. Simply remove the title tag from your header.php entirely, and in functions.php, add this code block.

// WordPress Titles
add_theme_support( 'title-tag' );

Create Global Custom Fields

Sometimes, you might have custom settings that you want to be able to set globally. An easy example on this page is the social media links on the sidebar.

Right now these links aren’t leading anywhere, but we want to be able to edit it through the admin panel. The source of this code is modified from this Settings API tutorial.

First, we’re going to add a section on the left hand menu called Custom Settings.

// Custom settings
function custom_settings_add_menu() {
  add_menu_page( 'Custom Settings', 'Custom Settings', 'manage_options', 'custom-settings', 'custom_settings_page', null, 99);
add_action( 'admin_menu', 'custom_settings_add_menu' );

Then we’re going to create a basic page.

// Create Custom Global Settings
function custom_settings_page() { ?>
  <div class="wrap">
    <h1>Custom Settings</h1>
    <form method="post" action="options.php">
<?php }

The code contains a form posting to options.php, a section and theme-options, and a submit button.

Now we’re going to create an input field for Twitter.

// Twitter
function setting_twitter() { ?>
  <input type="text" name="twitter" id="twitter" value="<?php echo get_option('twitter'); ?>" />
<?php }

Finally, we’re going to set up the page to show, accept and save the option fields.

function custom_settings_page_setup() {
  add_settings_section('section', 'All Settings', null, 'theme-options');
  add_settings_field('twitter', 'Twitter URL', 'setting_twitter', 'theme-options', 'section');

  register_setting('section', 'twitter');
add_action( 'admin_init', 'custom_settings_page_setup' );

Now I’ve saved my Twitter URL in the field.

For good measure, I’m going to add another example, this time for GitHub.

function setting_github() { ?>
  <input type="text" name="github" id="github" value="<?php echo get_option('github'); ?>" />
<?php }

Now you’ll just duplicate the fields in custom_settings_page_setup.

  add_settings_field('twitter', 'Twitter URL', 'setting_twitter', 'theme-options', 'section');
  add_settings_field('github', 'GitHub URL', 'setting_github', 'theme-options', 'section');
	register_setting('section', 'twitter');
  register_setting('section', 'github');

Now back in sidebar.php, I’m going to change the links from this:

<li><a href="#">GitHub</a></li>
<li><a href="#">Twitter</a></li>

To this:

<li><a href="<?php echo get_option('github'); ?>">GitHub</a></li>
<li><a href="<?php echo get_option('twitter'); ?>">Twitter</a></li>

And now the URLs are being dynamically generated from the custom settings panel!

Featured Image

You might want to have a featured image for each blog post. This functionality is not built into the WordPress core, but is extremely easy to implement. Place this code in your functions.php.

// Support Featured Images
add_theme_support( 'post-thumbnails' );

Now you’ll see an area where you can upload an image on each blog post.

I’m just going to upload something I drew in there for an example. Now, display the image in content-single.php.

<?php if ( has_post_thumbnail() ) {
} ?>

Now you have an image on your individual post pages! If you wanted the thumbnail to show up on on the main blog page as well, you could do something like this on content.php to split the page if a thumbnail is present:

<?php if ( has_post_thumbnail() ) {?>
	<div class="row">
		<div class="col-md-4">
			<?php	the_post_thumbnail('thumbnail'); ?>
		<div class="col-md-6">
			<?php the_excerpt(); ?>
	<?php } else { ?>
	<?php the_excerpt(); ?>
	<?php } ?>

Custom Post Types

One of the most versatile way to extend your WordPress site as a full blown content management system is with custom post types. A custom post type is the same as Posts, except you can add as many of them as you want, and with as much custom functionality as you want.

If you’re interested in using plugins, you can download the Advanced Custom Fields plugin, which will add a great deal of customizability to your theme with little effort.

For now, I’m going to show you how to set up a simple custom post type, and call the post in it’s own loop. There is much more that can be done with custom post types, but that’s a bit more complicated and deserves an article all of its own.

Custom Post Types on the WordPress codex will also give you more insight on some of the possibilities available.

In functions.php, I’m going to create the custom post type called My Custom Post.

// Custom Post Type
function create_my_custom_post() {
			'labels' => array(
					'name' => __('My Custom Post'),
					'singular_name' => __('My Custom Post'),
			'public' => true,
			'has_archive' => true,
			'supports' => array(
add_action('init', 'create_my_custom_post');

In the create_my_custom_post(), I’ve created a post called My Custom Post with a slug of my-custom-post. If my original URL was, the custom post type would appear at

In supports, you can see what I’m adding – title, editor, thumbnail, and custom fields. These translate to the fields on the back end that will be available.

  • title is the title field that I call with <?php the_title(); ?>.
  • editor is the content editing area that I call with <?php the_content(); ?>.
  • thumbnail is the featured image that I call with <?php the_post_thumbnail(); ?>.
  • custom-fields are custom fields that I can add in and call later.

I’ve decided I’m going to make a new page for the custom post to loop in. I created a page called Custom, which will appear at Right now, my page is pulling from page.php, like all the other pages.

I’m going to create page-custom.php, and copy the code over from page.php. According to the WordPress template hierarchy, a page-name.php will override page.php.

The original loop we used looked like this:

if ( have_posts() ) : while ( have_posts() ) : the_post();
	// Contents of the Loop
endwhile; endif; 

A custom post type loop will look like this:

$custom_query = new WP_Query( $args );
while ($custom_query->have_posts()) : $custom_query->the_post();
  // Contents of the custom Loop

Note that this only a while, and does not have an if or endif.

I’ll have to define the $args or arguments, before the loop.

$args =  array( 
	'post_type' => 'my-custom-post',
	'orderby' => 'menu_order',
	'order' => 'ASC'

Here I’m defining the post type as my-custom-post, and ordering the posts in ascending order.

So here’s the entire code for page-custom.php.

<?php get_header(); ?>

	<div class="row">
		<div class="col-sm-12">

				$args =  array( 
					'post_type' => 'my-custom-post',
					'orderby' => 'menu_order',
					'order' => 'ASC'
				 $custom_query = new WP_Query( $args );
            while ($custom_query->have_posts()) : $custom_query->the_post(); ?>

				<div class="blog-post">
					<h2 class="blog-post-title"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
					<?php the_excerpt(); ?>

				<?php endwhile; ?>
		</div> <!-- /.col -->
	</div> <!-- /.row -->

	<?php get_footer(); ?>

Now will only pull in posts from the custom post type we created. Right now, the custom post type is set up to only do things that the normal posts can do, but the more you fall down the rabbit hole, the more possibilities you discover.


We covered a lot of ground in this article; you should now be able to…

  • Create individual pages for blog posts
  • Add pagination to a blog
  • Add comments to a blog
  • Add WordPress functions
  • Enqueue scripts and stylesheets properly
  • Have a proper page title
  • Create custom global settings
  • Create a custom post type

All the source code is on GitHub as always. You can download the code and upload it into your themes folder and see it in action. I might set up a demo if there’s any interest in that.

There is much more that custom post types can do – and much more that WordPress can do, as well. I haven’t touched on the theme customizer, which is the most current way of creating themes.

I plan to continue this WordPress series and expand upon custom post types and what they can do. For now, I hope you learned something new, and of course, please feel free to reach out if I made any mistakes or errors or included any wrong or outdated information.

View on GitHub

Part Three

Update 8/11/16

In part three, I discuss how to add custom fields and meta boxes to a post!

Go to Part 3

92 comments on “Developing a WordPress Theme from Scratch Part 2: Pagination, Comments, Single Post, Functions, & Custom Posts”

  • Yoni says:

    Hi Tania,

    you missed an echo right here to display the data already registered :

    <input type="text" name="twitter" id="twitter" value="<?php echo get_option('twitter'); ?>">
    <input type="text" name="github" id="github" value="<?php echo get_option('github'); ?>">

    Apart of that, good tutorial

  • hasyemi says:

    Halo Tania, your tutorial is really amazing.

    But after reading and learning from the WordPress guidelines, they said that we need to use Costumizer setting rather than custom setting.

  • Aslam says:

    Thanks for this wonderful tutorial i have one doubt How to change post order to descending?

  • LJ Nissen says:

    I’m thinking about converting my site to WordPress and I found this tutorial very helpful. It’s even more helpful because you use Bootstrap as a template for responsive design.

    What I’m puzzled about is how you treat the images for the individual pages (ABOUT and CONTACT etc). Do you just keep the Bootstrap-code and call each page dynamically or do you upload them as Media files in WordPress?

  • jitu says:

    Hi, Tania
    Great article, and i’m learn lot of from them. from few i search a lot of wp tutorial for convert static web to wp themes… this me a lot to develop my first wordpress themes

    Keep it on.

  • Vikrant Negi says:

    Nice tutorial on WP.
    I just wanted to know how can i add multiple google fonts to the functions.php. You have used the enqueue to add Open sans fonts.

    I want to add multiple google fonts like roboto, raleaway etc to my wp site and i don’t know exactly how to do that the right way. D i need to copy that functions for each of the fonts or edit the current function in some way.


  • Jawad says:

    Great article…

    I am new to wordpress and was already impressed with “Create Global Custom Fields” section… but then I found that customizing the themes this way is already obsolete and customizer should be used.

    ” I haven’t touched on the theme customizer, which is the most current way of creating themes.”

    Hopefully you will write an article soon on customizer.


  • Zia Partovi says:

    I am coming from Java and .Net world and have worked with several content management systems (CMS) developed for these platforms. I have recently started working with WordPress and I am very impressed with the design, architecture of this CMS. It is absolutely the most complete CMS and extremely flexible.

    Since I want to develop my first theme for the WordPress I started searching internet for tutorials and discussions about this matter and I came across your tutorial. This is the first tutorial that I was able to comprehend and understand it in first read and believe me I have been in this field for over 30 years and I have read lots and lots of tutorials. You have a niche for teaching. You have the ability to explain matters in a very plain and clean way. You make it easy for your readers to understand you and follow your words. Thank you very much for such comprehensive article. It has been very useful to me. I will continue reading the other parts. Keep up the great work.

  • Chris says:

    You have a really great style of writing and explaining – thanks so much for posting these fantastic tutorials !

  • Keith says:

    I’m a long time user of WP, finally deciding to learn how to create my own custom site with WP plus bootstrap. I read both parts over and over and you’ve opened my eyes to the real power of WordPress. Thanks for taking the time to explain so clearly! And thank you again!

  • Yogesh says:

    how to use bootstrap.min.css in localhost in header file i edit any file (width:1170px;) plz suggest me

  • Beezy says:

    Hi Tania,
    When I try to do the custom post. I am able to go to the page where they should be displayed, but it doesnt display the custom post I made.

    When I click to go view the permalink, it says it cannot find it. (Not 404, it's working but it givs a message saying it cant find it.)

    I have researched countlessly and still cannot solve this. I used the default function snippet in the functions for a custom post page and copied and pasted the snippet from page-custom.php.

    Is there anything where I might have went wrong? Any naming conventions I need to change if I changed the names of anything? I really am at a loss here.

    • Beezy says:

      I realized what I did wrong, and in fact I don’t think I recall you mentioning this but, once you have edited your functions.php file. You need to reset your permalinks for the changes to take effect that is if you get this error.

      I now have another issue that is really weird. The posts show, but they don’t get listed in the custom posts page.

    • beezy says:

      Solved, you didnt mention to refresh permalinks after editing functions.php for the custom post type.

      New issue; my custom post type page doesn’t list the posts like its supposed to.

      Its not the page-custom.php file, I checked that. Its certainly not the snippet you gave us.

      what could it be?

      • Beezy says:

        I just realized that page-custom.php was the issue.

        so to make it short – page-custom.php should be page-whatever you named that special extra page to.php


  • Hikups says:

    Great article! i almost got lost learning a framework when i stumbled on this great post. Thanks! I hope the third part is coming soon !

  • Hi, Tania
    Great article, and i’m learn lot of from them. i enjoy them. but i have a some issues in making WordPress theme.
    please tell me about how to put main slider and logo.

  • Gagan says:

    There is problem for me. I cant see my sidebar in front-end and also cant see the widgets option on back-end .
    please help me ?

  • Ilya says:


    “In order for these to properly be inserted into your theme, needs to be placed before the closing tag, and before the closing tag.”

    Missing this ?

  • James says:

    Absolutely amazing tutorial. Your way of explanation is amazing….. Thank you so much Tania

  • pamela sillah says:

    By far the absolute best wordpress tutorial on the web! thank you for explaining everything so clearly! after struggling with various PDFs and video tutorials, this one made complete sense. thanks a lot. Im definitely recommending this site to my colleagues. 😀

  • Manuel says:

    Hi! Thx for ur very very clear tutorial!! Just one thing to better understood…i try to create new fild in : Custom settings.
    And all works very good! but in functions.php like u say in ur tutorial u create a page called options.php…where is?
    Really thx again and could we wait for a third part of tutorial? 😉 Bye!

  • Dennis says:

    Hi Tania,

    great tutorial for building my first WordPress theme, have a lot of experience with Joomla but none with wordpress. One question for you. Is it possible to create multiple (2) sidebars? Must they be defined in the theme or should i define them in widgets.php?

  • Itay Banner says:

    Your theme doesn’t make any use of the ‘style.css’ file. All the styling is done in ‘blog.css’ – why is that? Hi Tania, Thanks again for your brilliant and friendly tutorial!

    • Itay Banner says:

      Hmmm. cut-paste accident: the “Hi Tania” part should have come first 😉 sorry…. it’s 01:10AM here

      • Tania says:

        Hi there – the style.css, located in the root of the WordPress theme, is mandatory for a WordPress theme to work, based on the comments in the css file. I prefer to put all my styles in a dedicated /css/ directory, so I just leave the mandatory stylesheet there to define the theme and nothing else.

  • Riya says:

    Hi… How to register image size for featured images in functions.php ? please help me.:(

    • Tania says:

      You mean custom thumbnail sizes? You can do so like this.

      // Add 250 x 250 Custom Thumbnail Size
      add_image_size( 'custom-thumbnail', 250, 250, true );

      And retrieve it like this.

      $thumb = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'custom-thumbnail' );
      echo $thumb[0]; ?>
  • Anonymous says:

    Good stuff, keep posting blogs and tutorials as you enlighten people like me in tutorials like this.

  • Tomas says:

    Hi, awesome tutorial, i am looking forward to the next one. I have little issue at the end while trying to create custom post type. When i created fucntion “create_my_custom_post()” i have custom post option in back end, thats alright. After that i created page-custom.php file so i could be able to see my custom posts. Problem is that i dont have “Custom” button in main navigation bar as u have it on picture in tutorial. So i cant access this custom posts. Should i create it somehow and link it to the custom posts? Or should it be there already?

    • Tania says:

      It should show up regardless of whether or not you have created the page, so I guess just try copying the code exactly and making sure that theme is activated.

  • Rowell says:

    Hi Tania,

    This is really helpful. Now I can understand wordpress structure. I never use a wordpress before so this is the article I am looking for to start.

  • YONG MIN JI says:

    Wow It’s amazing tutorials I’ve ever seen. It really helps me Thanks!

  • Pingback: sienna sample
  • Mahmud says:

    Thank you so much for your tutorial. Your tutorial helped me much. But you haven’t write archive.php, search.form, widget like navbar. It would be very helpful if you write some tutorial on Advances WordPress. Would you please write about an ideal wordpress theme such as the themes like’s? Please help providing more tutorials.

    I am surprised because there is no advertise in this website. I try to help writer clicking their ads in pages. Thank you.

  • Mohammed says:

    Good job Tania and very helpful.

  • jjerro says:

    thank you again Tania.. Btw, there was no option to create menu using selected page and post category.. every page i made just popping up as in menu section.. how can i make this possible.. any references? thank you..

  • Schiler says:

    Thank you very much for these two posts! They helped me a lot getting started with theme developing! 🙂

  • toto sugito says:

    Thank you very much for this tutorial. I am new wordpress developer. Your tutorial very help me. Thank you

  • Brandon says:

    Hi Tania,

    Featured Image isn’t working for me, i supposed i only need to paste below codes into functions.php ,
    but after that, i still can’t see an image upload area T.T please advise, thanks.

    // Support Featured Images
    add_theme_support( ‘post-thumbnails’ );

    • Tania says:

      That’s literally all there is to it – as long as you have the correct theme active, you’ll see the upload area in the bottom right of your post.

    • René says:

      I also added

      add_theme_support( ‘post-thumbnails’ );

      to functions.php. But even if I add an image to a blog post by selecting an image and pushing the blue button, the image it does not become visible, when I view the blogpost.

  • Brandon says:

    Hi Taniam

    I’m confused in the “Enqueue Google Fonts” section

    i have copied “bootstrap.min.js”, “bootstrap.min.css”, “blog.css” to /cs and /js folder,

    and copied below codes into functions.php , but font still not work, is something missing? Thanks.

    // Add scripts and stylesheets
    function startwordpress_scripts() {
    wp_enqueue_style( ‘bootstrap’, get_template_directory_uri() . ‘/css/ootstrap.min.css’, array(), ‘3.3.6’ );
    wp_enqueue_style( ‘blog’, get_template_directory_uri() . ‘/css/blog.css’ );
    wp_enqueue_script( ‘bootstrap’, get_template_directory_uri() . ‘/js/bootstrap.min.js’, array(‘jquery’), ‘3.3.6’, true );

    add_action( ‘wp_enqueue_scripts’, ‘startwordpress_scripts’ );

    // Add Google Fonts
    function startwordpress_google_fonts() {
    wp_register_style(‘OpenSans’, ‘,600,700,800’);
    wp_enqueue_style( ‘OpenSans’);

    add_action(‘wp_print_styles’, ‘startwordpress_google_fonts’);

    • Tania says:

      Do you have <?php wp_head(); ?> and <?php wp_footer(); ?> in your theme? Also there’s a typo in bootstrap.css.

      • Brandon says:


        1.”” in header.php between tag and
        in footer.php before the end of tag.

        2. in footer.php before the end of tag.

        You are correct , i corrected the typo, and the bootstrap.css working properly.

        I wanted to post the codes here ,
        but not sure why codes can’t display, seem some limit from comment box,
        can i email the codes to you? Thanks.

        • Brandon says:

          Hi Tinia,

          Some code can’t display , i’m try to removed the php tag, thanks.

          1.”php wp_head();” in header.php between tag and
          in footer.php before the end of tag.

          2.”php wp_footer(); ” in footer.php before the end of tag.

          You are correct , i corrected the typo, and the bootstrap.css is working properly.

  • Brandon says:

    Where?i can download below files?


    • Tania says:

      Bootstrap – there’s a big download button right on the front page.

      • Brandon says:

        Hi Tania,

        I have downloaded the bootstrap 3.3.6 on yesterday already ,
        but i can’t find out the
        bootstrap.min.js and bootstrap.css files

        finally , i open the link in footer.php “”

        and save them as bootstrap.min.js file and put it into /js folder


  • Rakesh Ranjan says:

    Awesome Tutorial!!!
    I made my first theme from scratch. However if i want to give option for adding custom css in the theme can we do that using setting API.

  • Shahid khan says:

    How to display Custom post on my home page

    • Adeel Khaki says:

      Just get code from page-custom.php in above tutorial and create a short code like recent post short code and use it to any where int the home or any page.
      for example create a function.
      function my_custom_post_type(){
      —–Code here ———–

      refrence it here

      use it on home page like [custom_posttpe]

  • Chris says:

    Outstanding clear cut post, thank you! I look forward to the rest of your series, and thank you for the time you have taken to share your knowledge!

  • Dhaval M Patel says:

    this is the very helpful article for wordpress theme creation from scratch..

  • Ilya says:

    Awesome tutorial!

    Now page.php is pulling in content.php. Maybe page.php should pulling in content-single.php?


  • Sab says:

    Great Post maam! but clarification on this part?

    “In index.php, between endwhile; and endif;, I’m going to place this code”

    <ul class="pager">
    <li><?php next_posts_link( 'Previous' ); ?></li>
    <li><?php previous_posts_link( 'Next' ); ?></li>

    It returns an error.

  • Joao Devson Mucavel says:

    Awesome, Liked it!! Thank uu

  • Ex094 says:

    Tania, Thank you for putting up such an awesome tutorial, I’ve just started WP development and this tutorial has helped me a lot in the process. Danke!!

  • Yogesh says:


    Guys, I am very happy today after reached on this nice blog. I am going to thank you for once time just for this wonderful read!!I definitely appreciated every bit of it and i also have you saved as a favorite to see next informative and excellent post.


  • Spahar says:

    Your tutorials are really great. I was reading an ebook about theme creation in WordPress and after some chapters I got lost… then I found your tutorials. They are really good and easy to follow, I am looking forward to reading the next part. Keep it up! Thanks a lot.

  • maria says:

    Thank you Tania, appreciated tutorial!

    * Enqueue scripts and styles.

    add_action(‘wp_enqueue_scripts’, ‘theme_styles’);
    function theme_styles() {

    wp_enqueue_style (
    get_stylesheet_uri() . ‘/style.css’

    For me it does not work, so far only included with styles , but my new project not obtained.Can you help me?
    The structure of my files is :
    just template -main folder

    • Tania says:

      It should look like this.

      function theme_styles() {
          wp_enqueue_style( 'style', get_template_directory_uri() . '/css/style.css' );
      add_action( 'wp_enqueue_scripts', 'theme_styles' );
      • maria says:

        Again not work.

        Shows only this message:
        The following themes are installed but incomplete. The topics should have a list of styles (stylesheet) and template (template).

        I moved css file in the folder and again did not work.I tried with files from working themes and again does not work, do not know where to look for error .In previous works I had no such problems.

  • says:

    Awesome tutorial tania, really helpfull to learn more about custom post type in wordpress and query modifications.

  • Mat says:

    Thank you Tania, appreciated tutorial! 🙂

  • Lucas says:

    Hello Tania, great post.
    What would be the steps to create a portfolio theme? All the tutorials show how to create a blog, but how can I create a page with a potfolio grid, the elements in the grid with different heights, with captions, etc. Do you know any tutorial like this?

    Thank you!

    • Tania says:

      The process to create a portfolio page would be largely the same; mostly the only difference would be in the HTML and CSS that you use to design the site. You can pull images in from the media gallery to create a grid.

  • Samuel says:

    This Tutorial is great!!

  • andrzej says:

    after following first part(about adding individual post pages) my theme has this strange bug. when I click on the single blog post it goes to individual page but the whole post is displayed two times. I think it has something to do with The Loop but I cant figure out what. also each single page shows only first 55 words.

    thank you for great tutorial!

  • jack says:

    Thank you so much for this..Looking forward to more of these…

  • Captain Bacon says:

    I guess next tutorial you could cover how to register Taxonomies.

  • Piet says:

    Not sure you follow current developments of WordPress, but your recommendation on altering the title tag in the header.php file is becoming deprecated.

    You should remove everything to do with title from the head section and instead add add_theme_support( ‘title-tag’ ); to the theme’s functions.php file.

    Since WP 4.1:

  • bill says:

    Thank you so much for this article. It really helps a lot! I’ve been struggling with wordpress for months and this is the best tutorial I’ve read so far.

    I really hope you’ll continue this up to one of the core functionalities of wordpress – the online shop. Even just the basic. Thank you 🙂

Leave a Reply

Your email address will not be published.

Markdown is enabled in comments. If you would like to post code in your comments, please indent your code by four spaces. HTML/PHP code must be escaped. Failure to do so will make me sad.


    def print_hi(name)
      puts "Hi, #{name}"