WordPress Webhooked into GitHub

Home  >>  Common  >>  WordPress Webhooked into GitHub

WordPress Webhooked into GitHub

On December 3, 2012, Posted by , In Common, By ,,,,,,, , With No Comments

Code Affine is published using WordPress. Besides content provisioning there are technical tasks like site composition and software maintenance we have to take care of. Hence we were looking for a pragmatic but efficient way that allows us to develop locally, do versioning of changes, publish such changes automatically and last but not least run backups regularly. This post describes our ‘low budget’ solution for these problems using git, GitHub‘s post-receive hooks and a bit of PHP and shell scripting.

Our development takes place on local setups quite similar to the one explained in the article Test Driving WordPress1. However instead of downloading the complete installation and copying it into the web content folder of the test drive2 , we have a private git repository at GitHub containing the entire site. This enables us to clone the repository into the web content folder for development and work efficiently with the versioning capabilities of git.

As soon as we are pushing commits from the local repository to GitHub we like the according changes to be published automatically. For that purpose we use a webhook like service provided by GitHub called Post-Receive Hook. Such a hook is simply put an URL that gets called every time the repository is pushed to. In our case the URL points to a certain PHP page at codeaffine.com.

Furthermore the hosted web site is also a clone of the GitHub repository3. Because of this an incomming post-receive hook can be used to trigger a git pull to retrieve the latest changes that just have been pushed. In the simplest case the PHP page mentioned above could look something like this performing the pull45:

  <?php `git pull`;  

Note that this works only if the user the PHP process is assigned to is equipped with a SSH key that can be recognized by GitHub. Key generation and depositation at a GitHub repository is described thoroughly in the article Generating SSH Keys.

While writing posts the website’s content evolves and diverges from that one of the local drives. This applies to database values as well as to media content stored in the systems upload folder. To be able to setup test drives that are in sync with the live data at a certain point in time we also use git.

We achieve this by having one of the WordPress backup solutions installed that allows us to perform an automated database export. The exported file gets stored locally in a folder that is under control of our git repository6. With this in place the rest is a child’s play. A cron job runs first the database backup. Afterwards it executes a script that uses several git commands to add changes to the index, commit those changes to the local repository and push this commit to the remote repository7. Now content and the sources of the entire site are under version control and (re)setting up the complete system to any of the available revision points is straight forward8.

You may have noticed that our content storage is a one way solution. We do not change data locally, push the changes and run a database update to apply those changes to the web site. That is quite evident for content like posts because this is what a blog system is about after all. But thinking of installation of new- or update of existing plugins things are a bit different since those tasks may also imply database changes. In that case it might be desirable to autodeploy the changes to the live system after testing them thoroughly on a local test drive.

Of course we do plugin verification locally first, but as those changes in general are rather rare and small and the site traffic is managable we are content at the time being to replay this changes manually on the live system. Because of this we also go without a remote test drive.

As I mentioned at the beginning this is a ‘low budget’ solution that surely does not fit more comprehensive demands, but so far this setup served its purpose very well.


  1. Having an existing WordPress site up and running the section Installing an Existing WordPress Site is of particular interest
  2. I use the term ‘test drive’ although we are doing both development and testing on this installations. And with testing in this context I mean manually verification of the pages in contrast to the automated stuff I normally write about – shame on me :oops:
  3. Using such an approach you have to configure your .htaccess file properly to hinder download content of the git meta data directory
  4. Note the back-ticks that wrap the git command. PHP executes the content of the back-ticks as shell script. But you also might consider using one of the available shell-command execution instructions in php (exec, shell_exec).
  5. For reasons explaining is out of the scope of this post the real world scenario is a bit more complicated. But you might consider using a designated remote branch for publishing, let the PHP page basically set an update flag and use a separate shell script e.g. frequently run by a cron job to pull the changes if the flag is available
  6. Note once again to configure the .htaccess files correctly avoiding access to the database backup file – anyhow as we do not store secret stuff on our webserver this would not matter either ;-).
  7. As in general the cronjob runs at night and commits pushed from development are immediatly applied to the web site there is no danger of conflicts here
  8. Note that you might have to recreate your Permalinks after importing the database to your local system
Follow me

Frank Appel

Frank is a stalwart of agile methods and test driven development in particular. He understands software development as a craftsmanship based on a well-balanced mix of knowledge and the experience of the daily work.

fappel@codeaffine.com
Follow me

Latest posts by Frank Appel (see all)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>