Local WordPress Development with Local
I know my way around computers, I think that’s a fair statement, my machine has Virtual Machines and docker instances running. I’m quite happy spinning up a vagrant box for doing local development and I work for a hosting company so when it comes to spinning up areas to experiment with I have that covered. For my personal site, I use a vagrant install with a duplicate copy of the 34SP.com Managed WordPress Hosting containers. I use the same vagrant template when testing and experimenting with new features for the 34SP.com Hosting Platform.
I am a strong believer that your testing environment should be as close in terms of setup as your live environment. That said there are always differences, even two sites on the same container can have quirky differences. While a strong believer, I have been mellowing that thought, and if you are not running weird modules or unusual setups, differences will not affect running code. Ask me 5 years ago should you use XAMPP or MAMP and I would have told you “no”, now I say use what works for you, just be aware the results might be different.
So back in March/April I was helping to debug a problem where something wasn’t running correctly on our hosting but was in the client’s local environment. He was using Local Lightning and having exhausted most routes I decided to download Local and see if I could see what they were doing differently to us.
I won’t lie, it is very pretty. I was quite taken but boy those first few steps were frustrating. However, having solved the issue I thought it might be interesting to see if I could run my local development with Local. It’s been an interesting journey, one where I have learnt a lot about Electron apps along the way.
Local Lightning Review
Let’s start with a mini-review. I have been using Local Lightning on MacOS. I looked at their previous version, which used Docker to containerise, and it was pretty but you could tell the developers had been on a learning exercise with Docker. Lighting, their codename for their latest version, runs natively. They have done away with containers and generally this is a positive thing.
Local sites are managed through the Local App which is an Electron App. The Local team have made the choice to allow addons (more on this later) meaning it’s quite hackable. The App is pretty; it’s clear a design team has taken several passes.
Unfortunately, so have a marketing team, and it’s safe to say if you are not a Flywheel or WPEngine (Flywheel parent company) customer they will not stop hounding you till you are. Also several interesting features are very tightly locked down to just their services, this includes the ability to deploy to a remote host. This makes sense from a marketing perspective, and for a free product adverts are the cost. I notice they have a paid product. I imagine if I wasn’t a Flywheel/WPEngine customer on a paid service I might be a bit more upset.
They do say if you want to use another host to let them know. I would love this very vague promise backed up with API documentation for integrating other hosts and services.
Speaking of addons, most don’t work with Lightning. I’m sure they used to work great with the old versions, and you can still build addons, but they are focused on the old Docker instances. This, I’m sure, will improve.
Generally, for all the polish, you can tell in places this is still a beta of their new version, and every so often you will find old settings for the Docker setup.
Also something I only noticed while doing this review and going to tidy up for some screenshots, there doesn’t appear to be a way to delete sites?
So it’s a very pretty but not quite yet out of beta product.
Would I recommend it? I don’t know. If you are a Flywheel or WPEngine customer, yes use this. It’s been set up with you in mind. This feels like a no brainer.
If you are not using those companies, this is a solid(ish) development environment that is fast and pretty and that’s being actively worked on. I certainly would recommend it for the average user over something like VVV (which I think is a great project, but total overkill for the vast majority of people). If you have the technical skills to be running your own Virtual Machines and feel confident spinning up and playing with nginx/php this app will annoy you, and you will spend a lot of time tuting.
So I decided to move my local development of timnash.co.uk to Local at least temporarily. Let’s commence tuting.
Setting up a real local development environment with Local
So TimNash.co.uk is hardly a complicated site, but it is set up slightly differently. Its core setup matches the 34SP.com Managed WordPress Hosting setups so the WordPress core files are in a folder called wp/. I also use composer outside of the public_html
root for some files.
None of this is “unusual” so I fire up Local, press the big green button with plus icon, add my address, confirm I want PHP 7.3.5, there is no option for MariaDB which is a shame but I select MySQL and the HTTP server is Nginx (when I set up that was the only option, they have now also added Apache as an option).
A plain WordPress site is there. Excellent! So I navigate to the site in iTerm and just to confirm everything, run wp plugin list and it fails, WP-CLI can’t see the database. We are two minutes in and already I’m tuting.
Getting WP-CLI to work with Local Lightning
After a few minutes of head-scratching, the reason for why it wasn’t working becomes obvious. To keep things isolated, Local is creating separate Database instances on different sockets (they show this on the database tab) to simplify the experience and to avoid making changes to the default wp-config.php they set the socket in the PHP-FPM configs (this is actually quite smart). Unfortunately, WP-CLI runs PHP CLI and doesn’t use the PHP-FPM instance so doesn’t know the location of the socket.
The solution was to do what the devs were trying not to do, and in my wp-config.php I added:
if ( defined( 'WP_CLI' ) && WP_CLI ) {
ini_set('mysqli.default_socket', '/{SOCKETPATH}/mysqld.sock');
}
Where the SOCKETPATH is the path defined on the database tab in the Local app.
Side Note – a bit later on I wanted to get Tinkerwell working locally as well, so I actually changed it to be far more permissive with:
if ( null !== ini_get('mysqli.default_socket' ) {
ini_set('mysqli.default_socket', '/{SOCKETPATH}/mysqld.sock');
}
This allowed both WP-CLI and Tinkerwell to work.
UPDATE: WP-CLI working in Local (sort of)
After I posted this Clay Griffiths from the Local team got in touch on Twitter to say WP-CLI does work if you go to sites -> right click -> Open Site Shell.
I was aware of the menu item and had even pressed it to be presented with an error about shell variables and an issue referencing docker so had assumed it was broken. Looking at the error properly it is related to ZSH and conflicts with my local setup. So we can chalk WP-CLI not working to be down to me.
Is this solution practical, not really if you are the sort of person who uses the terminal, you are not going to want to go into Local to spin up a new shell with different variables, it also prevents tools like Tinkerwell working.
However WP-CLI works using the steps Clay outlined
Changing path setup
Next step was to change my default paths, I moved everything barring wp-content folder into the wp/ folder then add a index.php file that just had
<?php
/**
* Front to the WordPress application. This file doesn't do anything, but loads
* wp-blog-header.php which does and tells WordPress to load the theme.
*
* @package WordPress
*/
/**
* Tells WordPress to load the WordPress theme and output it.
*
* @var bool
*/
define('WP_USE_THEMES', true);
/** Loads the WordPress Environment and Template */
require('./wp/wp-blog-header.php');
A quick check and everything is now working, except that Local App no longer knows my WordPress version. This is a minor niggle and one at some point I intend to see if I can fix, I really don’t want to symlink a version file though so might look to see if I can build an addon to fix this.
Update: Fiddling with configs
Just before going live with this post, I gave in to the nag about updating and updated. I had made some custom Nginx updates, nothing to make Local work, simply to proxy images from my live site to save me having to sync upload folder. It appears the update has overwritten the configs, now this totally could be my fault for putting config changes in the wrong place. So this isn’t a grumble just a warning. I assumed things in the conf/
folder was safe to fiddle with but that’s not the case.
Setting up the local site
So now we are at a state where I can start to actually do something. My next step is to checkout a copy of my git repo for my site, which includes all custom code, including my deployment code. You can have a look at my deployment script for deployments and backups on Github. But once active I ran:
wp deploy run plugins.txt
This installed all my plugins, then I pulled the latest copy of my database and imported it into the DB, before finally running wp search-replace against the DB to change the URLs.
This whole process took about 20 minutes, and grudgingly, beyond the initial issues with WP-CLI and the version not showing, the dev environment worked well and is quite fast.
Very quickly I got annoyed by the fact, clearly, at some point, there was the option to open terminal and got to the apps default location. This makes sense as it would have had to open up the connection to Docker etc. The functionality had been removed (badly, as there were still references to it and even a menu item which errors out) so I wanted to add it back in. This also gave me an excuse to play with Electron, something I had not done for quite a while and only in passing. So I built a Local addon.
Building a Local Addon
So this is where things went a bit downhill. The documentation looks pretty but is utterly unusable, the support forums have unanswered questions. At one point it was clear the strategy was to make Local a bit like WordPress and be supermodular.
This idea seems to have died, they even have an ad offering money to people building addons but it seems this is legacy.
Basically, if you are building a Local addon it feels very much like you are on your own.
If you are familiar with building Electron apps then building a Local addon is like building a mini electron app, you have main.js and renderer.js, the later being the presentation layer. Local does provide some hooks, to hook into the admin, and actually the UI part is the best documented and once again gives you a hint that this was designer-driven.
While Electron Apps are just JavaScript, the Local team develops in TypeScript (which compiles down to JavaScript) so when you go exploring addons this might throw you. What does this mean? Not a lot other than a lot more build processes.
I spent probably close to a day to ultimately write maybe a dozen lines of code. The entire meat of my addon is:
main.ts
import * as Local from '@getflywheel/local';
import * as LocalMain from '@getflywheel/local/main';
export default function(context) {
const { notifier, electron } : { notifier: any, electron: typeof Electron } = context;
electron.ipcMain.on('launch-terminal-local', async (event, siteId: Local.Site['id']) => {
const site = LocalMain.SiteData.getSite(siteId);
try {
var open = 'open -a ';
var app = 'iTerm ';
var path = site.paths.webRoot
var escapedPath = path.replace(/(\s)/, "\\ ");
var exec = open.concat(app, escapedPath);
require('child_process').exec( exec );
} catch (e) {
notifier.notify({
title: 'Open Terminal',
message: `Unable to open iTerm`,
});
electron.dialog.showErrorBox('Open Terminal', e.stack);
}
});
}
Renderer.tsx
import React from 'react';
import { Button,TextButton, TableListRow } from '@getflywheel/local-components';
import { ipcRenderer } from 'electron';
export default function (context) {
const { hooks } = context;
//Debugging
//const remote = context.electron.remote
//remote.getCurrentWindow().openDevTools()
hooks.addContent('siteInfoUtilities', (site) => {
return (
<TableListRow key="open-terminal-local" label="Terminal">
<TextButton
style={{paddingLeft: 0}}
onClick={(event) => {
ipcRenderer.send('launch-terminal-local', site.id);
}}
>
Open Terminal
</TextButton>
<p>
<small>Will open default terminal Application</small>
</p>
</TableListRow>
);
});
hooks.addContent('SiteInfo_Top_TopRight', (site) => {
return (
<Button
onClick={(event) => {
ipcRenderer.send('launch-terminal-local', site.id);
}}
>
iTerm
</Button>
);
});
}
You might notice in that one I have commented out a few debugging lines to open DevTools because nowhere in the documentation mentioned there was the option in the UI via Preferences -> Advanced -> Show Develop Menu.
So don’t be me, just enable it in the app. You can see the full code on Github. However, the result, I now have a button next to the Start Site button to open iTerm. It’s not with the Admin/View Site button because I couldn’t find the appropriate hook.
This leads to another important consideration, Local is not open source. This is a closed source application, while you can tinker with it and create addons you don’t have access to the actual source code. It is an Electron app, you have more access than many applications but still, you can’t just peek and see what to look into.
For me developing a Local addon was utterly frustrating. There is a menu item in the preference that allows you to select which terminal application you wish to use. I would love to have hooked into that setting, but without documentation, I couldn’t actually work out how to call the setting.
To Local or not to Local
Local is pretty, it’s fast and, generally, I like it but it is incredibly opinionated and I don’t agree with some of those opinions. That’s ok, because for most people they are good options.
It is very much focused on WPEngine/Flywheel setups and customer acquisition, again that’s ok, they pay for its development.
It’s not open source and while there is a veneer of “come develop cool stuff and make this a great tool for your workflow”, it’s purely a veneer. The documentation is out of date but lacks any substance and without access to code to guide you, you end up looking at the existing addons which provide limited help.
It feels like at one point the team working on this came from a WordPress background, but I suspect that over time they have switched to be more designers and engineers. I don’t think people are dogfooding their own application.
Will I keep using Local? Probably not, though I haven’t switched it off. What I want is someone to do Local but open source. I want the prettiness, UX and speed of Local but the ability to actually fix the bugs and genuinely build out workflows.
Local has a lot of promise but I think it’s still struggling with direction, or maybe it’s not and it’s simply not the direction I want it to go.