As a web developer, I’ve built many custom themes for WordPress over the years. I’ve also done sporadic work on, debugged, optimized, and otherwise tinkered with countless other WordPress installs.

Having spent so much time learning the in’s and out’s of WordPress, I decided to put together a tutorial article that breaks down my typical “barebones” environment and approach to custom WordPress theme development.

One common misconception that many web designers have when first getting started with WordPress is that using a drag-and-drop editor plugin will somehow make things easier for them. I’m hoping to dispel that notion.

The template structure I’ll go into not only expands on the basic WordPress template structure but also includes a number of organizational methods that will make your code more scalable and flexible.

This tutorial is meant for designers and developers who are familiar with PHP, HTML, CSS, and Javascript and are just becoming familiar with WordPress.

This “barebones template” should be a starting point for you, feel free to expand on it and modify it as you see fit.

TLDR — here’s the Github repository: https://github.com/adamhodson/wp_barebones

Template Structure

Like with any website development project, code efficiency and code organization are extremely important. The standard WordPress template structure is simple and elegant. It includes a few ‘must have’ files like style.css, single.php, page.php, functions.php, and so-on.

WordPress allows you to easily override base template files using simple naming conventions. By using post type names, tag names, category names and more you can easily create custom page layouts without the need for setting up complex page routing or modifying additional layout files.

Single Properties Template

For example, let’s say you have a post type called “Services” with a slug of “services”. To create a custom single post template for the post type, you would just need to duplicate the single.php file and rename it to “single-services.php”. You can now modify this file to utilize an entirely different layout than the standard single post.

You can also create a number of custom page templates, template parts, and other template utility features. The standard WordPress template structure looks something like this:

When I develop a custom WordPress template I make a few modifications to the general structure to improve the overall organization. To start with a shot of the finished product first, a typical project template might look like this:

Page Templates Directory

My first modification to the standard approach is a ‘page-templates’ directory which, as you guessed it, will hold the custom page templates for the theme. I like to keep these within their own directory for two reasons. One, so that template files are easier to find. Two, so the root directory of the template has fewer ‘stray files’ floating around.

Page Templates & Page Partials Directories

Partials Directory

I also include a ‘partials’ directory in the root of my template and will use this to store my template parts. Examples of template parts might include things like a “global contact form”, a global “testimonials block”, or a “FAQs block”. Template parts are intended to be included in one or multiple WordPress templates or pages.

Template parts serve a few purposes. One, they cut down on the size of each individual template file. This makes your code cleaner and easier to manage. Two, it is more efficient to include one template part in multiple templates as opposed to copying and pasting the same block of code into each template. When you make changes to your template part, the changes are immediately reflected in all of your different templates and pages.

Lib or Library Directory

WordPress includes a “functions.php” file within its template structure that allows you to add your own custom theme functionality and hook into core WordPress functionality within your theme.

Instead of having one extremely bloated functions.php file, I’ve found it much more convenient to extend the file instead to require more clearly segmented function files.

To be clear, this is pretty much the same thing as the ‘inc’ directory in the “twentynineteen” theme.

To start, create a ‘lib’ directory in the root of your template and place a blank file named ‘functions.php’ in that directory. Then, within your main functions.php file place the code ‘require_once(‘lib/functions.php’)’.

Now, let’s say you plan to create 5 different custom post types for your WordPress theme. Instead of including all of that code within the main functions.php file, create a new file called ‘cpt.php’ within your ‘lib’ directory. Now open your blank ‘lib/functions.php’ and at the top of the file type ‘require_once(‘cpt.php’)’.

You can now keep all of the functionality required to create and manage your various custom post types within one easy-to-manage file. You can use this same logic for managing custom navigation functionality, custom user functionality, custom login functionality, and so on.

This approach not only makes it easier to organize your code and visualize your files, but it also makes debugging and refactoring code easier, especially for novice developers.

I do like to keep some of the more global WordPress theme functionality in the core functions.php file.

Examples of this include the ‘wp_enqueue_script()’ functions, any custom image sizes that I define for the theme, some global helper functions and other things of that nature.

Ultimately, use these files in whatever way works best for you.

Assets Directory

Similar to your ‘functions.php’ file, WordPress includes a core CSS file, “style.css”. As you can probably tell, I’m a big believer in keeping code organized and easy to read, so I like to move all of my files responsible for styling the website into a directory called ‘assets’.

