Image of Cortney & Jeremy

Manage Your WordPress Theme Using Git

by Jeremy L. Gaddis on July 20, 2011 · 1 comment

in Website

When I first started this website, my purpose was to simply have a place I could post things that were useful to me and that I could access from anywhere. It didn’t take me long to realize that the things I was documenting were also helpful to lots of other people.

This is one of those posts. The great majority of my readers work in IT (or aspire to) and several of you run your own blogs. If you run your own self-hosted WordPress blog and modify your theme at all, this post may be helpful to you (even if you’re not in networking) — but it is very long.

I’ll be demonstrating (on a “test blog”) how you can add a “Tweet” button and a Facebook “Like” button to your WordPress theme and not have them wiped out when you upgrade. We’ll also add in a “I only speak for myself” disclaimer that some of our companies want us to have.

OBLIGATORY: Make your backups first and practice this a time or two before you do it on your live site. Don’t blame me if you hose your blog.

If you’d rather watch than read, check out the video at the bottom of the post.

The Problem

If you run your own blog, you’ve probably taken the time to browse through the available themes to find one that “fits” your web site. Some of us then take the time to “tweak” it a bit more.

The problem surfaces when the theme author updates the theme. If you’ve made any changes to your theme and then update to the latest version, you’ve probably seen your changes wiped out. You then have to figure out exactly what it was that you modified (and how) in the first place. This is made even more difficult since some of us don’t make backups quite as often as we should.

If you have SSH access to the server your blog runs on, this doesn’t have to be a problem anymore.

The Solution

NOTE 1: You can also use this method to manage your WordPress installation as well, if you have the tendency to modify the core files.

NOTE 2: There are other, “better”, ways of doing this but this works for me and will likely work for you too. Keep It Simple, Stupid.

To eradicate this problem, I began using a distributed revision control system called “Git”. This is the same version control system used for the Linux kernel source code (it was also written primarily by Linus Torvalds).

Git itself can be somewhat difficult to understand for a new user, but we’re not going to be using many of its features. I’m not going to attempt to describe how to fully use it — I’ll just be explaining what you need to know in order to keep your changes to your blog’s theme from being wiped out every time you upgrade.

NOTE: For a full introduction to git, check out the git community book or the “Mastering Git Basics” video.

While git will runs on Windows, I’ve never tried it and it’s apparently not pretty. What I describe here will work just fine on both Linux and OS X, however this article will be centered on Linux. Alright, enough fluff, let’s get started.

Installing git

Obviously, we’re going to need git installed, so let’s go ahead and get that out of the way. For Debian and Ubuntu, this is as easy as:

[text-box]

# apt-get install git

[/text-box]

For older versions, you may need to substitute “git-core” instead. Users of CentOS, Fedora, and RHEL will need to grab the packages from EPEL unless things have changed since the last time I checked (please leave me a comment if I’m wrong and I’ll update this).

Starting From A Clean Slate

NOTE: For this article, I’m actually using a “test blog” instead of my real blog (since I’ve already made these changes to it). For reference, my WordPress installation is be in /var/www/demo.lab.evilrouters.net/ and the theme files will be in /var/www/demo.lab.evilrouters.net/wp-content/themes/arras/. You’ll want to change these names below to reflect your own installation, of course.

At this point, we need to get the original, unmodified WordPress theme files so that we can start with a clean slate. Grab that from the WordPress theme directory, the theme’s homepage, or wherever. The theme I’m using is called Arras and I started off with version 1.5.0.1.

$ cd /tmp

$ unzip arras.1.5.0.1.zip
$ mv arras /var/www/demo.lab.evilrouters.net/wp-content/themes/
$ cd !$

Here, I’ve uncompressed the theme file, moved it to the proper place in my WordPress installation, and changed to my “themes” directory. For verification:

$ ls -l

total 12
drwxr-xr-x 8 jlgaddis jlgaddis 4096 Dec 15  2010 arras
-rw-r--r-- 1 jlgaddis jlgaddis   30 Apr 15  2009 index.php
drwxr-xr-x 4 jlgaddis jlgaddis 4096 Jun 29 14:41 twentyten

