Livin’ in a WordPress Hacker’s Paradise

June 5th, 2006

I have been happily using WordPress as the infrastructure for this blog since its inception, almost one year ago. Since I’m perhaps slightly geekier than than the average WordPress customer, I have been wanting to get to know the sources a bit better and possibly make my own tweaks or write plugins to suit my particular needs. I also like to keep up to date with the latest versions of the software. The problem is that these activities are at odds with each other. See, if you don’t tweak anything, updating is a simple matter of “un-tarring” the package file over your existing installation and visiting the “update.php” URL. But if you’ve made any sneaky changes, you’re liable to overwrite them when you clobber a source file with the updated version.

This situation has led me to an unfortunate state of moaning about having to install WordPress updates. This is bad, because often the small updates contain security fixes, which are exactly the kind of thing I should want to install immediately. Furthermore, I’d like to stop editing WordPress with vi on the server, and searching the source base with grep. I’m proficient with these tools, but I have a Mac! It’s better at such things.

I need absolute WordPress control. Specifically, I need to be able to:

  1. Install WordPress updates with ease and confidence.
  2. Hack on WordPress and test results on my Mac before updating the live blog.
  3. Do so in a way that meshes with my regular work habits.

How do I address this? The problem screams for Subversion and Xcode, so that’s what I will throw at it. By integrating my WordPress hacking with Apple’s Xcode, I can treat the technical underpinnings of my blog just like I would any other code project. I spend so much of my day “building and running” that it’s distracting when any technical project does not fit in with that process.

Step 1: Get Things Under Control

Source control, that is. I decided that I needed a single repository where both my live web site and local Mac could access the same WordPress sources. That means I need an SVN server accessible from both locations, as well as Subversion client tools in each location. Luckily DreamHost comes standard with Subversion support (minor gripe: they’re stuck on version 1.1!). If your web host doesn’t offer Subversion, you might be out of luck for this particular round of magic.

Typically with Subversion repositories, the “mainline” of the project is identified as a subdirectory of the repository called “trunk.” In my case, I don’t control the mainline of WordPress, so I’m choosing more clear identifications. My repository is “all branches,” if you will, so I’m not including any folder called trunk, though “official” is the closest thing to being that:

% svn ls file:///home/jalkut/svn/opensource/wordpress/          
hacking/
official/
redsweater/
redsweater-assets/

What I’ve done here is take advantage of the “smart copying” in Subversion. I started the repository out with “official,” containing the latest 2.0.3 release of WordPress. I then copied that in the repository to “redsweater” and carefully copied all of custom bits and pieces in. If you do this right, only the customized parts take up repository disk space. Everything that’s the same is shared in the database. The custom bits include the database configuration, custom themes, installed plugins, images, etc.

Where possible, I took advantage of a feature in Subversion called “svn:externals.” This lets you specify points in the project hierarchy that, when encountered, will trigger a checkout from a different repository. It’s sort of like an NFS Mount-Point right in Subversion. In the mysterious “redsweater-assets” repository folder above, I’ve added folders for most of my custom elements. So when I checkout “redsweater” and Subversion gets down to the “themes” section, it notices that it needs to checkout my custom theme from the redswetaer-assets/themes repository folder. This technique works great in almost every area of WordPress, except for the plugins directory. Because svn:externals can only specify a directory, it breaks down when one would hope to use it to plop individual files down into a checked out directory. I imagine this limitation comes from the fact that every folder in a working directory has a single “.svn” folder for tracking the entries at that level. Therefore, a directory of assets from mixed repositories would be tricky.

Even with the svn:externals shortcomings, the setup works pretty well now. I have a “redsweater” branch that I can integrate changes into, and then update my web site directly from the command line. At any time, I can examine the differences between my customized branch of WordPress and the official release I last integrated with. Comfort!

Step 2: Integrate with Xcode

The Subversion infrastructure goes a long way toward calming my nerves about integration and updates. I can carefully stage any update by first updating and testing it on my local machine. That’s cool, but it’s not really good enough. I want to be able to hack the heck out of it on my local machine (Note: You need to install a PHP-compatible Apache server before you can really do this on your Mac). Furthermore, I want to possibly be able to maintain a separate, highly experimental copy of WordPress for days, weeks, or months while I continue to serve (and perhaps update) the more stable version of the blog from my site. It’s time to look at the “hacking” branch that I hinted at above.

The hacking branch started life as a copy of the redsweater branch. I want it to closely mimic my real blog, but I want to have freedom to mess around with it big time. So the first thing I altered after copying the branch over was the wp-config.php. Instead of pointing to my live database, I pointed to a local MySQL database on my Mac (yet another custom install, sorry!). This database contains a subset of my live blog’s content. The idea is it’s a totally safe sandbox for me to work in. I can add comments, posts, pages, etc. I can delete everything and start from scratch. I can even post drafts of my entries from MarsEdit to see how they’ll really look when they finally go live. The ultimate preview! One of the things I’ve noticed so far in hacking on WordPress is that I need to provoke different situations before I can play around with the behavior. For instance, if I want to tweak the spam-filtering behavior, I have to first cause a spammy comment to appear on the blog. I don’t like doing this on the live blog, but fake spam comments are fine in my sandbox.

What else does the hacking branch contain? This is where it gets fun. The branch contains an Xcode project file, and supporting shell scripts to facilitate a streamlined development process. First I added all the WordPress sources to the project, for easy global search & replace. It’s amazing how much faster you can get to know the project when you get a “birds-eye view” from Xcode:

I find that I understand a project much better even by doing simple tweaks like globally replacing something so that it behaves differently. When I can observe the changes, it connects my test changes to the project’s design as a whole.

Next up I attacked the problem of “fixing the workflow.” What does it mean to “build & run” a WordPress project in Xcode? I decided that building WordPress means “copying the files into my local web server directory,” and running it means “opening a suitable URL in my web browser.” To that end, I added a single target to the Xcode project, “Install Local,” which is a simple copy files build phase target. It takes all the specified files and plops them over to the “blog” subdirectory of my local test server:

Sweet! Now when I want to try out my changes, I can just press Cmd-B to build and then load up my localhost URL in Safari. But the scenario isn’t quite complete. When I build an application in Xcode, I don’t have to navigate to the Finder, find the resulting product, and double-click it. Why should I have to go manually reload this web page? With Xcode custom executables, I don’t. I added a couple shell scripts to my “hacking” tree that, when specified as custom executables, simply cause the local blog to open up in the default browser. This trick is accomplished with some simple AppleScript bridging:

#!/bin/sh
osascript -e "open location \"http://localhost/blog/\""

For every commonly debugged location in the blog, you can just pop another custom executable into the project with a slightly different blog URL. Then you select the desired executable from Xcode and “run” the project to see how your results are shaping up.

Now I can make changes, build, run, examine the results, and even use Xcode’s built-in Subversion features to review what I’ve changed!

If you want a head start at making your own WordPress hacker’s paradise, you can download and plop my WordPress Xcode Project files into your own local WordPress “hacking” directory. It should work just fine with a standard 2.0.3 copy of the sources. The archive includes the Xcode project itself as well as a couple example “executable” scripts.

21 Responses to “Livin’ in a WordPress Hacker’s Paradise”

  1. vasi Says:

    The OS X ‘open’ command line utility actually supports URLs, so you can shorten your shell script to:

    open http://localhost/blog/

  2. 21 ways Says:

    Mac WordPress hacking…

    When it comes to hacking WordPress on your Mac, this article gives you some very good info on the subject.

    ……

  3. Non Stop Mac Says:

    Livin’ in a WordPress hacker’s paradise…

    When it comes to hacking WordPress on your Mac, this article gives you some very good info on the subject. Daniel Jalkut writes: “By integrating my WordPress hacking with Apple’s Xcode, I can treat the technical underpinnings of my……

  4. Ashley Clark Says:

    Here’s a script that you could use instead of making multiple scripts for each URL.

    #!/bin/sh

    osascript -e “open location \”${URL:=http://localhost/blog/}\””

    On your custom executable you can then define an environment variable URL to whatever address you want, if you don’t define the variable or disable it then it will default to “http://localhost/blog/”.

  5. Fawzi Mohamed Says:

    I would check out darcs (http://abridgegame.org/darcs/) I think it would make the merging process much easier.

  6. Kunal Says:

    Cheers for this and the Python post as well. With “projects” like these you keep nudging as all in the right direction ;) These seemingly small things can often help overcome the inertia that has killed many a project before they’ve even begun. Thanks again.

  7. Daniel Jalkut Says:

    Fawzi: Somebody else also suggested svk. I need to learn about these distributed versioning systems – for now I’m stuck in the “dark ages” but it’s such a step up from what I had before that it feels like modern times :)

    Kunal: Thanks! I’m glad you appreciate the articles.

    Everybody: Thanks for the refinement suggestions!

  8. Fawzi Mohamed Says:

    For me darcs was exactly how I thought a version management system should be (and I use cvs and subversion daily).

    Darcs in patch (or change) based, It keeps track of changes not of versions.

    You can have two repositories one where you un-tar the reference version and check in (record) the changes in darcs (darcs can also be synchronized with cvs or subversion keeping also the change-log).
    Then you can import (pull) the changes done in the reference repository in your development version.
    The merging will happen automatically (and darcs merge is really good), and in the few occasions where you have a conflict… well then filemerge is indeed your friend…

    darcs now is stable (since 2004 it mirrors the linux kernel) and the commands are easy to learn, the only thing is that being in haskell you need ghc, but opendarwin and fink/unstable have both ghc and darcs (at least for PPC, for intel there is a statically compiled version that might work through rosetta, but probably I would not trust my data to it).

    To sum it is really worth checking out, and I think it will pay off quickly.

    Fawzi

  9. Fawzi Mohamed Says:

    Something I forgot to say:

    if disk space is an issue then darcs might not be a good choice: text file changes store only the diff, but binary files changes replicate the whole file, and branches in darcs are a copy of the repository…

    Fawzi

  10. TBT Diarrhea » Blog Archive » Updated Wordpress wasn’t Updated Says:

    […] I’ve goofed up. My apologies to “jangwoosung” as I had to delete your registration. Let me try explain. Since I’ve upgraded my WordPress to 2.0.3, I’ve had to go back and make some adjustments to the custom code that I did. Daniel Jalknut had the same problem: “I have been happily using WordPress as the infrastructure for this blog since its inception, almost one year ago. Since I’m perhaps slightly geekier than than the average WordPress customer, I have been wanting to get to know the sources a bit better and possibly make my own tweaks or write plugins to suit my particular needs. I also like to keep up to date with the latest versions of the software. The problem is that these activities are at odds with each other. See, if you don’t tweak anything, updating is a simple matter of “un-tarring” the package file over your existing installation and visiting the “update.php” URL. But if you’ve made any sneaky changes, you’re liable to overwrite them when you clobber a source file with the updated version. […]

  11. dvb Says:

    Say — I’m doing something similar, trying to keep a local WordPress on my Mac to try out plugin code and such before deploying. For some reason, many of the admin links locally navigate *away* from http://localhost/blog and back over to http://realdomain.com/blog. I have the local and the real one (Dreamhost) both using the same mysql db.

    Any thoughts offhand?

  12. Daniel Jalkut Says:

    dvb: I think this is coming from a couple of DB-resident settings from the “Options” panel in your admin panel. The “WordPress Address” and “Blog Address” settings are stored in the database instead of being implied by the install path. I’m really not too fmailiar with these settings but I wonder if there is a tricky way to change them so they’re relative instead of absolute URIs.

  13. dvb Says:

    arrrr thx!

  14. Daniel Jalkut Says:

    dvb: i looked into this a little further and discovered something very interesting. It looks like you can specify a relative path in the “WordPress Address” and “Blog Address” settings. I am still testing this to make sure nothing goes wrong, but so far it’s looking pretty good! On my test servers all of the URls that are generated using those settings seem to work, and best of all the wp-admin panel “sticks to the test server” and doesn’t jump out to the main URL.

    Give it a try at your own risk :)

  15. Daniel Jalkut Says:

    I finally noticed a downside: in the auto-generated emails from WordPress, it seems to build URLs by just tacking on to the configuration URLs. So you’ll end up with broken, unclickable URLs in those emails. Some day I’ll look into how hard it would be to adjust that.

  16. Mark Says:

    WP 2.4 fixed this problem?

  17. Kent Says:

    “it seems to build URLs by just tacking on to the configuration URLs.”
    Yep … it seems

  18. Kent Says:

    2 Daniel Jalkut: great idea!

  19. RobotSkirts » Blog Archive » Red Sweater Blog - Livin’ in a WordPress Hacker’s Paradise Says:

    […] Livin’ in a WordPress Hacker’s Paradise Using svn and Xcode to maintain a WordPress blog while hacking it. Sounds very cool, but it isn’t surprising that my $3/mo. host doesn’t do svn. […]

  20. Red Sweater Blog - OMG BBEdit HTML Code Folding Says:

    […] I know this outs me as the world’s nerdiest sometimes-web-page-editor, but my preferred environment lately for managing my sites has been Xcode. I can easily do global search/replace, configure Safari as an executable, etc. I wrote about this weird behavior of mine specifically with regard to WordPress in a past entry. […]

  21. Tutorial on Objective-C/Cocoa using Xcode Says:

    […] here’s an excellent post on how to integrate the blogging platform WordPress into […]

Comments are closed.

Follow the Conversation

Stay up-to-date by subscribing to the Comments RSS Feed for this entry.