Full Assets Directory

I break down my ‘assets’ directory into folders called ‘css’, ‘js’, ‘sass’, ‘images’, ‘vendors’ and when necessary things like ‘icons’ or ‘fonts’.

I then use this directory to not only store my images, CSS, and JS, but I also use it to store and compile my SCSS and JS files into compressed and minified output. To do this I use Gulp (which I will explain in detail later in the article).

I also like to further break down my SASS directory into individual directories like:

- “base” where I keep all of my base styles like fonts, colors, and grid settings, helper classes and more.

- “components” where I keep components styles for things like the header, i.e. ‘header.scss’ or ‘footer.scss’

- “pages” where I can keep page specific styles like ‘home.scss’ for easy organization

2. Make Use of Template Parts

When it comes to keeping your template code clean and easy to read, template parts will be one of your most powerful tools. In short, a template part allows you to store chunks of code within individual files. These individual files can then be included within any template file using a core WordPress function, ‘get_template_part()’.

Template Partials Directory Example

Template parts are primarily used to keep the template files smaller and stop developers from having to repeat themselves.

For example, you may have a “call to action block” or a “testimonials block” that you want to use on several pages of your site. Instead of copying and pasting an additional 50 lines of code into each template file, you can include a template part with only one line of code.

Template Partials in Use

This will not only keep your template code easy to read and edit, but it will also save you on time when making changes to the component code itself.

Instead of having to go back and edit each individual template to apply a change, you only need to make the change one time.

3. Load JS & CSS Through WordPress

Whenever possible load your CSS and Javascript files through your ‘functions.php’ file. It is not considered to be best practice to directly include these assets in the header.php or footer.php files.

Poorly placed or poorly optimized CSS or Javascript files are two of the more common causes of slow website load times and page speed.

By loading these files in the functions.php file, you can control the order they load, the pages that each file load on, and more. This allows you to easily keep each page as lightweight as possible.

This also allows you to utilize any number of WordPress plugins for caching, asset compression, asset minification and more.

While there are a number of plugins available for these purposes, two of the plugins I have used are Fast Velocity Minify and WP Fastest Cache.

WP Fastest Cache Plugin on Wordpress.org

Loading these files through your functions file also allows you to conditionally load files on pages. Conditionally loading assets allows you to keep pages as slim as possible, which also helps with page speed.

For example, let’s say you have to include a Google Maps JS library, a Google Map Plugin Library, and a special Maps Library to render a custom map overlay. These 3 additional Javascript files will add quite a bit of size to a page and slow down your website load time.

If you only needed to use these files to render a map of your location on the contact page, then there is really no reason to load these heavy Javascript files on any other page.

Using your functions.php file, you can identify the page or pages you’d like to load your assets on, and wrap those items in a conditional statement. Below is an example of a number of additional Javascript files being loaded only for “dashboard” pages on a website.

Conditionally Loading Additional JS Files For A “Dashboard” View

You could use the same conditional logic in a header.php or footer.php file, but you shouldn’t.

For one, the functions.php file will be run by WordPress before the page is rendered by the browser. This means that all of the conditional “decision making” will be done on the server and the browser will just need to display the final output.

If you place that logic in the template, you will essentially ask the browser to stop rendering the page momentarily while the additional logic is run, which will have a bigger impact on your load times and user experience. (It also will just increase the size of your template files and make your code more difficult to read.)

I also suggest compressing and minifying your template’s core CSS and Javascript files during development using Gulp. This will further reduce the number of files that you will need to include in your functions.php file.

4. Use Gulp For CSS & JS

When it comes to handling SASS pre-processing, minifying and combining CSS and Javascript, image optimization, and other optimization tasks, my build system of choice is Gulp.

GulpJS Home Page

You will need a few basic things to run Gulp from your local development environment.

First, install Node if you haven’t already. Here is an easy to follow tutorial on how to do that: https://blog.teamtreehouse.com/install-node-js-npm-mac.

In addition to Node, you will also need to have a very basic understanding of how to use the command line or terminal.

NPM — Node Package Manager

Once you have Node installed, you will be able to use Javascript packages for development. NPM, or the Node package manager, is a website that developers publish code and development utilities for other developers to use in their projects.