$ ls -l arras/
total 200
-rw-r--r-- 1 jlgaddis jlgaddis   659 Sep  3  2010 404.php
-rw-r--r-- 1 jlgaddis jlgaddis  2027 Sep  3  2010 archive.php
-rw-r--r-- 1 jlgaddis jlgaddis  1133 Sep  3  2010 attachment.php
-rw-r--r-- 1 jlgaddis jlgaddis  2007 Sep  3  2010 author.php
-rw-r--r-- 1 jlgaddis jlgaddis  3184 Sep  3  2010 comments.php
drwxr-xr-x 5 jlgaddis jlgaddis  4096 Dec 15  2010 css
-rw-r--r-- 1 jlgaddis jlgaddis   996 Sep  3  2010 footer.php
-rw-r--r-- 1 jlgaddis jlgaddis  2326 Sep  3  2010 functions.php
-rw-r--r-- 1 jlgaddis jlgaddis  5192 Sep  3  2010 header.php
-rw-r--r-- 1 jlgaddis jlgaddis  4531 Sep  3  2010 home.php
drwxr-xr-x 4 jlgaddis jlgaddis  4096 Dec 15  2010 images
-rw-r--r-- 1 jlgaddis jlgaddis   134 Sep  3  2010 index.php
drwxr-xr-x 3 jlgaddis jlgaddis  4096 Dec 15  2010 js
drwxr-xr-x 2 jlgaddis jlgaddis  4096 Dec 15  2010 language
drwxr-xr-x 4 jlgaddis jlgaddis  4096 Dec 15  2010 library
-rw-r--r-- 1 jlgaddis jlgaddis  1322 Sep  3  2010 page.php
-rw-r--r-- 1 jlgaddis jlgaddis  1252 Sep  3  2010 pagetpl-archives.php
-rw-r--r-- 1 jlgaddis jlgaddis  1427 Sep  3  2010 pagetpl-onecolumn.php
-rw-r--r-- 1 jlgaddis jlgaddis   498 Sep  3  2010 pagetpl-redirect.php
drwxr-xr-x 2 jlgaddis jlgaddis  4096 Dec 15  2010 sample-child-theme
-rw-r--r-- 1 jlgaddis jlgaddis 82216 Sep  3  2010 screenshot.png
-rw-r--r-- 1 jlgaddis jlgaddis  1817 Sep  3  2010 search.php
-rw-r--r-- 1 jlgaddis jlgaddis   442 Sep  3  2010 searchform.php
-rw-r--r-- 1 jlgaddis jlgaddis  1855 Sep  3  2010 sidebar.php
-rw-r--r-- 1 jlgaddis jlgaddis  1094 Sep  3  2010 single.php
-rw-r--r-- 1 jlgaddis jlgaddis  2233 Sep  3  2010 style.css
-rw-r--r-- 1 jlgaddis jlgaddis   110 Sep  3  2010 user.css
-rw-r--r-- 1 jlgaddis jlgaddis   955 Sep  3  2010 yarpp-template-arras.php

Here, we see there are a total of two themes installed: one that come with WordPress by default and the new one we just installed. I’ve also shown a list of my theme’s files.

Go ahead into your blog’s admin interface and switch over to the new theme. At this point, here’s what a post looks like before making any changes to the theme (click for full-size):

Creating A Git Repo

We’re going to keep all of our theme’s files in a git “repository”, so we need to create that before we make any changes at all to our files. Let’s change into our theme directory and initialize the repository:

$ cd arras/

$ git init
Initialized empty Git repository in ...

NOTE: Technically, you can skip this next step if you’re the only one who is going to be working on your files, but it’s become habit for me (I use git as part of a team on other projects as well) so I prefer to do it.

Let’s tell git what our name and e-mail address is:

$ git config user.name “Jeremy L. Gaddis”

$ git config user.email jlgaddis@gnu.org

Branches

At this point, our git repo is ready to go. I need to quickly cover one other concept, though: branches. Branches are used in the development process, to keep various things logically separate. Instead of working in the “master” branch, development/changes/bug fixes, etc. typically happen in their own branch. When I’m working on bugs for the logcheck project, for example, I create a separate branch for each bug. When you’re finished, you can then “merge” your local branch back into the “master” branch.

Sound complicated? It can be but, fortunately, we don’t need to know much about branching for what we want to do. The thing to remember is that the original theme files will live in the “master” branch and every change we make will be done in our own (“local”) branch.

Checking In

The master branch is where we start out. The first thing we want to do is “check in” the original, unmodified theme files into the master branch.

$ git add .

$ git commit -m 'checking in upstream v1.5.0.1'
[master (root-commit) be0ee2e] checking in upstream v1.5.0.1
 135 files changed, 11873 insertions(+), 0 deletions(-)
 create mode 100644 404.php
 create mode 100644 archive.php
 create mode 100644 attachment.php
 ...
 create mode 100644 style.css
 create mode 100644 user.css
 create mode 100644 yarpp-template-arras.php

Here, we’ve “checked in” the theme files. The git add command tells git which files we want to add to our commit (the “dot” signifies everything below our current location in the filesystem). git commit is what actually commits our changes, as you might imagine.

Before we make any changes to the source files, we need to create our own branch. Remember that the original theme will be in the master branch and our changes will be made in our own branch. You can call it whatever you want to, but I’ll call it “local-mods”. Let’s create our branch and switch into it:

$ git branch local-mods

$ git checkout local-mods
Switched to branch 'local-mods'

Let’s Get Hacking

Now that we’ve got everything set up, we can begin customizing and tweaking our theme all we want to. As I mentioned earlier, we’re going to make a total of three changes to our theme: adding “Tweet” and “Like” buttons and adding in our disclaimer.

NOTE: I’m not going to focus on the actual code used for adding the buttons. How to do that has been written about enough already. What we’re concentrating on here is preserving our changes across updates.

Tweet This

I added the code for the Tweet button into the theme (in single.php, in this case). If I look at my site now, we can see that it shows up right where I wanted it:

Now that we’ve got it how we want, run the git status command. The output should look something like this:

$ git status

