June 2020 by Kristian Lumme

Using Git with WordPress — Part 1

In the first article in our new series on using version control with WordPress, we look at the benefits of keeping our work in version control and walk through a couple of simple scenarios where a plugin or a theme is kept in a Git repository. In upcoming articles, we'll go beyond the basics and expand our repository to include more of the project, look at Git submodules and the Composer package manager, and consider the role of the database in our workflow.

Make sure to check out article #2, #3 and #4— and get notified when the next article in this series is available, simply by signing up for our newsletter or by following us on Twitter.

WordPress and Version Control

There are many reasons you might want to keep a WordPress site — or parts of it — under version control. The potential benefits of version control are much the same here as they are for any other kind of project. You'll be able to experiment fearlessly, knowing that you can always get back to an earlier version of your code. Branches let you develop new features while simultaneously implementing fixes in your production version. Using a hosting service like GitHub, Bitbucket or GitLab, you'll not only have code backups with a full history of development, but collaboration with other developers will also be a lot smoother.

However, WordPress was conceived at a time when the use of version control was less ubiquitous than it is now. For example, the first release of WordPress was in 2003, while the first release of Git took place in 2005. Of course, there were capable version control systems long before Git, but considering the widespread use of Git in the industry today, this may serve to put WordPress in its proper context.

In other words, WordPress probably wasn't made with a version-controlled workflow in mind and, as anyone who tries to apply one to WordPress discovers, this does cause some issues. Unlike with some more modern systems, there is no single best way to do things, no generally accepted best practices. Still, people have given this topic quite a bit of thought, and the WordPress community has come up with some solutions and workarounds! By applying these techniques, you can get many of the benefits of a version-controlled workflow in your WordPress project with a minimum of the headaches.

Coming Up

In this article series, we'll look at some scenarios where you might want to use Git with WordPress, along with ideas on how to approach them. Moving from simple to more intricate workflows, we'll start with a couple of basic examples and then go on to introduce concepts like Git submodules and the Composer package manager. We'll also take a look at a couple of WordPress plugins that can be integrated into your workflow in order to streamline some aspects of it. Hopefully, the series will serve as a good overview of the different options available. Let's dive right in!

Scenario: Developing a Standalone Theme or Plugin

First, we'll quickly touch on the scenario where you're developing a standalone plugin or theme. This differs from the other scenarios which concern themselves with developing and version-controlling a website, and is the simplest of our scenarios. In this case, it probably makes sense to keep just your burgeoning plugin or theme in version control. You'd make the directory in question a Git repository, tracking changes here as you develop your project. While you probably use a WordPress installation to test it, the project is not directly tied to any particular WordPress site, and so the other aspects of the site don't belong in your repository.

Below is a quick look at how that may work. Let's assume we're working on a plugin, but haven't created a repository for it yet. Our plugin is in the usual place in wp-content/plugins inside the WordPress folder, and the contents of our plugin directory look something like this:

assets/
include/
src/
gulpfile.js
my-awesome-plugin.php

We want to add most of these files to the repository. The assets directory, though, contains files that are automatically generated from files in the src directory, using a build tool like gulp. Best practice is to not include files that are automatically generated from other files in your repository, and so we create a .gitignore file with the following contents inside the plugin directory:

/assets

Then, we initialise a repository in the plugin directory and add the relevant files and directories to it:

$ git init
$ git add .
$ git commit -m "Initial commit"

Next, we do some work on our plugin, editing some SCSS for example, resulting in git status reporting the following:

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes [...])
    modified:   src/scss/main.scss

no changes added to commit ([...])

We then commit our hypothetical change:

$ git add src/scss/main.scss
$ git commit -m "Prevent image overflow on smaller screens"

Now, git log shows a record of our changes:

$ git log --oneline
8df5539 (HEAD -> master) Prevent image overflow [...]
017159c Initial commit

As we keep working on our plugin, we can always check the development history, compare versions, and work on different features in separate branches. In addition, let's say we've created a remote repository for the plugin on a hosting service like GitHub. We can now push up our local repository, which gives us a code backup and makes collaborating with others easier (remember to substitute your own username and repository name):

$ git remote add origin https://github.com/klumme/my-plugin.git
$ git push -u origin master

To be sure, it's possible to expand on what's included in the repository. For example, we could have automated tests that essentially create a temporary WordPress installation programmatically. Maybe we have one or more Docker images with different WordPress setups used during development and testing, and the configuration of these are included in our repository. There are many options, but in this scenario it seems likely that the repository is focused on the plugin or theme.

What benefits will Git give us in a situation like this?

  • For one, it lets us try new things without worrying about losing any work. If we make commits every time we complete a self-contained chunk of work, we'll be able to jump back and forth in our development history, undo changes, compare versions and find out when a particular bug was introduced.

  • Using branches, we can try out new ideas without affecting the main line of development, discarding or integrating the ideas as we go along.

  • If we are working on our project with others, a Git hosting service such as GitHub, Bitbucket or GitLab will be a great help in integrating the work of all developers and distributing the latest changes to everyone.

Scenario: Developing a Site by Creating a Custom Theme

A scenario that is very similar to the one above is developing a site by creating a custom theme, keeping only the theme in version control. In this case, we might have a WordPress installation running on our computer, another on the site server, and possibly some testing or staging installation. We keep only the theme directory in version control, handling the WordPress installations and their content separately. For a simple site, this might be a good solution, giving us version control without the challenges that come with trying to keep more things in Git. The drawback is that the rest of the site lives its own life outside of Git, and so we don't have all of the development and history of the project in one place.

The steps for this scenario look much the same as the steps for the scenario above. Instead of repeating those, we'll look at how the workflow plays itself out in the Tower Git client. Similarly to the earlier plugin scenario, we have a theme we're working on, but not yet a repository. The theme resides in wp-content/themes/my-awesome-theme inside our WordPress directory, with the following files and directories:

assets/
include/
src/
functions.php
gulpfile.js
index.php
style.css

To initialise a repository here, we just drag the folder into our repositories in Tower and choose "Create Repository":


Again, we don't want the assets directory to be added to the repository, as its files are automatically generated. The same goes for the style.css file. To accomplish this, we just right-click the files inside Tower, choose "Ignore → Ignore This Item", and Tower will generate the .gitignore file for us:


We stage all the files and create our initial commit:


After making some changes and committing again, our development history is available right in Tower, and, as before, we can check the development history, compare versions, and work on different features in separate branches — this time, right in Tower!


The benefits are largely the same as mentioned for the previous scenario: code backups, fearless experimentation, collaboration... In addition, Git may be useful when we want to deploy the changes in our theme to the site. For example, a script on the site server could pull down the latest code from a hosting service and execute some build steps, or we could use an automation tool like Ansible to accomplish the same thing, or a dedicated third-party deployment service. In either of these cases, deployment likely starts with committing the latest updates to our Git repository.

Conclusion

That's it for the first installment in the series. We've looked at keeping a plugin or theme directory in version control using Git, and considered some benefits this brings us. In the next article, we'll go beyond the basics and expand our repository to include WordPress core files as well. We'll consider the cases where this makes sense and the ones where it doesn't, and deal with some of the challenges such a workflow brings with it.

Make sure to get notified when the next article is available — simply by signing up for our newsletter below or by following us on Twitter.

Your Download is in Progress…

Giveaways. Cheat Sheets. eBooks. Discounts. And great content from our blog!