NPM is also where you would get Gulp and the other plugins we’ll be using. To start, you will want to create a new ‘package.json’ file for your project. This file will include all of the different dependencies you’ll be using.

I’ve included one for you in my barebones theme, but you can also search Google for other Gulp package.json files. There are also great resources on Github like this one: https://github.com/alferov/awesome-gulp.

In addition to the ‘package.json’ file, you will also need a gulp file, which will dictate how the Gulp plugins are used.

If you’re unfamiliar with the concept of Node packages and a package.json file, you can read a bit more about that here before moving on https://semaphoreci.com/community/tutorials/getting-started-with-gulp-js

Once you’ve placed the ‘package.json’ file with your Gulp dependencies and your Gulp file in the root of your WordPress template, open the terminal on your computer and change to your template directory.

‘cd /your_dir’

Once you’re in the template directory, just run ‘npm install’ to install all of your Gulp dependencies.

Gulp Running In The Terminal

Once everything is installed, you will then be able to run commands from your command like ‘gulp’, ’gulp dev’, or ‘gulp watch’ (all depending on your Gulp file configuration). These commands will in one way or another process your CSS, JS and image files for you either on demand or after certain events like changes to CSS files.

You will typically keep all of your SASS files within a ‘/sass/‘ directory and have your processed CSS files write to a separate directory, i.e ‘/css/‘.

It’s important that you don’t make changes directly to the files within the ‘/css/‘ directory as every time Gulp runs, it will remove the files from that directory and create a new version of your compiled CSS. This means any direct changes you make would be lost.

If you’re still not quite sure what Gulp is or why it is so important to use in your development workflow, here’s another article that breaks it down a bit more for you: http://brandonclapp.com/what-is-gulp-js-and-why-use-it/

5. Utility Plugins

While many developers will hear the word ‘plugin’ and cringe, there are quite a few plugins that can be very useful to developers and won’t really have an impact on things like website speed, user experience or usability.

I refer to these plugins as “utility plugins”.

Utility plugins will typically extend the core functionality of WordPress to make some aspect of the website more usable for the developer, the website owner, the end-user or all of the above.

While there are several other plugins that would definitely qualify as “utility plugins” out there, I tried to keep the list as sparse as possible.

Advanced Custom Fields

The first utility plugin on the list is Advanced Custom Fields. This plugin can be one of the most powerful tools in a WordPress developers tool belt. Advanced Custom Fields, or ACF for short, allows for developers to create a wide variety of custom fields and inputs and then attach these inputs to any page, post type, user, category or other WordPress data type.

Advanced Custom Fields Home

Examples of custom fields would be basic text inputs, text areas, images, repeater fields and more.

For example, if you wanted to store additional basic text page content like “Subheadline”, “Section Two Headline” or “Section Two Content”, you could use input fields like text inputs, text areas or WYSIWYG editors.

These fields would then appear on the Admin edit view for the page or post you assign them to.

Create A New Advanced Custom Field

Now, any admin user or user with page/post edit capabilities can control each field individually instead of having to use complicated drag-and-drop and visual editors.

The user can directly edit the data in each individual field which will correspond to specific text fields in the template.

Edit Fields In Posts

In my experience, the majority of clients end up preferring simplified input based page management over page builder tools.

Advanced Custom Fields also makes it very easy to integrate the custom field data directly into your template.

For example, let’s say you were to include the custom field on your ‘About ‘ page and the ‘About’ page uses the template-about.php template. In order to integrate the custom field into your template, you would simply replace your static text content with ‘echo get_field(‘FIELD_NAME’)’.

Integrate Custom Field Into Template

This allows the end user the ability to quickly and easily add and edit pages and posts on their site as needed without the worry of compromising the site design or layout. I’ve found that the vast majority of my clients prefer to edit their websites this way as opposed to a ‘drag and drop’ editor.

Gravity Forms

Another plugin that makes developing custom WordPress templates a lot more scalable for you and your clients is the plugin “Gravity Forms”.

Gravity Forms allows the WordPress admin to easily create fully custom frontend forms that can then be embedded directly into template code or included into pages or posts via shortcodes.

Gravity Forms can be used to create frontend forms of all sorts like contact forms, quote forms, meeting request forms, address forms, multi-page questionnaires, and so much more. If you can think of a need to capture user input on the frontend of your website, Gravity Forms can probably handle it.

Gravity Forms also offers a number of native integrations that really improve a website business workflow. For example, you can sync specific Gravity Forms with MailChimp email lists or with your Agile CRM data. This means that as a theme developer you can

Quickly create completely custom forms with form validation and spam bot protection that also sync up with the website owners existing processes. Give the website owner the ability to quickly and easily create completely custom forms with form validation and spam bot protection that also sync up with the website owners existing processes.

I’ve found that backend usability is just as important as front-end user experience to a vast majority of my WordPress website clients.

Gravity Forms is a plugin that gives clients a great deal of flexibility to quickly create new forms and capture flexible user data as they need to.

Gravity Forms also integrates with a number of payment processors so that you and your clients can build custom payment forms. For example, let’s say you plan to hold an event and want to sell tickets, t-shirts, raffle tickets, and a combined package.

You can quickly create a form that allows the user to choose the items they’d like, input a credit card, and securely check out on your website.

The form can also utilize conditional fields when offering product or services to the users.

For example, let’s say the user selects that they would like a t-shirt with their order. You can set up a conditional field that asks the user if they’d like to buy a second shirt for half price only if they select the first shirt.

Gravity Forms also has an easy to use API. The API lets developers create forms on the backend that can integrate with forms created for custom experiences, third-party apps, and third-party websites.

As an example, let’s say the developer builds an interactive Javascript experience that gathers user data along the way. Each time the user moves to the next step, the data can then be compiled to a Javascript object.

Once the user completes the process, that object can then be sent to the Gravity Forms API and submitted as a new entry to the form on your website.

The admin can then view, edit, manage and export all of the form submissions in the existing Gravity Forms interface.

The data will also be able to hook into the existing Gravity Forms integrations like MailChimp. Best of all, you can also easily utilize all of the core form notification functionality to send alerts based on the form events.

Gravity Forms is an excellent plugin that makes an otherwise time-consuming aspect of website creation easier for WordPress developers and WordPress website owners alike. Try it out using their demo version, but if you like it and intend to use it going forward, I suggest going for the developer license. You won’t regret it.

3. Yoast SEO

Yoast SEO is one of the more popular SEO plugins for WordPress. It’s free to use and hits almost all of your basic on-page optimization needs.

This plugin is not one that is “plug-and-play” so to speak. You will still need to understand the general concepts behind on-page optimization and you’re still going to have to write a ton of content. But this plugin will help you make sure your website has the best possible chance to be found for their target keywords on Google.

Here are a few of the features I’ve come to really appreciate about Yoast SEO.

Meta Descriptions

Meta descriptions are very important when it comes to on-page optimization. They shouldn’t be empty, they should be concise and organic, and they definitely shouldn’t be duplicated.

WordPress doesn’t make the meta description a default setting that a user can edit, which presents a unique SEO challenge.

Yoast SEO adds a custom meta field input on to every page and post. The plugin also lets you set a fallback meta description for your various post types, categories, archives, and pages.

Bulk Meta Data Optimization

Yoast SEO makes it very fast and easy to update meta titles and meta descriptions for all of your pages and posts.

Normally, you would need to go into each post or page individually, add or edit the metadata, save and then continue on to the next. This plugin gives you an easy to use bulk interface that allows you to edit multiple pages all at once.

You can start by filtering down by page, post, post type or some other filter option. Then decide whether you want update meta titles or meta descriptions.

You will now be able to update the metadata in batches of 10, 20 or 30 posts at a time to quickly get through your on-page optimization.

Focus Keyword Setting

Another great feature of Yoast SEO is the ability to set a focus keyword on your pages and posts.

Any on-page optimization efforts should be focused on targeting a keyword or group of keywords. This setting allows you to let the plugin know what that keyword is for each specific page.

Once you’ve entered your text content into the page or post, the plugin then runs a series of checks against the content for your focus keyword. It measures things like keyword density, readability, text length, image usage, linking strategy and much more.

While there are many more factors that can go into really engineering content for performance in search engines, the content checks that Yoast performs are an excellent starting point for anyone interested in creating well-optimized articles and pages.

WP Fastest Cache

WP Fastest Cache is another plugin that I’ve used on a large number of WordPress websites for website page speed improvements.

Normally when WordPress renders a page in a user’s browser, it uses PHP to make a request to a MySQL database and return some data that is then rendered in the browser. All of this amounts to work that the server needs to do in order to render the page.

The more requests that your page needs to make, the more slowly it will load.

This also means that the more people you have on your website, the more requests there will be to the database, increasing your server usage.

In very simple terms, when WordPress renders your website for the first time, WP Fastest Cache creates and saves a static version of the dynamic output.

Now when any users return or new users come to your website they will be served the “cached” static version of the website that does not require all of the database requests.

Whenever the website owner or admin makes changes to pages or posts, they would then just need to clear the website cache and the changes will then render on the frontend, starting the caching process starts over.

WP Fastest Cache also has a number of other performance-enhancing features like enable Gzip compression, JS and CSS combination, asset minification, stripping away things like emojis and much more.

WP Fastest Cache also has a premium version that allows you to optimize and clean up your database, defer Javascript files to load in the footer, and a number of other really useful website speed enhancements. This is another plugin that is always worth the investment.

https://www.wpfastestcache.com/

Sucuri Security

Let’s be honest, WordPress is not the most secure of content management systems. As a result, there have been several really great plugins created that can help to lock down and harden any WordPress install. Of these plugins, my typical choice is Sucuri.

Sucuri Website Home Page

Sucuri offers a number of security configuration and hardening options, as well as a number of admin notifications that will alert you to all sorts of events. In addition, the plugin is constantly watching for malware, attempted intrusions, file integrity and much more.

The Sucuri team is also constantly monitoring a number of blacklists for malware. By synchronizing with these lists the plugin tells you whether any of them are negatively flagging your website after each scan.

I could go on for days about all of the great security features this plugin provides, but if there ever was a plugin that you should just install first and ask questions later, this would be it. It goes to work the moment you activate it, and should immediately give any WordPress website owner an improved peace of mind when it comes to security.

Easy WP SMTP

The last plugin on my list is Easy WP SMTP. I like to include this plugin with just about every WordPress website I build due to how finicky the internal ‘wp_mail()’ functionality can be when it comes to spam filters.

I’ve found that one way to ensure that emails are sent and get where they need to go just about every time is to use Easy WP SMTP. This plugin lets you connect to any SMTP server and send your emails directly through it.

You can use Gmail credentials or other free email services that provide SMTP services, however, I always suggest just using the SMTP credentials for the server your website is hosted on if possible.

The plugin is easy to configure and test, and most shared and commercial hosting providers will give plenty of documentation and support on how to make an SMTP connection. Here are links to documentation for a few of the more popular hosting providers for clarity.

GoDaddy, Siteground, Nexcess, HostGator.

6. Using A CDN

So now you have a website that’s just about ready to launch and your primary focus is getting the website load times as low as possible.

When it comes to page speed, one of the biggest concerns on any website will be the image assets, video assets, CSS files, and Javascript files — also known as static assets.

In a typical website hosting situation, the website is hosted on a single server in a single location. This server is responsible for serving the website and it’s assets to any user who visits the website URL, regardless of the location.

So why is this a problem?

Even though we’re only transferring data, physical distance still comes in to play. It will simply take a longer amount of time to send the image data from Virginia to Spain than it would from Virginia to New York. This time would likely be calculated in fractions of a second, however, there is still a difference, especially when you start accounting for tens of thousands of website visitors.

To make the delivery of these assets more efficient, the CDN, or Content Delivery Network, was created. So how does a CDN work?

First, a website owner connects its website and domain with the CDN. Depending on the CDN service, for example, Cloudflare, this will typically involve modifying some DNS records and syncing your website data to the CDN.

CDN Diagram from Cloudflare

Once the website has connected with the CDN and all of the static files have synced, you will then need to modify your website so that it no longer serves these static files from your server, but from the CDN.

With Wordpress, most CDN providers offer some sort of plugin or direct connection which makes setting up a CDN easy. If your CDN provider does not offer a plugin, there are a number of free plugins available that will work well for this, for example, Wordpress CDN Enabler.

Cloudflare Website Home Page

Once your assets are synced with the CDN and your site is configured to serve assets from the CDN, you should start to see all of your static assets on your website being served from the CDN URL.

CDN Diagram from Cloudflare