# On branch local-mods
# Changed but not updated:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#	modified:   footer.php
#	modified:   single.php
#
no changes added to commit (use "git add" and/or "git commit -a")

This shows us the files that have been changed. To see the actual changes, you can use the git diff command to see them (“man diff” for more info on how that works if you’re not familiar with UNIX diff style output).

Since we’ve got this working the way we want, let’s commit these changes to our git repo:

$ git add footer.php single.php

$ git commit -m 'added tweet button'
[local-mods 6837562] added tweet button
 2 files changed, 4 insertions(+), 2 deletions(-)

Yeah, You Like That?

We’ll use a similar process, editing single.php again, to add the Like button. I want it displayed at the bottom of the post so I add in the code at the appropriate place. Once again, git status shows what files have been changed:

$ git status

# On branch local-mods
# Changed but not updated:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#	modified:   single.php
#
no changes added to commit (use "git add" and/or "git commit -a")

We’ll commit those changes just like we did before:

$ git add single.php

$ git commit -m 'added facebook like button'
[local-mods 09e0953] added facebook like button
 1 files changed, 1 insertions(+), 1 deletions(-)

Now our site looks like this, with the Tweet and Like buttons added in:

Don’t Blame My Employer For What I Say

Many of us have employers who want us to include something saying that our opinions do not necessarily reflect the opinions of our employers. In the bottom-right hand corner of my demo site, there’s a link to the theme’s web site. I’m taking that out and putting in my disclaimer instead.

Okay, with the disclaimer in, let’s commit the change:

$ git add footer.php

$ git commit -m 'added disclaimer to footer'
[local-mods 65020f3] added disclaimer to footer
 1 files changed, 1 insertions(+), 1 deletions(-)

Are you starting to see how this works? We’ve inserted one line and deleted one line (even though really we just changed one existing line).

An Update To Our Theme

Oh, look, the author of our WordPress theme has released an update. At this point, one of two things usually happens: the user updates the theme and wipes out all the changes he made -or- he decides never to update because he doesn’t want to lose those changes. Neither option is ideal.

Because we’re now using git to manage our changes, we get the best of both worlds: we can update to the latest version AND we get to keep our changes!

You might recall that I mentioned that the theme files will be kept in the “master” branch and our changes will be kept in the “local-mods” branch. When updating our theme files, we want to be absolutely certain that we’re working in the master branch (regardless of whether you update the files yourself or use the automatic update feature). Let’s switch back to the “master” branch:

$ git checkout master

Switched to branch 'master'

Download the new theme file (I’ve put it into /tmp) and let’s get ready to upgrade from v1.5.0.1 to v1.5.1.1:

$ cd /var/www/demo.lab.evilrouters.net/wp-content/themes/

$ unzip /tmp/arras.1.5.1.1.zip

unzip will tell you that the files already exist and ask if you want to overwrite them. Answer “A” to tell it overwrite all of them.

Archive: /tmp/arras.1.5.1.1.zip

replace arras/404.php? [y]es, [n]o, [A]ll, [N]one, [r]ename: A
  inflating: arras/404.php
  inflating: arras/archive.php
  inflating: arras/attachment.php
  ...
  inflating: arras/style.css
  inflating: arras/user.css
  inflating: arras/yarpp-template-arras.php

Go ahead and commit those changes (the updated files) to your repo:

$ cd arras

$ git add .
$ git commit -m 'checking in upstream v1.5.1.1'

Oh Crap, We’ve Lost Our Changes!

Let’s take a look at what our site looks like now.

OH NOES! All the time we spent making our changes was for nothing — our changes are gone!

Calm down, we just need to “rebase” our changes.

Getting our changes back is EASY! First, let’s switch back to our “local-mods” branch:

$ git checkout local-mods

Switched to branch 'local-mods'

Now we simply “rebase” our modifications against the new (updated) master branch:

$ git rebase master

First, rewinding head to replay your work on top of it...
Applying: added tweet button
Applying: added facebook like button
Applying: added disclaimer to footer

Remember how we did each of our modifications and committed them individually? The advantage is that each modification is now applied to the new version of theme independent of the others. If we decided that Facebook sucks, for example, and didn’t want to include the Like button anymore, we could easily leave that one out.

And if we take a look at our site now?

Voilà! Our changes have magically reappeared!

Future Updates

When new updates to your theme come out, you can repeat the update/rebase process to safely upgrade yet again, ensuring that you never lose your custom changes.

Caveats

I’d be doing you a disservice if I didn’t mention the possible caveats of using this method. Occasionally, when rebasing, you’ll get “conflicts”. Git isn’t sure what it should do in these situations and, instead of simply guessing, it aborts the rebase process and leaves it up to you to fix the conflict. Fortunately, these conflicts are easily resolved and then the rebase process can continue on.

If all this sounds way too complicated, well, it’s really not. If you’ve never used a revision control system before, it can sometimes take a bit to get accustomed to. I use the method that I’ve described here on several web sites and it really does save me a lot of time and trouble.

Video

For those of you who didn’t want to read all that, here’s a video showing the whole process from start to finish. You can see just how easily it is:

{ 1 comment… read it below or add one }

Leave a Comment

Previous post:

Next post: