How to write a WordPress template from scratch

After trying to endlessly hack the WordPress API to make my own doggamn site I finally said FUCK IT… and decided to learn how to actually write a WordPress template. Use this tutorial when you are asked to deliver a quick website. Say in 30 minutes. Crazy, I know. But possible… here we go!

Set up WordPress

Let’s install and set up WordPress first. Download WordPress and follow the following great YouTube video on how to install WordPress. Now install the following plugins:

  • Ultimate TinyMCE
  • Custom content type manager
  • Simple Taxonomy (Then find it in Settings/Custom Taxonomies)

Optional plugins (bells and whistles):

  • Meta slider (Create multiple sliders/embed codes are provided on the admin screen once you start using it)
  • Ninja Embed Plugin
  • TubePress (For grabbing youtube channel or playlist feed and displaying the videos nicely with pagination)
  • Google Analytics
  • Contact form 7
  • Social Login (For users to be able to login with Facebook or Twitter to add comments on your site)

Also, download bootstrap and put it under wp-content/bootstrap.


Throw a .htaccess file under your WordPress installation root with the following content:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

Create a template

This is it! Create a new folder (named whatever you want your theme named) under wp-content/themes. For example wp-content/themes/mikhailisthebest. The most important thing to have in that folder is style.css. At top of style.css you must have a comment like the following:

Theme Name: Name-of-your-theme
Author: Your Name
Author URI:
Version: 1.0

@import url('../../bootstrap/css/bootstrap.min.css');
@import url('../../bootstrap/css/bootstrap-responsive.min.css');

That’s it, now WordPress will parse that top part of your style.css file and you will be able to see your theme it in the WordPress admin panel with all the metadata finely presented. For more information on what other fields can you define in style.css see this WordPress reference.

Bonus: Child themes

If you want to use all the goodies (such as style and functionality like pagination) from an existing theme, but you want to add or override some files, you can so-to-say “inherit” a theme. That is, your theme is what’s called a child theme and you have to specify the parent theme. You specify the parent theme in the top part of style.css by adding the following the Template field:

Template: twentytwelve

More information on child themes here on Codex.

MEGA-TIP: whenever you change the top part of style.css (AKA the theme meta) you need to deactivate and activate your theme again for these changes to be interpreted

WordPress template hierarchy

Consider the following picture:


This is the logic that the WordPress engine uses to pick what file from your template will be used to display the current content. That is, content of the current WordPress state your website is in, such as a page, a single post, a list of search results, page 2 of latest posts of type “video”, etc. This is the image that opened my eyes to how WordPress functions.

Also it made me feel very stupid, ’cause they do A LOT of shit for you.


One of the most important files to add to your template is functions.php. Here is a sample:

//============= 1 =============
function mikhail_loadscripts($more) {
    wp_enqueue_style('bootstrap', get_template_directory_uri() . '/bootstrap/css/bootstrap.min.css');
    wp_enqueue_style('bootstrap-responsivesss', get_template_directory_uri() . '/bootstrap/css/bootstrap-responsive.min.css');
    wp_enqueue_script('commonnnn', get_template_directory_uri() . '/js/common.js', array( 'jquery' )); // that last argument is dependency
add_filter('wp_enqueue_scripts', 'mikhail_loadscripts'); //add_filter is hooking a callback "mikhail_loadscripts" to an event "wp_enqueue_scripts"

//============= 2 =============
    'name' => __( 'Sidebarrr2', 'mikhail' ),
    'id' => 'right-sidebar',
    'description' => __( 'Widgets in this area will be shown on the right-hand side.', 'mikhail' ),
    'before_widget' => '<li id="%1$s">',
    'after_widget' => '</li>',
    'before_title' => '<h3>',
    'after_title' => '</h3>'

//============= 3 =============
    'travelmenu' => __('travelmenu navbar menu', 'mikhail'),

//============= 4 =============
add_theme_support('custom-header', array(
    'flex-width' => false,
    'width' => 960,
    'flex-height' => true,
    'height' => 200

Here is a rough description of what each part does:

  1. load CSS and Javascript like this
  2. register a custom sidebar (admin: Appearance/Widgets menu, you will see “Sidebarrr2” in the menu)
  3. register a custom menu (admin: Appearance/Widgets menu, you will see “mamamenu” in the menu)
  4. enable custom header, so you can configure the image displayed on the top of your blog. (admin: Appearance/Header)

As you can see the functions.php file can get quite big. Take care to keep it clean and organized. What I showed here did not even scratch the surface, but it is enough to make a basic website. Keep doing more templates and you will pick up more snippets on what goes into functions.php.

header.php and footer.php

It is very likely you will need a header and a footer. Otherwise you need to write html top to bottom from scratch EVERY TIME! Literally too.

About header: don’t forget to call wp_head(). This is the part that outputs the Javascript and CSS you registered on the “wp_enqueue_scripts” event.

Oh, by the way, remember “mamamenu” from function.php above? Well, we call on it here using wp_nav_menu(). It will inject the HTML.

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
    <meta charset="<?php bloginfo( 'charset' ); ?>" />
    <title><?php wp_title(); ?></title>
    <meta name="description" content="<?php bloginfo( 'description' ); ?>">
    <link rel="stylesheet" href="<?php echo get_stylesheet_uri(); ?>" type="text/css" media="screen" />
    <link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />
    <?php if ( is_singular() && get_option( 'thread_comments' ) ) wp_enqueue_script( 'comment-reply' ); ?>
    <?php wp_head(); ?>
<body <?php body_class(); ?> >
                <img src="<?php echo get_template_directory_uri(); ?>/img/plane.jpg" />
                <?php wp_nav_menu( array(
                    'menu'            =>      'mamamenu',
                    'depth'           =>      2,
                    'container_class' =>      'menu-mama-container',
                    'menu_class'      =>      'menu',
                    'menu_id'         =>      'menu-mama',
                    'fallback_cb'     =>      ''
                )); ?>

About footer: don’t forget to call wp_footer(). This is the part that adds the admin header which floats on top when you are logged in. Otherwise you won’t see it.

    <?php wp_footer(); ?>


Remember Sidebarrr2 from functions.php above? We will call on it here using dynamic_sidebar(), just like we did with “mamamenu” above.

<div id="sidebar">
        <?php if (!dynamic_sidebar(__('Sidebarrr2', 'mikhail'))) : endif; ?>


You must have index.php. In nothing else, according to template hierarchy, WordPress will look for index.php and render the current content with it. So make index.php as generic as possible. Then, for more specific cases, create other pages. But index.php comes first! We bring in our HTML chunks…

  • for header with get_header()
  • for footer with get_footer()
  • for sidebar with get_sidebar()
<?php get_header(); ?>
        <?php if (have_posts()) : while (have_posts()) : the_post();
            $post_format = get_post_format();
            get_template_part('parts/post', $post_format);
        endwhile; endif; ?>
        <?php global $wp_query;
        $big = 999999999; // need an unlikely integer
        echo paginate_links( array(
            'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
            'format' => '?paged=%#%',
            'current' => max( 1, get_query_var('paged') ),
            'total' => $wp_query->max_num_pages
        ) );
    <?php get_sidebar(); ?>
<?php get_footer(); ?>

A lot of shit just happened. Let me explain.

The Loop: AKA how it works

The piece of code above that looks like

        <?php if (have_posts()) : while (have_posts()) : the_post();
            $post_format = get_post_format();
            get_template_part('parts/post', $post_format);
        endwhile; endif; ?>

…is called the WordPress Loop, boys and girls. This is the heart of WordPress and the reason why so many people have jobs today. It will loop through posts in the current context, be it the top 5 posts on the home page (index.php or home.php), or a specific (single.php) post or a page (page.php) or search results (search.php). The template hierarchy is huge and there are many scenarios, but there is always a collection of zero or more posts on any WordPress page. See the above picture for template hierarchy.

When the_post() is called, many global variables (well, to be honest, just one, $post) are set and global functions such as the_title(), the_excerpt(), the_content(), the_mikhail()… oops, not that one, sorry, wrong blog… Anyways, all those functions take effect and will inject HTML when called. And if you know and understand this, that is the bare minimum of WordPress!


In the above code we use get_template_part() which renders a PHP from file. In this case it will look for parts/post.php. So, let’s create this file. Create a folder called parts. Then inside “parts” create post.php. It will have the following code:

<div <?php post_class(); ?> id="post-<?php the_ID(); ?>" >
    <?php if (has_post_thumbnail()) { ?>
        <a href="<?php the_permalink(); ?>">
            <?php $atts = array('class' => 'media-object', 'width' => 'full'); ?>
            <?php the_post_thumbnail('full', $atts); ?>
    <?php } ?>
        <h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
            <?php the_excerpt(); ?>
    <nav><?php wp_link_pages(); ?></nav>

And I believe that’s it. That is the bare minimum you must have in order to write a WordPress template. This is only scratching the surface. WordPress has much MUCH more to offer.

  • Custom content types
  • Custom admin pages and menus
  • Custom menu walker
  • Custom options
  • Shortcode injection to make use of other plugins (Like this: <?php echo do_shortcode(get_option(“homepage_slider”)); // ?>)
  • etc, etc, etc

There are a billion tutorials out there, read them too. Learn, learn, LEARN! Good luck!

Useful links

  1. Jerrod says:

    Very informative post, i’m regular reader of your website.
    I noticed that your website is outranked by many other websites
    in google’s search results. You deserve to be in top ten. I know what can help you,
    search in google for:
    Omond’s tips outsource the work

Leave a Reply

Your email address will not be published.