If you’re not sure if they are being served from the CDN, you can use your browser’s code inspector to see where the files are being loaded from. If you see that images are loading from a third-party domain, for example, “https://121-cloudflare.com/imagename.jpg", you know that your CDN is working.

Now when a user accesses your website from Virginia, the assets will be served from the CDN node that is closest to Virginia and when a user accesses your website from Spain, the assets will be served from a node that is closed to Spain.

This improved asset delivery not only makes it more efficient to deliver assets around the world, but it also takes a huge amount of strain off of your server. This means that you will not only be improving page speed by delivering assets more quickly, but you’re also allowing your server to respond to local requests more quickly, making your page load even faster.

There are a number of great CDN services available right now, so when it comes to picking the right one, it’s hard to make a bad choice. Here are a few great CDN options to get you started:

7. Utilizing Github for Version Control & Deployment

Up until this point we’ve covered just about everything you’ll need to know to get you on your way to developing a custom Wordpress theme. The last piece I’ll be covering will be how you can use Github for both version control and deployment to your development and live servers.

Github Home Page

To start, you will need to sign up for a Github account. If you have never used Github before, it would also be good to watch a few videos on how to use Git. I will provide some basic commands that you can use below, but it’s always a good idea to understand what you’re doing, not just how you should do it.

Once you’ve created your account, you’ll want to create a new repository, or “repo”, for your project. Once you’ve done that, you can then open up your terminal.

WP Barebones Repository

Inside of the terminal, change into the directory that your project is in, for example:

‘cd /project_name’

Once inside the folder run the command ‘git init’ to create a new git repository.

‘git init’

Now add a file or files from your project to the repository using the ‘git add’ command:

‘git add Readme.md’

If you’d prefer to add all of the files within your project to the repository at once you can by running the below in the terminal instead:

‘git add -A’

You are now ready to make your first commit to the repository. Run the command

‘ git commit -m “type a message about the commit” ’

Make sure the message you type in is descriptive so that if you need to go back to find a commit it will be easy to do.

Now add the remote with the command “git remote add origin https://github.com/username/reponame.git"

This will allow you to push code from your local repository to the remote repository you’ve created on Github.

Now push your new commit to the master branch of your Github repo using the command “git push -u origin master”. If you were working on your dev branch instead, you would use the command “git push -u origin dev”.

Moving forward, whenever you are ready to commit new changes to your code, you would run the following commands.

’git status’ — this will show you all of the files that have been modified and can be committed as well as any new files that you will need to add to the repo. ‘git add -A’ — if you have several new files to commit, this will let you add all of them at once. ‘git add filename.php’ — This will let you add one filename to your commit. ‘git commit -m “commit message” -a’ — If you do not need to add new files to your commit, you can add an ‘-a’ flag to the end of your commit to add all of the files you’ve changed to your commit. ‘git push’ — This will push all of the changes in your commit to your repository.

Now that you are able to push the changes you make in your local environment to a Github repository you can set up a deployment workflow.

Configure Deployment Workflow

While you could configure a deployment workflow from Github to your server without the need for paid 3rd party tools, that whole process really deserves its own post. For the purpose of this post, I’ll just suggest that you use DeployHQ.

Deploy HQ Home Page

Once you signup for DeployHQ you will then be able to connect your Github repository and it’s different branches to various servers.

This way, once you push changes to a dev branch, it will update the code on your dev server. Or if you merge code from your dev branch to your master branch, it can then push those changes to your live server.

Deployment workflows like this simplify the process of pushing your changes from local to production and give you the ability to migrate changes in a safer, more secure way.

Getting Started With The WP Barebones Structure

If you’d like to build a new WordPress theme using this barebones structure, I’ve put everything you’ll need to get started together in this Github repository: https://github.com/adamhodson/wp_barebones

Start by cloning the repository on to your local machine, renaming the main sass file and js file, and updating the gulp file for the new file names.

Once you’ve done all of that, just run ‘npm install’ to install the gulp packages and gulp or gulp dev to start gulp.

Depending on the version of Node you’re running you may need to update packages or replace packages, but the package here should work fine with Node 6 to Node 9.

Make sure to update any of the plugins you use from the barebones theme as they are all updated regularly and at different intervals.

Keep in mind, this is a barebones structure — expand on it, change it, modify it and make it your own. Good luck and happy coding!