I’ve been meaning to write this one for a while. While every developer has their own workflow, I wanted to create a blog post explaining in reasonable detail what, how, and why I operate as far as workflow is concerned. I also wanted to include more in-depth technical information for any budding WordPress developers.


Design and Wireframing

I used to be a die hard fan of Sketch; opting to pay for it alongside my usual Creative Cloud subscription. That was, until I was introduced to Adobe XD by Sai Karlen. Hands down one of the best designers you’ll find in Brisbane.  Launching as Project Comet in early 2016, this little app does have a bit to catch up on, but does come with a few features that’ve convinced me to switch.

  1. It’s an Adobe product, and so it integrates with CC libraries
  2. Real-time collaboration. I can make comments, and change designs on the fly with other designers
  3. Share URLs meant I could do away with InVision

Web server

There’s no prizes for guessing that I’m a massive NGINX fanboy. As always, I recommend using my NGINX WordPress cookbook. I know there’s a few others out there, but I’ve been pretty happy with my setup. Just need to change the caching expiration for development when making CSS changes.

I have two servers hosted with Vultr named after the celestial bodies Jupiter, and Saturn. One is used for production projects, and one for staging projects (client-staging.cameron-morgan.com). I use Vagrant for local development, and then push to a branch within GitHub called ‘Staging.’ When I’m happy with the feature, I’ll push it through to the production server. That production server runs a similar configuration as to both my local, and staging servers just with more in depth performance tweaks.


Composer is not a particularly complex product. It’s just a package manager for PHP. I use Composer mostly for managing WordPress plugins. It is required for my theme framework TypeRocket, but I would have opted to use it regardless. Where Composer really shines is it allows you to automate a lot of the plugin installation rigmarole that comes from a new WordPress installation. It also ensures that if you’re working with a team of developers that you all are working with the same version.  Rather than having cross-version compatibility issues.

HTTP Cache (Production)

I use WP Super Cache for the HTTP cache in production. Amateur WordPress users are quick to say ‘Page caching is what makes your site load quick!’ when really, as you’d know dear reader… It’s much more complicated than that. Included in my NGINX Cookbook is configuration that will support the much more optimised ‘Expert’ mode of the plugin.

I’ve also used WP-Rocket, and am a massive fan of the tool. But I do always get a ‘Hmm, is this not overkill when WP Super Cache exists?’ thought in the back of the head. I no longer recommend W3 Super Cache, it’s more complex for most people, and really slow actionability on security issues.

Object Cache (Production)

This is a caching solution that I seldom see mentioned by the larger WordPress ‘how to make faster’ blogs. It’s a lot more technically involved than HTTP cache, but it can help speed up queries by fetching them from a cache, rather than pestering MariaDB every time for those results. After all, beneath everything that WordPress is it’s still a glorified database. I use Redis; the difference between Memcached and Redis these days is pretty much non-existent.


I use MariaDB, not MySQL.


Source control

I personally like using Git for source control. With the number of backwards, and forwards-ing I’ve experienced in agency life, I found using Git was the simplest way to just keep track of changes on a feature-by-feature level. I currently use GitHub at DSR Branding, but have been slowly moving things over to GitLab for my own personal projects. I don’t really have a preference here, both have really good UIs in their desktop apps. But GitLab’s deployment tools are a lot better than those offered by GitHub.



I deploy using a tool called DeployBot. It connects to my two servers using SFTP. I can see what code has been changed, by whom, and what files were modified. Unlike competitors such as Forge, it gives me the ability to still setup, and maintain NGINX, directory structures, and what not. I really like it.


Starter theme

I’ve tried a couple of starter themes, but my personal preference still remains HTML5Blank. It’s a great starting point, contains a few things to get me started. It’s also a heck of a lot leaner than the others.

The philosophy of starting with a starter theme rather than from scratch is that you’re getting a few tools to get started with. It already follows the coding standards recommended by WordPress. Despite this, there’s a few changes I made to this starter theme, mostly in the header.php file.

Personal modifications

Firstly, I change the opening HTML tag to be lang=”en-AU” rather than it’s dynamic counterpart. Coming from an SEO background, I’ve always needed granular control over that. I can use Hreflang for content if the site has multiple languages or geographic targeting. I also add the bog-standard humans.txt file, and accompanying tag + ASCII art in the header. I create my favicons using a website called ‘Real Favicon Generator’ and place them in the /assets/img/favicons directory. I’ll usually put any theme related assets in the assets directory, and use the Media Library purely for content. It’s less likely for brand assets to get deleted that way.

I usually disable WP-Emoji, and RSS feeds using a function in functions.php. Most people don’t need it. On most sites, I usually leave out any other SEO things in the header. Instead, I let Yoast SEOhandle those for me on a page-to-page basis. Finally, I replace the bog-standard Google Analytics, with ga-lite from Jehna.

I’m still a little bit uncertain about the need for Schema.org for most, so I’ve been slowly adding it to my starter-theme.


<!doctype html>
<html lang="en-AU" class="no-js">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title><?php wp_title(''); ?><?php if(wp_title('', false)) { echo ' :'; } ?> <?php bloginfo('name'); ?></title>

<!-- CSS -->
<link rel="stylesheet" type="text/css" href="<?php echo get_template_directory_uri(); ?>/assets/css/style.css">

