
Create Your Own WordPress Theme Framework
If “premium theme” was the talk of WordPress Land in 2025, I’d wager a bet that the favorite talk of 2026 will be over “theme frameworks.” There are plenty of awesome frameworks out there for you to use, too.
This post is going to offer a method for developing your own theme framework. We’ll learn from the aforementioned awesome themes, develop a plan of action, and follow through with building it out. Care to join?
What’s a theme framework?
A theme framework works ideally like any other type of framework. From one we should be able to build out other themes, faster and more easily than if we started from scratch.
Odds are you’ve at least heard of one or two of the WordPress theme frameworks out there: Understrap, _Underscores, and SeedProd are a few examples. Astra Pro is a fairly powerful addition.
But enough about them. This is about your theme framework.
Why does it have to be yours?
This is all about you, and not about any deficiency in any of the current theme frameworks. In fact, a key part of this whole process will be taking a look at some of the popular ones, to see just why they are as popular as they are.
There are a number of benefits to having your own framework, and building themes from them:
- Your framework will grow with your knowledge, and vice versa.
- A big part of WordPress is about the freedom to be empowered and create something of your own, something better.
- Manage your own roadmap. No changes you aren’t hip to.
Of course, not everything with a project like this will be rainbows and skittles. Creating and maintaining your own theme framework will bring with it its own difficulties:
- It means you’ll need to be staying on top of WordPress development. (Psst, keep on eye on this blog.)
- It means responding to questions/support, assuming you want to make your theme public.
- It means diligence — use your framework. If it works, it should work.
Frameworks aren’t for everyone, and managing your own framework is for far fewer. But at the very least the process of creating a theme framework can be both enlightening and rewarding. What you do with it in the end is up to you.
It’s the smartest and fastest way to catch up with what’s been happening in the field. It’s also the best way we can create something unique, something that stands out apart from the rest.
Now it’s time to start putting this know-how into practice.
In this part of the tutorial we’re going to nail down a flexible HTML
structure and very basic CSS
. From here we’ll be able to build out our WordPress theme files and start adding in some of what makes a framework a framework.
Establishing HTML
structure
We’re going to start off with the assumption that our HTML
won’t work in 100% of cases. That would be unreasonable. Instead, we’re going to aim so that we create an HTML
structure that will work with 95% of sites.
Think back to some of the sites you’ve put together, and some of the div
s you find you end up needing that you hadn’t anticipated. We want to anticipate those, within reason, right from the get go. Without further ado, I propose the following as a nice starting point:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>My Theme Framework</title>
</head>
<body>
<div id="wrapper">
<div id="header">
<div class="wrap">
</div>
</div>
<div id="nav">
<div class="wrap">
</div>
</div>
<div id="container">
<div class="wrap">
<div id="main">
</div>
<div class="aside">
</div>
</div>
</div>
<div id="footer">
<div class="wrap">
</div>
</div>
</div>
</body>
</html>
This gives us the most basic structure for each of our templates. Now let’s think ahead to what our layout will end up being. Since we don’t know, we have to prepare for any 95% of cases.
There are six basic layouts we may run up against. So in reality we’re looking at three layouts. One where there is a single column of content, one where there are two columns, and one where there are three columns. Structurally speaking, this is what we’re concerned with. With smart HTML
we shouldn’t have any problem swapping in different layouts later on.
So I propose the following additions to the HTML
we’re starting with (see line 30 for where this goes):
<div class="aside" id="primary">
</div>
<div class="aside" id="secondary">
</div>
Having both of these sidebar elements available will make it super easy to shuffle them around based on our needs.
(The files as-is at the end of this tutorial, and each subsequent tutorial, will be available for download. So don’t freak out too much about keeping track of changes.)
Quickly, some default content
To test the fidelity of our basic HTML
so far, let’s drop in some default content and run through a couple of scenarios.
First is our header:
<div id="header">
<div class="wrap">
<div id="site-title">
<h1><a href="#" title="Site title"><span>Site title</span></a></h1>
</div><!-- #site-title -->
<div id="site-description">
<p><span>A simple description for our website</span></p>
</div><!-- #site-description -->
</div><!-- .wrap -- >
</div><!-- #header -->
<div id="nav">
<div class="wrap">
<ul>
<li><a href="#" title="Page">Page</a></li>
<li><a href="#" title="Page">Page</a></li>
<li><a href="#" title="Page">Page</a></li>
<li><a href="#" title="Page">Page</a></li>
<li><a href="#" title="Page">Page</a></li>
</ul>
</div><!-- .wrap -->
</div><!-- #nav -->
What we’ve done above is add in our site’s title using an h1
and our navigation using a simple ul
function. Though our site’s title will often be replaced with a graphic logo of some sort, the true meaning behind the logo is the title of the website, and so should be treated as a topmost level heading.
Next, we’re going to add some default content to our main content area, the place within the div
with the ID
of “main”.
<div id="main">
<ul class="postlist">
<li class="post">
<h2><a href="#" title="Post">Post title</a></h2>
<p>Posted by Ryan Imel not long ago
<p>Lorem ipsum dolor sit amet, dolor sit amet.
</li><!-- .post -->
<li class="post">
<h2><a href="#" title="Post">Older post title</a></h2>
<p>Posted by Ryan Imel a bit longer ago
<p>Lorem ipsum dolor sit amet, dolor sit amet.
</li><!-- .post -->
</ul>
</div><!-- #main -->
I’m assuming at the time being that we’re dealing with a page holding a number of posts, rather than a single page template which would hold only one. Obviously we wouldn’t use an ul
to mark up a single post, that would be silly.
And finally, let’s add some default content to our sidebar div
s.
<div class="aside" id="primary">
<ul>
<li>
<h3>About this theme</h3>
<p>This theme is your own, and you can do with it what you want. You'll probably never see this anyway.</p>
</li>
<li>
<h3>Pages</h3>
<ul>
<li><a href="#" title="Page">Page</a></li>
<li><a href="#" title="Page">Page</a></li>
<li><a href="#" title="Page">Page</a></li>
<li><a href="#" title="Page">Page</a></li>
</ul>
</li>
</ul>
</div><!-- .aside #primary -->
<div class="aside" id="secondary">
<ul>
<li>
<h3>The second sidebar</h3>
<p>This theme is your own, and you can do with it what you want. You'll probably never see this anyway.</p>
</li>
<li>
<h3>Posts</h3>
<ul>
<li><a href="#" title="Post">Post</a></li>
<li><a href="#" title="Page">Post</a></li>
<li><a href="#" title="Page">Post</a></li>
<li><a href="#" title="Page">Post</a></li>
</ul>
</li>
</ul>
</div><!-- .aside #secondary -->
This might be a good time to mention thoughtful commenting. Notice that every major tag we close (and by major I mean anything with a class
or ID
attached to it) we include a comment that identifies what it closes. The more you do this, the happier you will make those attempting, later, to understand your code.
Odds are you’ll thank yourself when you’re looking at your work again, a year down the road.
Then there’s the footer, which we’ll include for the sake of posterity.
<div id="footer">
<div class="wrap">
<p>This current theme is built on <a href="https://wordpress.org" title="WordPress.org">WordPress.org</a> and this theme framework.</p>
</div><!-- .wrap -->
</div><!-- #footer -->
Once we have template tags and our theme’s name, we can include those things as well. Onward.
The most basic CSS
What will we get if we load up our HTML
in a browser, aside from a plain text snoozefest? Technically speaking, each of us will see something different. So we’ll start by adding in a pretty standard reset.css
file by using import
in our new stylesheet.
The reset.css
we add will look like this:
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 100%;
vertical-align: baseline;
background: transparent;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
/* remember to define focus styles! */
:focus {
outline: 0;
}
/* remember to highlight inserts somehow! */
ins {
text-decoration: none;
}
del {
text-decoration: line-through;
}
/* tables still need 'cellspacing="0"' in the markup */
table {
border-collapse: collapse;
border-spacing: 0;
}
And our style.css
file will look like this:
/* Brings in the reset stylesheet, by Eric Meyer */
@import url('reset.css');
And don’t forget you’ll need to add in the link
in the head
of the HTML
in order for any of this to work:
<link rel="stylesheet" href="style.css" type="text/css" media="screen" charset="utf-8">
Now your page should look even worse. But at least you’re sure to have a crappy look that’s consistent between browsers.
Testing various CSS
layouts
The real reason for filling in all of this fake content and having a simple layout, at this point, is specifically so that we can do some basic layout tests. We want to know whether this HTML
we’ve laid out is enough for the majority of layout styles out there.
In order to easily show the results of our CSS
here, I’ll add some color coded borders around the elements.
/* For testing purposes, color coded borders */
div#header, div#nav {
border: 3px solid #f00;
margin: 1.0em 0;
}
div#main {
border: 3px solid #0f0;
margin: 1.0em 0;
}
div.aside {
border: 3px solid #00f;
margin: 1.0em 0;
}
div#footer {
border: 3px solid #000;
margin: 1.0em 0;
}
div#wrapper {
margin: 0 2.5%;
width: 95%;
}
The 1 column layout
So let’s start with the CSS
we would use to achieve a simple one column layout.
/* A one column layout */
div.aside {
display: none;
}
Obviously this isn’t the ideal way to achieve it, since we wouldn’t want to include the sidebar content in the first place. Just hang in there.
A 2 column layout
Okay, that was exciting. Let’s try the two column, sidebar on the right layout now.
/* A two column, right sidebar, layout */
div#main {
float: left;
width: 70%;
}
div.aside {
clear: right;
float: right;
width: 25%;
}
div#footer {
clear: both;
}
By floating both sidebar div
s to the right, we create the illusion of only one sidebar. And of course the footer will clear our floats for us.
A 3 column layout
Now, can our structure stand up to a three column layout, with one sidebar on either side?
/* A three column, left and right sidebar, layout */
div#container {
position: relative;
}
div#main {
float: left;
left: 30%;
position: relative;
width: 40%;
}
div.aside {
width: 25%;
}
div#primary {
float: right;
}
div#secondary {
float: left;
margin-left: -40%;
}
div#footer {
clear: both;
}
Success! We seem to have an HTML
structure that is strong enough to move forward. Let’s do just that.
CSS
so our eyes stop bleeding
We don’t want to spend a lot of time on CSS
, specifically because this is a framework, not really the place for heavy styling. But let’s add in some basic styling so that we can look at this HTML
without a barf bag close by.
Using the right sidebar on a two column setup, we’ll use this very basic CSS
:
/* Basic styles */
body {
font-family: Cambria, Georgia, Times, 'Times New Roman', serif;
font-size: 65%;
}
div#wrapper {
font-size: 1.4em;
}
div#header {
float: left;
width: 50%;
}
div#nav {
float: right;
width: 50%;
}
h1 {
font-size: 2.0em;
}
h1 a {
color: #000;
}
h2 {
font-size: 1.6em;
}
h3 {
font-size: 1.4em;
}
p {
margin: 1.0em 0;
}
a {
color: #888;
text-decoration: none;
}
a:hover {
color: #000;
text-decoration: underline;
}
div#nav li {
float: left;
margin: 0 2.0em 0 0;
}
.post {
margin: 0 0 3.0em 0;
}
div.aside li ul li {
list-style-type: disc;
margin: 1.0em 0 1.0em 1.5em;
}
Ah, that’s a bit better, right?
Next time: assembling the theme files
Now that we have a foundation to work from, next time around we’ll be separating our basic HTML
into more practical atomic elements, as well as discussing not only the minimum requirements for a WordPress theme, but the best number of files for a WordPress theme framework.
Mike Smith
April 7, 2025Great series and good timing! I just started looking into frameworks, so this is helpful for me to understand what the hoopla is about. This post is the first one that I’m finding easy to follow, It’s the first theme development walk thru that keeps it simple without bombarding you with things that aren’t yet important.
I may change my tune once you get to the php parts – I stink at php, but have a feeling you’ll get me thru it – cheers.
Szabi - WPBay
April 7, 2025Thanks Mike, I’m glad you’re enjoying it so far! Follow this blog for more similar posts. 🙂