It’s a bold title, I know. But I have been working to achieve this for about five years now and am finally very satisfied with my configuration. If you’re looking to work on WordPress Themes or Plugins on your local machine, manage your code base with GitHub, and effortlessly deploy updates, you’ve come to the right place.
The first thing you need to do is upgrade to Mac OS X Sierra 10.12.2 or else you’re going to have problems left and right. You should already have done that, though, because you’re a developer and developers don’t like to live with stale operating systems.
After that you need to follow Chris Mallinson’s excellent tutorial, The Perfect Web Development Environment for Your New Mac. (I’m not going to rehash his whole article here because he did such a great job.) You can skip the bit at the end about implementing a custom home page if you want. I didn’t do that and it’s not really important if you already have your own method of navigating your own file system. I use Coda as my IDE and it handles organizing my projects.
The only tricky part of Chris’ instructions is getting your httpd.conf files right. You may get lucky and have everything work perfectly just by following his rules. I was not lucky and had to make several changes, but that’s probably because I have been screwing with my httpd.conf files for years. If you contact me I’m happy to send you my copies of httpd.conf and httpd-vhosts.conf and they’ll probably work on your machine. I keep an archive of them in my iCloud Drive folder and use the exact same configuration on multiple machines — two Mac Mini desktops and my MacBook Air — with no issues.
After you’ve installed MySQL locally you need to make sure you have the ability to actually use it. Terminal.app is your friend:
/usr/local/mysql/bin/mysqladmin -u root -p'temppassword' password 'newpassword'
Now you can create a database to use for WordPress. I always name mine “wordpress” but you can name it anything really.
In that code the temppassword is what the MySQL install gave you for root. It’s probably annoyingly complex enough to just use that same one again for the newpassword, but you can change it if you want.
Once you’ve gotten that working you’re ready to start really cooking. Download a copy of WordPress, unzip it, and drop it into ~/Sites/wordpress/ first. You’re going to run into some permission issues probably, but you can handle them with:
sudo chown -R _www ~/Sites/wordpress ; sudo chmod -R g+w ~/Sites/wordpress
And you’ll need to make sure you can install Plugins locally by adding this line to your wp-config.php script:
At this point you should be able to hit wordpress.test in your browser and start the WordPress installation process. I know it’s tempting to use localhost as your database host, but you should stick with 127.0.0.1. The database name is going to be the database you added to MySQL a few minutes ago.
Okay. So now you have WordPress running locally and you can edit Themes and Plugins without worrying about taking down a production website while you hack. Now it’s time to get serious. Do you have GitHub Desktop yet? If not, grab it and install it. (If you’re some crazy person that does everything via CLI, I have no idea why you’re even reading this since you probably know how to do it all already.)
Let’s work on Theme development first. Create a new GitHub repository and initialize it with a README. I’ll assume you named your repo “Skywalker” because you’re an awesome person and that’s what awesome people do. (Whether you make it public or private is up to you.) Click the big green Clone or download button and choose “Open in Desktop”. You’re going to save Skywalker in ~/Sites/wordpress/wp-content/themes/skywalker and it should only take a zillionth of a second because it’s an empty repo right now.
Okay. Edit your theme. You don’t have to do anything dramatic; just drop a style.css file in there and add a title to get started and save it. Switch to your GitHub Desktop app and it should show that a file has been changed and is ready to commit. But don’t commit yet. We’re just getting to the cool part.
Before you do anything else, SSH into your web server. If you can’t SSH into your web server, you’re out of luck and can’t really continue. You should be able to SSH into your web server, though. If you can’t, tell them you need shell access or else you’re going to switch to a different host! (I recommend DreamHost.) Once you’ve SSHed to your server, make sure it has git installed by running:
If your web server doesn’t have git running, guess what? You need a better web host.
Good to go? Okay … Moving right along.
Download Marko Marković’s Simple PHP Git deploy script and update its config script.
- You can get a value for the SECRET_ACCESS_TOKEN from the handy Random Key Generator. I know you want to use one of the Strong or Fort Knox passwords, but this key needs to be used as a querystring variable, so save yourself a headache and just use one of the CodeIgniter Encryption Keys instead. If you’re working on a WordPress theme for the government or a bank, jump through the hoops to make it Fort Knox safe. Otherwise I wouldn’t be too worried about someone hacking the local pizza place’s website by cracking the code here.
- Update the REMOTE_REPOSITORY to your own. It’s going to look like https://github.com/YOUR_GITHUB_USERNAME/skywalker.git
- For now leave the BRANCH set to master. If you’re rolling your eyes here and know that you want to use a different branch, go nuts. This is supposed to be a tutorial for beginners.
- Your TARGET_DIR is going to depend on your web host, so I can’t give you much direction here. If you use DreamHost and have WordPress running in the root of your domain, it will probably look like this: /home/DREAMHOST_USERNAME/yourwebsite.com/wp-content/themes/skywalker
You’ll need to FTP – or, better, sFTP – these two files to your web server somewhere. It doesn’t matter where, as long as they’re accessible to the outside world.
You also need the contents of your public SSH key (usually id_rsa.pub) from your web server. SSH into your server and run this to generate a key if you don’t have a way to get one from your web host:
ssh-keygen -t rsa
Doing that will likely drop id_rsa.pub into a /.ssh/ folder. (You can use vi to get to it. You just need to copy its contents.)
While you’re still SSHed into your web server, try to SSH from it to GitHub to make sure you can. You need to do this to “authorize” your web server to connect to GitHub, too. Run this command:
You should get a response saying something along the lines of, “That worked but you can’t do it,” which is confusing but okay. If it doesn’t work, you’re going to need to talk to someone at your web host and / or at GitHub to figure out why your server can’t talk to GitHub. I’ll assume it works so you can move to the next step.
Go back to GitHub, click on your repository’s Settings tab to get to the Deploy keys panel. You’re going to add the contents of the id_rsa.pub file you just created as a deploy key. (You can name it whatever you want, as far as I can tell the name doesn’t matter.) One snafu here, though: You can only use a single deploy key on a single repository. So if you want to work on two separate themes on the same server, you need to either generate a new user on your server for each one and then generate a new SSH key for each user or you need to drop your entire wp-content directory into the repo. (That’s what I did, but I don’t recommend it because then you’re going to have to deal with git-ignoring a ton of files, since all your WordPress media uploads and any other Plugins are in that folder, too.)
Switch to the Webhooks panel and add a new webhook.
- Your “Payload URL” is the full path to the deploy.php script you uploaded, along with a querystring containing the SECRET_ACCESS_TOKEN you added to the deploy-config.php script. Just append ?sat=SECRET_ACCESS_TOKEN to the file.
- The “Content type” should be application/json
- I have my webhooks set to “Send me everything”, although you can limit it to just the push event if you want to minimize how frequently it gets pinged.
- Yes, you want to make it active.
When you are done and click the green “Add webhook” button, GitHub will send a test ping to your web server’s deploy.php script and tell you the results right there.
If everything has gone smoothly to this point, you should be able to switch back to your GitHub Desktop app and run a commit. (I have mine set to always commit and sync. Under Edit check the “Automatically sync after committing” option.) When you commit, your files are pushed to GitHub which triggers the webhook which calls the deploy script which pulls your files from your repo and pushes them to your web server and BOOM!, now your new Skywalker theme is in production. How cool is that?!
You can have different webhooks for different branches of your repository. So let’s say you have three branches: dev, beta, and master. On your web server you would then have deploy-dev.php, deploy-beta.php, and deploy.php, each with its own unique SECRET_ACCESS_TOKEN and each hitting its own unique config file with a different TARGET_DIR updating the appropriate folder. Since you can selectively assign permissions to branches — assuming you have an “Organization” GitHub account — that means you could have some developer working on the dev branch and only allowed to push to your dev folder. Then you make your dev folder serve up your dev subdomain and now you don’t have to worry about a developer accidentally pushing something into production.
If you use Slack you can configure a different webhook to send a message to a Slack #channel any time someone commits, which is handy if you’re working on a big project.
I cannot promise that this will work perfectly in all situations, but here are the contents of my httpd-vhosts.conf file. I’ve stripped the comments. (Updated April 23, 2018)
<Directory "/Users/YOUR_USERNAME/Sites"> Options Indexes MultiViews FollowSymLinks AllowOverride All Order allow,deny Allow from all </Directory> <Virtualhost *:80> VirtualDocumentRoot "/Users/YOUR_USERNAME/Sites" ServerName home.test UseCanonicalName Off </Virtualhost> <Virtualhost *:80> VirtualDocumentRoot "/Users/YOUR_USERNAME/Sites/%1" ServerName sites.test ServerAlias *.test UseCanonicalName Off </Virtualhost> <Virtualhost *:80> VirtualDocumentRoot "/www/sites/%-7+" ServerName xip ServerAlias *.xip.io UseCanonicalName Off </Virtualhost>
- The Perfect Web Development Environment for Your New Mac
- Install WordPress on Mac OS X
- Get Apache, MySQL, PHP and phpMyAdmin working on OSX 10.11 El Capitan
- MySQL Download Page
- WordPress Download Page
- How to install plugins on localhost
- GitHub Desktop
- Simple PHP Git deploy script