<!-- Prefetch Content -->
<link rel='dns-prefetch' href='//cdn.jsdelivr.net' />
<link rel='dns-prefetch' href='//fonts.googleapis.com' />
<link rel='dns-prefetch' href='//s.w.org' />

<!-- Favicons -->
<link rel="apple-touch-icon" sizes="180x180" href="<?php echo get_template_directory_uri(); ?>/img/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="<?php echo get_template_directory_uri(); ?>/img/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="<?php echo get_template_directory_uri(); ?>/img/favicon/favicon-16x16.png">
<link rel="manifest" href="<?php echo get_template_directory_uri(); ?>/img/favicon/manifest.json">
<link rel="mask-icon" href="<?php echo get_template_directory_uri(); ?>/img/favicon/safari-pinned-tab.svg" color="#0b4978">
<link rel="shortcut icon" href="<?php echo get_template_directory_uri(); ?>/img/favicon/favicon.ico">
<meta name="msapplication-config" content="<?php echo get_template_directory_uri(); ?>/img/favicon/browserconfig.xml">
<meta name="theme-color" content="#ffffff">

<!-- Developed by Cameron Morgan for ### -->
<link type="text/plain" rel="author" href="<?php echo get_template_directory_uri(); ?>/humans.txt" />

<?php wp_head(); ?>
// conditionizr: Configure Environment Tests
assets: '<?php echo get_template_directory_uri(); ?>/assets/js/',
tests: {}

<body <?php body_class(); ?> itemscope itemtype="https://schema.org/WebPage">

<!-- wrapper -->
<div class="wrapper">

<!-- header -->
<header class="header" role="banner" itemscope itemtype="https://schema.org/WPHeader">
<!-- logo -->
<div class="logo">
<a href="<?php echo home_url(); ?>">
<img src="<?php echo get_template_directory_uri(); ?>/img/logo.svg" alt="Client Name" class="logo-img">
<!-- /logo -->

<!-- nav -->
<nav class="nav" role="navigation" itemscope itemtype="https://schema.org/SiteNavigationElement">
<?php html5blank_nav(); ?>
<!-- /nav -->

<!-- /header -->


<!-- footer -->
<footer class="footer" role="contentinfo" itemscope itemtype="https://schema.org/WPFooter">

<!-- copyright -->
<p class="copyright">
&copy; <?php echo date('Y'); ?> Copyright <?php bloginfo('name'); ?>.
<!-- /copyright -->

<!-- /footer -->

<!-- /wrapper -->

<?php wp_footer(); ?>

<!-- Tracking Codes -->
<!-- ga-lite by Jehna https://github.com/jehna/ga-lite -->
})(window,document,"galite","script","https://cdn.jsdelivr.net/npm/[email protected]/dist/ga-lite.min.js");
galite('create', 'UA-XXXXXXXX-X', 'auto');
galite('send', 'pageview');

<!-- External Resources -->
<link href="//fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">


Theme framework

I use TypeRocket. New to the framework game, TypeRocket has quite a few features that I never quite got in my old Framework, Unsyon. The main three reasons why I switched across was:

  1. It provided a page builder that had flexibility, but still retained development control.
  2. Custom post types, and fields were a five line affair.
  3. Code was just so much neater.

Installing TypeRocket is easy enough with installation managed through Composer. Once installed, all you have to do is add a single line of code to the functions.php, and you’re up and running (I’ve found on Apache, I’ve had to flush rewrite rules).


Bundled plugins

It’s safe to say I’m in the ‘avoid plugins’ camp. In my freelancing career, it was not unheard of for me to come across websites with 40-50 poorly written plugins with the brief of ‘make fast pls.’ I stick to the following out of the box:

My philosophy is to include display features in the theme, and only use a custom plugin for functionality. Say for example, I had a ’10 colours’ display in my theme, and used a tick box in a product meta to decide whether or not it showed on the front end. I’d built that into my theme. But wouldn’t build in something that issued PDF invoices.


I really like Brackets. I used to use Sublime, but this Adobe project converted me. The simple, yet beautiful layout of this editor made web design visual for me again. It’s quick to get started, features a lot of custom plugins, and best of all is written completely in JS. It features it’s own Live Preview feature which is a blessing for CSS, and HTML work. Like all good editors, it comes with code completion, and syntax highlighting. I changed the typography from it’s default ‘SourceCodePro-Medium’, and now use David Jonathan Ross’ wonderful Input. The Watson theme is my preferred.


I use GSuite for client emails, MailGun for transactional sends, and my own EDM based on Campaign Monitor for campaign emails. Using the MailGun for WordPress plugin, I can utilise MailGun’s HTTP API rather than SMTP through plugins such as WP Mail SMTP. All about that speed.

Project Management

I use Asana. Each project is setup with a new ‘Project’ inside of Asana where I map out the project based on the deadlines I’ve outlined in my proposal. I then use the Git commit and leave a comment on each major milestone so I can see myself which commits aligned to what milestone and/or feature. I then have a Gravity Form setup where clients can report bugs related to their site to me. These bugs are created as Asana tasks thanks to this plugin. Very neat.


Hopefully that’s helped a few young ‘Pressing developers into how to work with WordPress. If you’ve got any questions, or cool things you do yourself that you think I should check out leave a comment below and I’ll check it out! 🙂