Tania Rascia

Skip Navigation
Developing a WordPress Theme from Scratch

Developing a WordPress Theme from Scratch

 /  902 responses

You know HTML, CSS, and JavaScript. You can make beautiful websites. Maybe you’ve heard about WordPress, but aren’t entirely sure how to implement it, or why you might need it. Maybe a client asked for WordPress, but you’re not really familiar with it. Maybe you’ve worked with it before, but don’t know how to make your own theme from scratch. Whatever the case, this article is for you.


All you need to start is a website. Any website will do. You don’t need to know any PHP, or have any prior experience with WordPress. Your website can be custom, or built on Bootstrap/some other framework.

You do need to know how to set up a local server environment. Fortunately, if you don’t know how, I wrote a short, sweet article about getting set up with one. It will only take a few minutes, so go ahead and do that first.


  • Install WordPress locally
  • Take an existing HTML website and convert it into a custom WordPress theme


I’ve made additional tutorials to add on to this one.

  • Part 2: Pagination, Comments, Single Post, Functions, & Custom Posts (intermediate)
  • Part 3: Custom Posts, Custom Fields and Meta Boxes (advanced)

What can WordPress do for me?

WordPress was originally built as a blogging platform, but is now what is known as a CMS – Content Management System.

Any website that you intend to make updates to can benefit from a CMS. If it’s a blog, you want to be able to add posts. If it’s a restaurant website, you want to be able to add and update menus. If it’s a company website, you want to be able to update prices, packages, and so on. This website is a custom theme running on WordPress. (Open source, too!)

If someone is paying you to make a website, it’s because they don’t know how or don’t have time to deal with code. It needs to be as simple as possible for the client. WordPress can help with all this and more.

Getting started: The design

I can’t stress enough how much it doesn’t matter what you use for your design – Bootstrap, Foundation, Skeleton, custom CSS. The point is that you have a website and you like how it looks.

I’m going to take an existing simple starter template and convert it into WordPress for this article.

Bootstrap Blog Template

This is one of the default themes on Bootstrap’s official website.

I have conveniently set up a GitHub repository of the code that you can pull to a local directory and follow along with me.

Don’t know how to use Git/GitHub? You can remedy that by reading my Getting Started with Git article. If you just want to get started without dealing with Git, just create a directory on your computer with index.html and blog.css and you’re ready to go.

Installing WordPress

There are plenty of articles out there about how to install WordPress. They make the process seem long and scary, and the first time you do it, it can definitely be a bit confusing. Here is the official guide to getting set up.

Since we’re using a local server and MAMP, I already know you have all the prerequisites to installation, and FTP is not necessary.

Create a place for WordPress to live

Make an empty directory on your computer somewhere, and point your localhost or virtual host to that directory.

Download WordPress

Go to the WordPress download page and download the latest version of WordPress.

Unzip WordPress

Unzip WordPress and place the contents of the folder into your directory.

Create a database

Update 2017: The latest versions of MAMP do not come with phpMyAdmin preinstalled. Instead, you’ll download SequelPro on a Mac, or SQLYog on Windows, both free programs. To enter the database after downloading, login to the host locahost (or, with username root and password root. The rest of the instructions will be the same.

Now, if you go to your local server in the browser, assuming the servers are on and everything is pointed to the right direction, you’ll get this message.

You’ll learn to love that message. In MAMP, click Open WebStart page. Find this near the top:

Click on phpMyAdmin. Click Databases > create database. I’m going to call mine startwordpress. That’s all you need to do in phpMyAdmin!

Configure WordPress

Alright, final step. Find wp-config-sample.php in your directory.

It will look exactly like this.

Don’t be nervous. Change the database name, username, and password, from this:

/** The name of the database for WordPress */
define('DB_NAME', 'database_name_here');
/** MySQL database username */
define('DB_USER', 'username_here');
/** MySQL database password */
define('DB_PASSWORD', 'password_here');

to this:

/** The name of the database for WordPress */
define('DB_NAME', 'startwordpress');
/** MySQL database username */
define('DB_USER', 'root');
/** MySQL database password */
define('DB_PASSWORD', 'root');

Find this:

$table_prefix  = 'wp_';

And change it to literally anything else with numbers and letters. For security. xyz_ or 735hjq9_, etc.

$table_prefix  = 'xyz77_';

Go to https://api.wordpress.org/secret-key/1.1/salt and replace the entire ‘put your unique phrase here’ with that generated code.

Save the file as wp-config.php in your directory.

Now, when you go back to your website and refresh, you should see this screen.

You’ll have to input a few things – username, password, e-mail address, and then you’re done. Congratulations, you have successfully installed WordPress! You will be redirected to /wp-login.php, where you can input your credentials to log into the backend. If you go to your main URL, You will see the default WordPress blog and “Hello, World!” post.

Creating your custom theme

Outside of configuring WordPress, almost everything you do in WordPress will be in the wp-content folder; everything else is core code, and you don’t want to mess with that.

From this point on, the WordPress Codex and StackOverflow will become your best friends. I’ll show you how to build a basic theme, but how you choose to customize your themes beyond that is totally up to you.

In Finder, follow the path of wp-content > themes to arrive at your themes folder. You’ll see the WordPress default themes – twentyfifteen, twentyfourteen, twentythirteen – and index.php. Create a new directory for your theme; I called mine startwordpress.

A WordPress theme needs only two files to exist – style.css and index.php.

In your custom theme folder, create style.css. It simply contains a comment that alerts WordPress that a theme exists here. Change the name, author, description, and so on.

Theme Name: Start WordPress
Author: Tania Rascia
Description: Bootstrap Blog template converted to WordPress
Version: 0.0.1
Tags: bootstrap

Remember the Bootstrap blog source code from earlier in the article? Move those two files – index.html and blog.css – to your custom theme folder. Rename index.html to index.php.

Your theme has now been created. Go to the WordPress dashboard, and click on Appearance > Themes. You’ll see the theme in the collection with all the default themes.

Activate the theme and go back to your main URL. Yep, it’s that simple. You’ve technically created a custom theme already. Of course, it doesn’t do anything yet beyond what a static HTML site can do, but you’re all set up now.

There is one thing you might notice – blog.css is not being loaded. Bootstrap’s main CSS and JS files are loading via CDN, but my local css file isn’t loading. Why?

My local URL may be startwordpress.dev, but it’s really pulling from wp-content/themes/startwordpress. If I link to blog.css with <link href="blog.css">, it tries to load startwordpress.dev/blog.css, which does not exist. Learn right now that you can never link to anything in a WordPress page without some PHP.

Note: Chrome no longer allows .dev local URLs. This example will use .dev, but you can use .test or something else of your choice.

Fortunately, this is easily remedied. There’s a few ways to do this, but I’ll show you the easiest way to start.

Locate where you linked to the CSS stylesheet in the head of index.php. This is what it looks like right now, but we’ll have to change it.

<link href="blog.css" rel="stylesheet">

We need to tell it to dynamically link to the themes folder. Replace the above code with the below code.

<link href="<?php echo get_bloginfo('template_directory'); ?>/blog.css" rel="stylesheet">

If you reload the page, you’ll see that CSS is now loading in. If it is not loading in, please do a hard refresh. The concept will be the same for images, javascript, and most other files you have in the themes folder, except PHP files.

If you were not successfully able to get the CSS to load, click on “View Source” and find the path of your CSS file in the code. It should be startwordpress.dev/wp-content/themes/startwordpress/blog.css. Make sure blog.css is saved in the correct location.

Note that this is not the most correct way to load scripts into your site. It’s the easiest to understand and it works, so it’s how we’ll do it for now.

Dividing your page into sections

Right now, everything is in index.php. But obviously we want the header, footer and sidebar on all the pages to be the same, right? (Maybe some pages will have slight customization, but that comes later.)

We’re going to divide index.php into four sections – header.php, footer.php, sidebar.php and content.php.

Here’s the original index.php. Now we start cutting and pasting.

Everything from <!DOCTYPE html> to the main blog header will be in the header file. The header usually contains all the necessary head styles and the top navigation to the website. The only addition I will make to the code is adding <?php wp_head(); ?> right before the closing </head>.

<!DOCTYPE html>
<html lang="en">

	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<meta name="description" content="">
	<meta name="author" content="">

	<title>Blog Template for Bootstrap</title>
	<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
	<link href="<?php echo get_bloginfo( 'template_directory' );?>/blog.css" rel="stylesheet">
	<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
	<!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
	<?php wp_head();?>


	<div class="blog-masthead">
		<div class="container">
			<nav class="blog-nav">
				<a class="blog-nav-item active" href="#">Home</a>
				<a class="blog-nav-item" href="#">New features</a>
				<a class="blog-nav-item" href="#">Press</a>
				<a class="blog-nav-item" href="#">New hires</a>
				<a class="blog-nav-item" href="#">About</a>
	<div class="container">

		<div class="blog-header">
			<h1 class="blog-title">The Bootstrap Blog</h1>
			<p class="lead blog-description">The official example template of creating a blog with Bootstrap.</p>

Same deal for the footer as the header. It will include whatever visible footer you have, your JS links (for now) and <?php wp_footer(); ?> right before </body>. Since I included the .container div in the header, I’m going to close it in the footer.

    </div> <!-- /.container -->

		<footer class="blog-footer">
      <p>Blog template built for <a href="http://getbootstrap.com">Bootstrap</a> by <a href="https://twitter.com/mdo">@mdo</a>.</p>
        <a href="#">Back to top</a>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<?php wp_footer(); ?> 

Most websites, especially blogs, will have a side area for including content such as archives, tags, categories, ads, and whatnot. (Content removed for brevity.)

<div class="col-sm-3 col-sm-offset-1 blog-sidebar">
	<div class="sidebar-module sidebar-module-inset">
		<p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p>
	<div class="sidebar-module">
		<ol class="list-unstyled">
			<li><a href="#">March 2014</a></li>
			<!-- More archive examples -->
	<div class="sidebar-module">
		<ol class="list-unstyled">
			<li><a href="#">GitHub</a></li>
			<li><a href="#">Twitter</a></li>
			<li><a href="#">Facebook</a></li>
</div><!-- /.blog-sidebar -->

If the sidebar is where all the secondary information goes, the content is where all the articles and main content of the website go. (Content removed for brevity.)

<div class="blog-post">
	<h2 class="blog-post-title">Sample blog post</h2>
	<p class="blog-post-meta">January 1, 2014 by <a href="#">Mark</a></p>

	<p>This blog post shows a few different types of content that's supported and styled with Bootstrap. Basic typography, images, and code are all supported.</p>

<!-- the rest of the content -->

</div><!-- /.blog-post -->

The index file should be pretty sparse now. In fact, it should only be this:

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

Now we’re going to add everything back in. Here’s your new index.php.

<?php get_header(); ?>

	<div class="row">

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

			<?php get_template_part( 'content', get_post_format() ); ?>

		</div> <!-- /.blog-main -->

		<?php get_sidebar(); ?>

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

<?php get_footer(); ?>

Even if you’ve never used PHP before, this code is all very self explanatory. get_header();, get_sidebar(); and get_footer(); are all functions that look for their respective .php files and insert the code. Of course, they all go inside their own <?php ?> tags to let the server know to parse them as HTML. The content function is slightly different, but it does the same thing.

If you re-load your URL, your entire site is now loaded, just as before. You will notice a top bar if you’re logged in to the back end.

Main Settings

Before we start pulling in posts and pages, we need to configure some main settings of WordPress. For example, my title right now is “The Bootstrap Blog”, hard coded in HTML. I want the <title> and <h1> of my site to be changeable through the back end.

In your dashboard, go to Settings > General. Set your title.

In header.php, change the contents of the title tag and main h1 tag to this code:

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

And the description to this one.

<?php echo get_bloginfo( 'description' ); ?>

Finally, I want the title to always take me back to the main blog page. bloginfo('wpurl'); is the code that will do that.

<a href="<?php echo get_bloginfo( 'wpurl' );?>"><!-- site title --></a>

Here’s the full code in case you’re confused.

<div class="blog-header">
	<h1 class="blog-title"><a href="<?php echo get_bloginfo( 'wpurl' );?>"><?php echo get_bloginfo( 'name' ); ?></a></h1>
	<p class="lead blog-description"><?php echo get_bloginfo( 'description' ); ?></p>

We’ve finally made the first dynamic change to the page. The front end should reflect what you put in your settings.

Now go to Settings > Permalinks. By default, WordPress is set to Day and name, which is a really ugly URL structure. Click on Post name and apply the changes.

The Loop

The most exciting part is being able to dynamically insert content, and in WordPress we do that with The Loop. It’s the most important function of WordPress. All of your content is generated through a loop.

In the dashboard, if you click on Posts, you will see a “Hello, world!” post in there by default. Our goal is to display that post in the blog.

The Loop itself is quite simple.

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>

<!-- contents of the loop -->

<?php endwhile; endif; ?>

It explains itself – IF there are posts, WHILE there are posts, DISPLAY the post. Anything inside the loop will be repeated. For a blog, this will be the post title, the date, the content, and comments. Where each individual post should end is where the loop will end. We’re going to add the loop to index.php.

Here’s your new index file.

<?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(); ?>

The only thing inside your loop is content.php, which will contain the contents of one single post. So open content.php and change the contents to this:

<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 -->

It’s amazingly simple! the_title(); is the title of the blog post, the_date(); shows the date, the_author(); the author, and the_content(); is your post content. I added another post to prove at the loop is working.

Awesome. Let’s make the sidebar dynamic, as well. There should be a description and archive list in the sidebar. In the dashboard, I’m going to edit my user description to say “Front end web developer and professional nerd.”

Delete all the <li>s under Archives and change it to this code.

<ol class="list-unstyled">
	<?php wp_get_archives( 'type=monthly' ); ?>

For my description, I’m going to pull in metadata from my user account.

<p><?php the_author_meta( 'description' ); ?> </p>

Now this content is being pulled in dynamically as well.

Here’s my blog so far.

Menu and Pages

Okay. Now we know how to make a blog, and edit some sidebar content. Only one main aspect of this page remains – the navigation, and where it leads. Well, there are two main aspects to WordPress – Posts and Pages. They’re very similar in that they both use the Loop. However, pages are where you put content that isn’t a blog post. This is where the CMS aspect of WordPress comes in – each individual page can be as customized as you want.

In the dashboard, I added a page so we can see two. First, we’re going to edit the navbar so that the links lead to the pages. Back in header.php, find and change this code.

<div class="blog-masthead">
	<div class="container">
		<nav class="blog-nav">
			<a class="blog-nav-item active" href="#">Home</a>
			<?php wp_list_pages( '&title_li=' ); ?>

wp_list_pages(); will list all the pages you have in an unordered list. 'title_li=' is telling the code not to add a “Pages” title before the list. Unfortunately for us, this looks terrible; the original blog.css has the links coded in a tags, not li tags.

Fortunately, this is a very easy fix. I’m just going to apply the style from one to the other. Add this to blog.css

.blog-nav li {
    position: relative;
    display: inline-block;
    padding: 10px;
    font-weight: 500;	
.blog-nav li a {
    color: #fff;

Now it should show up correctly. However, if the CSS is not applying, please View the source of your HTML output and find out what the URL of your CSS is. It should be startwordpress.dev/wp-content/themes/startwordpress/blog.css. Make sure to do a hard refresh.

Much better.


I want the pages to have a different layout than the blog posts; I don’t want sidebars on them. Think of index.php as the blog-index and page.php as the page-index. I’m going to create page.php, which will be very similar to the index except have a full 12-wide grid instead of an 8-wide content and 4-wide sidebar.

<?php get_header(); ?>

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

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

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

<?php get_footer(); ?>

When I click on my sample page, the layout is now different than the blog post layout.


There is much, much more to learn about WordPress. I sincerely hope this article opened a world of possibilities to you. Now you know that any website can be converted into a WordPress theme – without using plugins, widgets, or someone else’s theme.

If something was unclear, please let me know. If I’ve posted any blatantly incorrect information, please let me know! Any feedback is greatly appreciated! My aim was to make the article I wish I had in front of me when I first started learning how to use WordPress and PHP.

If you would like to know how to migrate this local instance to a live server, view this small tutorial:

Migrating WordPress

Last updated: 4/16/2018

In part two, I discuss additional functionality for WordPress, such as paginaton, comments, functions, custom post types, and more. In part three, I go over how to create custom fields and metaboxes.


Get updated when I create new content.
Unsubscribe whenever. Never any spam.


I'm Tania. I turn down every ad, affiliate, and sponsor request I get. I write free resources that help thousands of people successfully become devs. If you enjoy my content, please consider supporting what I do.

Support my work

Write a response

Your email address will not be published. Required fields are marked *

All code will be displayed literally.


  • Keith Morgan says:

    thank you so much

  • Jack Pistro says:

    Thanks for Tutorial…Its amazing..

  • Monika says:

    I was opening WordPress on the local server before. After I have installed WordPress through Hostgator. Now I cannot reestablish the connection on local through the server even if I follow the instructions 🙁

    • Monika says:

      Does it mean I cannot have installed WordPress on local MAMP and through Webhost Hostgator at the same time? What is the best way to work on the theme?

      • Orion says:

        Hey how are you ? i migrate mine form bluehost, godaddy all the time. One thing to look out for is make sure you are changing your home and site urls in and pointing to your localhost, i had this issue and it really tossed me for a loop. Hope this is the same issue. Best of luck to you

  • Alia says:

    Awesome article. This is by the far the clearest one I've found. I have a client who wanted a wordpress site and I was tearing my hair out until I came across this tutorial. I'm definitely buying you a coffee. Thanks so much!

  • Stain says:

    Thanks for the tutorial

  • balint says:

    I think with your great explanation here I am on the right track, thanks!

  • Deanna says:

    You're amazing! Thank you for the helpful tutorial! 🙂

  • Arek says:

    thank you very much for this tutorial.

    Best Regards

  • Kurtis says:

    Great post! 🙂

    Looking forward to parts two and three.

  • Munir says:

    Your efforts are greatly appreciated, may god bless you Tania.

  • Lee B says:

    Hi Tania,

    Thanks so much for all you do to help complete beginners like myself!

    Everything was going swimmingly and I was on Part 2 of your WordPress from Scratch tutorial when my SQLyog started giving me the following error –

    "SQLyog Community
    Error no. 2058 plugin caching_sha2_password could not be loaded: The specific module could not be found."

    I have no idea what has triggered this and having Googled it into oblivion over the last three weeks I thought I'd post here and see if you or one of your followers can help?

    I'll keep anyone up to their eyeballs in coffee if they can assist! I'm on Windows 10 btw and have next to no coding experience so apologies in advance if I've missed something obvious. Also I don't have MySQL installed and pretty much every page on Github or Stack Overflow that talks about my error code mentions MySQL… but your original tutorial didn't say I'd need it and everything worked fine until recently?!?! So I don't have MySQL.

    Kind Regards,
    Lee B

  • Anonymous says:




    Great blog Tania. Your role in making people tread the learning curve easily is very commendable!

  • Victoria Grace says:

    A resourceful article indeed. You’ve covered all the necessary steps to create a WordPress website from the scratch. I believe many have already made a WordPress website with the help of this article. Those who have made one and struggling to index their websites on Google and get a good ranking can read this article on <a href="https://fluentthemes.com/speed-indexing-wordpress-site/">"Index Your WordPress Site In Google-5 Killer Methods To Rank Your Site At The TOP!!"

  • Drin Dagsaan says:

    Hello There Tania! This is really a great tutorial..

    I only have some issue/clarification on the page.php part, so I created the page.php with 12 columns wide but i'm stuck
    on implementing it as a page index..
    How can I do that?

  • Rebeca Lopez says:

    Hi Tania, you'll see, my menu appears like an unordened list yet, and I did every step. I haven't idea how to fix it. I tried to add: "list-style: none" to the unordened list, but that is not enough for fix it. 🙁

    • eric jose says:

      Hi Rebecca,if you have done what Tania has told to do, that is write the CSS for .blog-nav li & .blog-nav li a & made sure blog.css is attached by right clicking and checking the page source for the link to blog.css after bootstrap.css.

      then the only thing that remains to be done is do a hard refresh, that is clearing all the history in your browser and then reloading the page.

      hope that helps and you have with wordpress.

    • Mroched says:

      ul li {
      display: inline-block;

  • Tony Conte says:

    This is a great tutorial. Super way to digest the subtle differences from a page being in a file to a CMS. I did have one issue that tripped me up for a while. When I put the loop code in, and went to display my blog posts, I kept getting my front page rather than the blog posts. Double checked the code and restarted the server, but always the same thing. I started looking at the Site Settings and found on Reading Settings the answer. I needed the first radio button to be selected "Your home page displays…Your latest posts" As soon as I selected this and refreshed the page, it worked fine. It was set by default to "A static page" which was my front page. Hope this will help others that have this issue.

    Really liking the capability in WordPress, very powerful. This tutorial is an excellent introduction into this world…thank you Tania. Time to buy her some coffee!

  • Phil says:

    Hi there thank you so much for the tutorial. Im unfortunately stuck at still not able to get the CSS to load

    "If you were not successfully able to get the CSS to load, click on “View Source” and find the path of your CSS file in the code. It should be startwordpress.dev/wp-content/themes/startwordpress/blog.css. Make sure blog.css is saved in the correct location."

    Could you please explain how to find the path of the CSS file in the code? Ive opened the page source but don't really know what Im looking at

    Thank you very much!

    • Vaibhav says:

      Hi Phil,
      When you go to View Source, press ctl+f or find in page and put the name of your css file with coreect case.

    • James says:

      Hi Phil, mine didn't work at first and I racked my brains for ten mins. Then I tried clearing the web browser cache so as to force to reload the updated blog style sheet and it displayed fine then.

      • Tony C. says:

        I had the very same issue. I restarted my MAMP server, but still didn't work. When I cleared the browser cache, it worked fine. Thanks for that reminder!

  • Genesis Murillo says:

    Super helpful! This is the perfect start for me!

  • anmar albahramai says:

    Hello ,
    thanks alot about the important informations . my question is : i can create a theme but when i active the register nav menu and by example use bootstrap navbar i show the links of the pages which i creat it in the wp-admin
    but the question is : how can i control the navbar to put a picture in the midle of the navbar how to active the templates of the pages and control it .
    excuse me for my english .

  • AI Sudin says:

    Hello Tania! Thank you so much for such a great post on WordPress Theme Development. This is in fact the most helpful, insightful and easy-to-follow post on WP theme building in the entire web. However, I was wondering if you could write another post on menu registering and styling with pure CSS (for those like me who already have hand coded responsive websites but want to harness the extensive features of WP), form styling, and perhaps integrating tables in single post pages.

    Would you please add two more parts to this great post and help millions like me? You are my WP mentor, and I will surely buy you a coffee along the way. 🙂

  • byteexp says:

    hi there,
    what is the difference between using content.php
    and vs. placing everything inside the index.php

    • kali says:

      hi byteexp,

      >> what is the difference between using content.php
      and vs. placing everything inside the index.php

      these things about WP that sometimes make no sense or you're wondering why it's done this way and not this other, simpler, way is so the website continues to function properly after you upgrade to a newer version of WP, or change themes, etc..

  • Judy Saunders says:

    What a helpful article! Thank you so much. I am still very new to HTML and CSS (haven't learned PHP or JS or anything else yet), and I was able to take my raw HTML and CSS and apply your changes to that and got a nice looking theme. I am wondering why (in the theme selection panel of WordPress) my theme just shows as black and white checkers instead of a pretty screenshot like the default themes. Did I miss a step? Thank you again.

  • Manoj Kumar says:

    Thanks , it was really helpful for a starter or for an experienced web designer like me who knows customizing WordPress any how, but never thought for creating from scratch.

    This really helped me to understand the basic idea behind a theme.

  • Rohit Goyal says:

    Thank you so much for this. Please also write blog on custom comment_template(how to change label name and remove mandatory option at input field).

  • Jordana says:

    Great guide! Thank you so much! <3

  • newsbd69.com says:

    Great Post..
    Keep it up……
    Thank you so much

  • Reader says:

    Hello Tania and Thanks for This Post.

  • Anonymous says:

    great guide thanks

  • Borjan Mukaetov says:

    Also to know that the example for page.php is working only with "Plain" and not "Post name"or any other permalink

    i don't know why … i'm trying to figure it out.

    using WordPress 4.9.7

  • Daniele says:

    Great guide! Thank you!

  • Borjan Mukaetov says:

    i found that page.php should have

    * Template Name: My Special Template

    in front in order to show the name "My Special Template" on Page Attributes in Admin console in order to call the page.php

    pleasse add this to the article

  • Lee says:

    Helo Tania! Great article by the way. The only issue I have found is that my pages (Sample & Privacy) are not showing new information, only changing page format. Is this expected, or should the data inside of the pages be displayed? Thanks!

    • Lee says:

      Figured it out! Turns out I didn't make a change to my `content.php` file! You're guide is flawless, I just made an error 🙂

  • immanuel says:

    wow! thank you. i have looked all over the internet space, none was as much detailed as clearly stated as yours. thankyou!!

  • Leif says:

    Great, well written and easy to understand walk through.

    Thank you!


  • ajay says:

    how to add pagination in this type of template

  • Adrian says:

    In the startwordpress theme, Widgets(Dashboard >> Appearance >> Customize") disappear.
    How can I view Widgets or create "Search" separately?

  • Anonymous says:


  • Christo Fouche says:

    Hi Tania,

    Wow, what can I say. This was really a very awesome article. Exactly what I was looking for. Your style of presenting the information is clear and I had absolutely no trouble developing my own Bootstrap like WordPress Theme.

    Way to go !!

    Thank you

  • Steave Mark says:

    Very well written post. It will be useful to anybody who uses it, as well as myself. Keep doing what you are doing – looking forward to more posts.

  • Rohit Goyal says:

    This code is not working.
    .blog-nav li {
    position: relative;
    display: inline-block;
    padding: 10px;
    font-weight: 500;
    .blog-nav li a {
    color: #fff;

    • Nauman ALi says:

      Add this code in header.php
      <nav class="blog-nav">
      <a class="blog-nav-item active" href="index.php">Home</a>
      <?php wp_list_pages( '&title_li=' ); ?>

      and add this in blog.css or style.css
      .blog-nav li {
      position: relative;
      display: inline-block;
      padding: 10px;
      font-weight: 500;
      .blog-nav li a {
      color: #fff;

      and reload the website after clearing the history from browser

  • Jessica says:

    For menus and pages I was unable to get them side by side, I added the code to blog.css and checked the source of my HTML output. Any idea why?

  • Todd says:

    Oh my gosh! This tutorial was amazing. So easy to follow. I wish you had been my teacher for my WordPress class in college. lol.

    The only area I got a bit confused on was what to do with the Previous and Next buttons. It wasn't specified which file to put their section of the html on. I added it the content.php. However, when I added the second blog post, the Previous and Next buttons were showing up under both posts.

    Not a big deal really, as I was concerned with just learning the overall creation process of a custom theme. That mission was accomplished.

    Thanks, Tania!

  • Carmina Bas says:

    This really informative post! Honestly, I have no idea on customizing a blog especially PHP. When I was the one managing my business site, it was a scratch. So I decided to let my site managed with professional, they changed everything including the hosting. Currently, we are using WordPress and wphosted.net.

  • Zayne says:

    What happens if you open this in the backend WordPress? Would you have any options to change colors, button shape and all of that other fun stuff? This article was really helpful! I actually feel like I can do this.

  • pierre bukasa says:

    What's the advantage of running a wordpress website on your own server?

  • Luca says:

    I'm a beginner, and I know only the basics of html code. Is it enough to create a theme in the way you describe, or risk having a vulnerable site? Are professional knowledge necessary or is site security given by other things like SSL certificates?
    Sorry for my question, it's really silly.

  • Stephanie says:

    Coming from heavy Drupal background and a little experience dabbling with a couple established wp sites, I literally smiled when I found "A WordPress theme needs only two files to exist – style.css and index.php.", looking all important in its own box. Thank you.

  • Vincent says:

    Amazing tutorial, I really don't like WordPress but i have to use it for my customers. I didn't knew how to develop a custom theme, this helps me so much !

    Thanks !

  • Hassaan says:

    I have no words. You made it feel like a piece of cake!
    You made it so easy! Thanks a lot!