Author Archives: Boone Gorges

Dropout

I’m a grad school dropout.

A little over a year ago, I left my full-time instructional technolgy gig at Queens College. At the time, I cited my languishing thesis as one of my reasons for leaving. Through the summer and fall of 2010, I put in an honest effort toward my dissertation. It was certainly my most sustained and serious effort since finishing coursework a couple years earier. But I couldn’t figure out a way to enjoy it. I found myself far more productive in other areas of my life, which had the dual effect of taking the joy out of my academic work, and also demonstrating that I no longer had any career-related reasons to finish the PhD.

So, a few months ago, I counted my losses and withdrew from the program. I use the word ‘losses’ with some trepidation, as I don’t feel like I lost much, if anything. In the philosophy program, I learned a lot about philosophy, got some nice teaching experience, and met some good friends. And being in graduate school had a huge number of indirect professional and personal benefits for me. Except for the academic work, I enjoyed being a grad student. If, in quitting, I’m losing anything, I’m losing face. But, to be perfectly honest, if there’s anyone who thinks less of me because I didn’t finish my PhD, that person is more than welcome to kiss my ass.

What excites me most about formally giving up on the PhD is leaving behind the guilt associated with the unfinished dissertation. Many times in the past couple of years (and increasingly so, as time has gone on) I’ve been approached with an offer or an idea about some new project – writing, coding, eating, etc. Time and time again, I have turned down these kinds of projects, because I’d end up feeling overwhelmed by the guilt of working on something other than my dissertation. To tell the truth, I had even stopped reading books for pleasure, because I felt so bad about it. I’m looking forward to feeling more freedom in this respect. (Also, the baby’s coming soon!)

I’m not writing this post because I’m looking for any validation of the decision; I feel good about it already. I’m also not really interested in starting a large discussion about the value of graduate school or a graduate degree; my decisions are specific to my situation. I mainly just want to get it off my chest, so that I don’t have to have the inevitably awkward conversations about it. To wit: I was chatting with some academic friends at THATCamp and I told the group that I’d dropped out, which they took as a cue to rationalize and support my decision. It was, of course, very well-intentioned. But from a certain point of view it suggested pity, which I neither need nor want. I may be a grad school dropout, but I’m a happy one!

BuddyPress and the YOURLS: WordPress to Twitter plugin

A few weeks ago, I wrote about reclaiming short URLs using YOURLS. That post raised some interest among the CUNY Academic Commons team in having a URL shortener just for the Commons, with full integration into BuddyPress. So I emailed Ozh Richard, author of YOURLS, about the possibility of adding BuddyPress support to his official YOURLS WordPress plugin, YOURLS: WordPress to Twitter. He graciously accepted my offer to do the leg work.

Today I’m releasing the fruits of this collaboration: version 1.5 of YOURLS: WordPress to Twitter. YWTT 1.5 automatically detects when you’re running BuddyPress, and adds the following BP-specific features:

  • Member and Group URLs – Generate short URLs for member profiles and for group home pages.
  • A “pretty URL” setting – Instead of generating random URLs (like http://blo.so/54), you can make member and/or group members ‘pretty’ (like http://blo.so/username or http://blo.so/groupname).
  • User customizability – Optionally, you can add new options under groups’ Admin > Group Settings and members’ Settings > Short URL allowing users to request a custom short URL of their choice. (This feature requires that you set YOURLS_UNIQUE_URLS to false in your YOURLS configuration file.)

Down the road, I plan to flesh out BP-YOURLS functionality, with optional short URLs for forum topics, activity items, and so on.

I’ve also slipped full localization support into version 1.5. Send me your mo/po translation files if you’d like them to be distributed with the plugin.

Download YOURLS: WordPress to Twitter 1.5, with BP support.

Stand for something

Lately it’s been fashionable to talk about the evils of sitting. This particular reporting trend hits especially close to home for me, as I’ve made the transition from peripatetic teacher/grad student to get-me-another-mountain-dew coder over the last year or two. So, on the inspiration of a few blog posts (notably, Gina Trapani’s and Derek Brooks’s), I decided to give the standing desk a shot. I made the switch around five weeks ago. Here’s how I did it, and how it’s going.

Standing Desk Setup

Standing Desk Setup

The setup

You can buy desks that are specifically made for standing. You can even buy desks that convert from a sitting to a standing position. The problem with these is that they cost a lot of money. As evidenced by the fact that my current desk is a piece of crap I found for free on the internet, I don’t want to spend a bunch of money on a desk if I don’t have to. Also, it seems unwise to invest big bucks in a standing desk before knowing whether it’ll be a workable setup. So I set it up on the cheap, using crap that I found around the house. (I may never work up the gumption to spring for the super-expensive standing desk, as my makeshift setup is working just fine.)

People who see my setup are often amazed by how high everything is, especially my screens. (Usually, these people are shorter than I am.) I am a big believer in being able to look at my computer screens without craning my neck downward, so I prop them all the way up to standing eye-level. In fact, this is something I’ve always done, even at a regular sitting desk. For those using a laptop, this means getting a separate keyboard and mouse. But this one change – moving screens to a natural eye-level – has had more positive ergonomic effect than any other adjustment I’ve ever made in the way I work. I definitely recommend it.

I did quite a bit of experimentation with keyboard/mouse heights. At first, I had put them too low – around waist level – which meant bending my wrists backward a lot. Then I overcompensated and moved them too high, but my hands kept getting cold and falling asleep due to decreased circulation. I settled on a height that allows me to keep my forearms roughly parallel to the floor at all times (which means that my elbows are at roughly a right angle, and my wrists are straight). To alleviate arm fatigue, I have a couple little gel-thingies where I rest the heels of my hands when I’m not typing quickly.

The biggest complaint I’d seen about the switch to the standing desk had to do with foot fatigue, which many seem to experience during the switch. For some reason, I have never felt it. The only place I ever get sore is in my upper back, between my shoulder blades. This probably has something to do with the way that I tense up when I type or when I think too hard. (This happens a lot, because, duh, I’m such a deep thinker.) However, I did end up buying a standing mat, as I have hardwood floors that would get somewhat uncomfortable after an entire workday. I went with the Imprint Nantucket Series, which got nice reviews on Amazon. So far, I like it.

How it’s going

To date, the experiment has had mostly positive results. Aside from the shoulder pain mentioned above, I don’t have any physical complaints. Standing seems to keep me more alert, and makes me feel less lethargic. It forces me to take breaks through the day (something I had a tendency not to do before, which probably had a net negative effect on my productivity). Generally I’ll take a half-hour sit around lunchtime, and if I’m lazy in the mid-afternoon, I’ll unplug my laptop and move to the couch for a while. Standing also means that I don’t work into the wee hours – I tend to start work around 8:30am and never work past 6 or 6:30pm. This is a good thing for my mental health. Finally, standing leads to much more dancing, which is, of course, something we all need more of in our lives.

Working on a photoblog theme for WordPress

After seeing that Andrew Spittle is working on a WordPress theme for a mobile photoblog (as discussed here), I thought I’d do the same. I happen to like Autofocus pretty well, so I’ve just made a child theme, with a few Twitter-specific modifications. Follow it on Github: https://github.com/boonebgorges/boones-photoblog. (Keep in mind, you’ll need the parent theme Autofocus installed for the Boone’s Photoblog theme to work.)

Shorten your own dang URLs

In my last Project Reclaim post, I talked about using WordPress as a Twitpic-like personal mobile photo service. When the ultimate goal of the photoblog is to send a tweet, it’s almost always necessary to use a URL shortener. But trusting your URL shortening to a free service is a dangerous move. If that service goes out of business, or if they decide to take down the database for some reason or other, the links in those tweets will break. (This problem is delightfully called “linkrot”.)

So, while URL shorteners are sometimes necessary, they’re also an obvious instance for reclaiming your data. Moving to your own URL shortener means that you control the domain, you control the content, you can back up the database however you’d like, etc.

I went with a piece of software called YOURLS. It’s written by Ozh Richard, a WordPress developer, and there’s a slick WP plugin that makes it a great choice for use with my WP photoblog. Here’s a short walkthrough of how I set it up.

Setup

  • Get a domain. Something short is nice, obviously. I just started typing two- and three-letter domains into my domain registrar’s search box (I use Dynadot), which showed me the top-level domains available, until I found one that was easy to look at and remember (http://blo.so). Make sure you do whatever setup your registrar requires to get the domain working – probably as simple as setting the nameservers to your host’s NS addresses.
  • Install YOURLS. The instructions provided at the YOURLS site are pretty concise, but here’s the gist: upload the software to the server, create a new database, copy the sample configuration file to user/config.php, and fill in the configuration file with the proper database info, etc. You can get more YOURLS config info here.
  • Configure an Apache virtual host, if necessary. If your hosting provider doesn’t have cPanel or some other tool that easily lets you point your new short domain to a subdirectory, you’ll need to do it manually by creating a new Apache virtual host file and activating that site. This website has a pretty good explanation. But essentially, just copy the default configuration in sites-available (likely at /etc/apache2/sites-available) and change the info in the VirtualHost section.
  • Install the WordPress plugin. The YOURLS: WordPress to Twitter plugin is easy to install and set up. Once the plugin’s installed, go to Dashboard > Settings > YOURLS and fill in the necessary information. Setting up the Twitter bit is a pain, thanks to Twitter’s requirement that you get a developer’s key, but it’s easy to do. Just follow the on-screen instructions.

At this point, everything should be set up. Send a test post or two to try it out.

Bonus! Use me with Tweetdeck

YOURLS has a REST API that can be used with a bunch of applications. For instance, I’ve configured my TweetDeck installation to do its URL auto-shortening with blo.so. Go to Settings > Services and choose Other from the URL shortener dropdown. Your endpoint will look something like http://blo.so/yourls-api.php?signature=XXXXXXX&action=shorturl&url=%@&format=simple. You’ll have to replace blo.so with your own URL, of course, and the XXXXXXX signature with a custom YOURLS signature password. You can get it from the YOURLS admin screen (http://example.com/admin/tools.php > Secure passwordless API call)

Here’s the great thing. There’s no reason why a couple people can’t share a single YOURLS installation. In fact, I’ll put my money where my mouth is, and start my own URL shortening co-op. I’ll give usernames/passwords to blo.so to the first couple friends who want in. Send an email to boonebgorges at gmail if (1) you are my friend, (2) you want in on blo.so, and (3) you promise to actually use it and break the bit.ly/tinyurl habit.

Kicking the Twitpic habit with WordPress

Twitpic and its ilk are pretty convenient, especially when they’re integrated into mobile Twitter apps. But as recent articles have shown, the terms of service of such services can be downright icky. Twitpic may have changed its tune a few days after the outcry, but honestly, if it takes an outcry to make a company not be evil, then maybe you shouldn’t be dealing with that company.

This is a perfect little side project for Project Reclaim, and something of a no-brainer. Twitpic etc are stripped-down publishing platforms. I already run a couple installations of a non-stripped-down publishing platform, namely WordPress. So I set up my own photo blog in just a couple of minutes.

I already have an instance of WordPress Multisite that I use for a bunch of different purposes. So setting up the blog itself was easy – I went to my Network Admin panel and clicked Add Site. If you’ve never worked with WordPress Multisite before, you should know that it’s already built into the WordPress installation that you may already have. You can read more about how to turn on Multisite at the WordPress Codex, or you can watch a somewhat out-of-date but otherwise charming video of a handsome and engaging speaker talking on this very subject.

Then I found a theme that looks nice with photographs. I didn’t look very far. My favorite visual theme has, for some time, been Allan Cole’s AutoFocus. In the future, I’ll probably build a child theme that has a few tweaks appropriate for my mobile photo blog, but it works pretty nicely out of the box.

Then I fired up my WordPress Android app (there’s one for the iPhone too) and connected it to my new WordPress blog. (You’ll have to enable XML-RPC on your WP blog if you want to use the mobile app.) I tweaked a few of the blog setting in my app, so that the photo would be linked after I published it, and the thumbnails would be of an appropriate size.

Finally, I got a WordPress plugin that sends tweets every time a post is published on the photo blog. I’m using YOURLS (more on this in an upcoming Project Reclaim post), but there are lots of them out there that are freely available. Just search the WordPress plugin repository.

Now, when I want to tweet a picture, here’s what I do. Open the WP app. Create a new post. Click the Media button. Take the photo. Add the content of my tweet in the Title field. Publish. (Don’t have to do it in this order, of course.) Totally painless – and I don’t have to worry about any terms of service. Yippee!

For more reading, here’s another blog post about the very same idea.

BuddyPress Docs 1.1: Doc History

BuddyPress Docs History

BuddyPress Docs History

I’ve just released version 1.1 of BuddyPress Docs, my collaborative editing software for BuddyPress.

The big new feature in version 1.1 is the History tab. After upgrading, you’ll notice that what used to be a single Edit button has been reorganized into three tabs: Read, Edit, and History. History allows you to brows the entire revision history of a document, to compare the differences between two revisions side by side, to view a single revision, or to restore to any point in the document’s history. Access to the History tab can be limited in the same way that access to the Edit tab can be, on a doc-by-doc basis.

This new feature will, I hope, bring some of the best qualities of wikis to BuddyPress Docs, and make Docs an even better way to collaborate.

Download BuddyPress Docs from the wordpress.org plugin repo or follow development at Github.

Revisiting Git, Github, and the wordpress.org plugin repository

Some months ago, I wrote about using Git and Github with the wordpress.org plugin repository. Since that time, I’ve been refining my plugin development workflow. I now do all of my development with Git, using git-svn tools to do all svn management.


Preamble: Git as primary vs secondary

Before talking more about my workflow, I should make a sort of conceptual distinction. When I develop most of my plugins, I am working alone. In these cases, Git is primary. It’s where the meaningful version control happens, while svn.wp-plugins.org is just a gateway for wordpress.org/extend, the distribution channel. I am not using the wordpress.org svn repository for version control or code sharing in any interesting way. Likewise with a few team projects that I’m involved in, notably Anthologize. All of our code-sharing and true version control happens via Git and Github (here’s our repo), with the wordpress.org svn repo used only as a distribution mechanism.

In contrast, I also use Git to develop BuddyPress, but the strategy is quite different. In the case of BuddyPress (as in the case of WordPress), the svn repo is the officially sanctioned version control system for the project. Git, in this case, is a secondary, local versioning system – essentially, my development sandbox. This setup places additional restrictions on how the git-svn link is managed, raising issues such as juggling svn branches, tagging version off of an svn branch, exporting patches in an svn-compatible format, and so on.

In this post, I’ll be focusing on the first kind of development setup, in which the wordpress.org svn repo is serving merely as a distribution channel. It’s a bit simpler to start there. Moreover, I’ve been chatting with Mark Jaquith about Git for WP development, and I know from those chats that he’s planning on writing up a description of the second kind of workflow (which characterizes the WordPress core work that he’s more concerned with). So I’ll leave the sophisticated stuff to him.


Part One: Getting your repos set up

You’ll need to have Git installed on your computer, with git-svn compiled. Here’s a guide to compiling it yourself on OS X; it’s also available through a number of repos on various OSes.

Create a directory for the plugin in the plugins directory of your dev install. I’ll use my recently released plugin Unconfirmed as an example; you can follow along using the example (until it comes time to push and commit!), or use your own plugin.

[code]

cd wp-content/plugins

mkdir unconfirmed

[/code]

The next step will require you to clone your wordpress.org svn repo. This assumes that you have requested and been granted space in the repository already. If you’re just starting plugin development and don’t want to request space yet, that’s OK – just begin your development in a normal Git repository. As long as you are pushing your Git changes somewhere (like Github), you’ll be able to wipe out your local copy when it comes time to send it to wordpress.org and start from this point as if you were starting from scratch.

Get a revision number for the plugin. You don’t want to force git-svn to crawl through the 300,000+ revisions on the wordpress.org repository. (For those keeping score, this is the only time you will have to run an svn-native command!)

[code]

svn log http://plugins.svn.wordpress.org/unconfirmed

[/code]

Look for the first commit number, where the plugin was added to the repository. In my case, it’s r387893.

[code]

r387893 | plugin-master | 2011-05-23 04:10:19 -0400 (Mon, 23 May 2011) | 1 line

adding unconfirmed by boonebgorges

[/code]

Clone the svn repository into the local plugin directory. Here’s the syntax, followed by some explanation.

[code]

git svn clone -t tags -b branches -T trunk -r387893 http://plugins.svn.wordpress.org/unconfirmed unconfirmed

[/code]

  • git svn clone is the command itself
  • -t tags -b branches -T trunk tells Git about the directory structure of the svn repository that you’re cloning. The flag --stdlayout or -s is shorthand for the same thing, though I’ve had mixed luck getting it to work – so I just enter the whole thing explicitly.
  • -r387893 is the svn revision number where I want Git to clone. In the next step, we’re going to tell Git to fetch the svn revision history starting with this commit; that’s why we chose the first, rather than the last, commit from the unconfirmed repo.
  • http://plugins.svn.wordpress.org/unconfirmed is the address of the plugin on the wordpress.org repo. It’s important to use this address rather than the alias http://svn.wp-plugins.org. As I discovered (after much frustration), Git is not able to trace the branch/tag history from the wp-plugins.org address – you have to use plugins.svn.wordpress.org.
  • unconfirmed is the relative path to the directory where I want the repo cloned.

Next, fetch the svn commit history like so:

[code]
cd unconfirmed
git svn fetch
[/code]

When you hit enter, git-svn queries the wordpress.org repo, starting with the initial revision number you pegged in the previous step, and walks all the way forward to the (entire) repo’s most recent revision, mirroring your plugin’s svn revision history in your local Git clone. If you’ve just received the space in the svn repo, this will only take a few seconds. If you’re doing this with a plugin that was put into the repo some time ago, or one that has a lot of revisions (and branches and tags) in the svn repo, you’ll have to wait a long time. Drink a beer or ten while you wait.

You’ll know the process is done when you are returned to your command prompt. Test to make sure that you’ve pulled in all of the remote tree by entering the following:

[code]
git branch -r
[/code]

This will show you a list of all the remote branches being tracked by this Git repository. If it’s a fresh repo, you’ll only see the trunk. If it’s a repo with existing branch and tag history, you’ll see one Git branch corresponding to the trunk, one corresponding to each svn tag, and one corresponding to each svn branch.

If you’re not planning to use Github or to share your code with anyone else, you’re done. If you are planning to use Github (as I do), you’ll need to add your Github endpoint as a remote repository. Assuming you’ve already created a repo on Github,

[code]
git remote add origin git@github.com:boonebgorges/unconfirmed.git
[/code]

origin is the name I’ve chosed for the Github endpoint, but you can call it whatever you want.

Now it’s time to reconcile your commit histories. Hopefully, you’ve only got one history to deal with – either in the Git or in the svn repo – so you won’t have too much trouble. In such a situation, something like the following should work:

[code]
git pull –rebase origin master
[/code]

So, here’s the thing about --rebase. It rolls back, albeit temporarily, all of the changes on your local copy of the repository back to the last common commit, applies all of the remote revisions, and then attempts to apply your revisions on top of it. If you are working with a fresh Github repository, there will be no common commit in the history, and there won’t be any revisions from Git to rebase back onto the tree. Thus, the svn history will be rolled back, zero commits will be put onto the local repo, and the svn history will be laid back down. In other words, nothing will happen, except that the Github repository will establish a common ancestor revision, allowing you to push. Mutatis mutandis, if you have an active Github repo but an empty svn repo, zero commits will be rolled back, and your Github history laid on top of the local repo, with the zero commits laid back on top. In other words, it’ll sync with the Github history seamlessly, and allow you to commit back to the svn repo by establishing a common revision history. If you have active, separate commit histories in both svn and Github, may God have mercy on your soul.

In any case, use --rebase with great caution. Read the git-rebase docs and try to wrap your head around it before doing anything that will mess up the revision history.

Once you’ve successfully pulled from Github, your three repositories – the local Git repo, the Github Git repo, and the svn repo on wordpress.org – will all be aware of each other and in sync. You are ready to develop.


Part Two: Day to day development

Let’s say you’ve found a bug (OH NOES) and you need to fix it. Before digging into the code, get yourself to the command line to make sure you’re in good working condition.

The first thing I do before I touch any code is to see what’s happening in my local repo:

[code]
git status
[/code]

There’s a lot of good information that git status can give you, for which I refer you to the docs or to Google. The important concept for our purposes is that we start a new local branch every time we want to fix a bug or develop a new feature. The notion of hyper-specific, temporary branches is one of Git’s biggest selling points, as well as one of the places where it differs the most from the way that many WP developers work with svn. Since branches are strictly local unless explicity pushed, and since Git’s merge and rebase tools are so nice, you can create, merge, and destroy branches at will, and keep your work separate. To add (and switch to) a branch called stupidbugfix, use this syntax:

[code]
git checkout -b stupidbugfix
[/code]

This does two things: it creates the new branch stupidbugfix, and it checks out that branch (similar to svn switch). git status will show you that you are now On branch stupidbugfix.

Do your bugfixing as you would normally do. When you’re ready to commit the changes, do another git status. You might see a result that looks like this:

[code]
# On branch stupidbugfix
# Changed but not updated:
# (use “git add …” to update what will be committed)
# (use “git checkout — …” to discard changes in working directory)
#
# modified: readme.txt
#
no changes added to commit (use “git add” and/or “git commit -a”)
[/code]

In this case, I’ve made changes to one file: readme.txt. In order to commit these changes, you’ll first need to stage the file with git add:

[code]
git add readme.txt
[/code]

(git add is automatically recursive, so you can add whole directories this way too.) Now you can commit the changes:

[code]
git commit -m “Fixing that stupid bug.”
[/code]

If you’re confident that you want to stage all changed files to a commit, you can skip the explicit git add and use the -a flag:

[code]
git commit -am “Fixing that stupid bug”
[/code]

Now, let’s get your changes from the stupidbugfix branch into the master branch, which we’ll use to push to our central repository. Then we’ll delete the temporary stupidbugfix branch.

[code]
git checkout master
git merge stupidbugfix
git branch -d stupidbugfix
[/code]

If you are sharing your code on Github, you can push your commits at this point:

[code]
git push origin master
[/code]


Part Three: Releasing a new version to the wordpress.org repo

If you’re following the steps I’ve outlined above, all of your development is happening in Git and Github. The only time you’ll need to touch the wordpress.org repository is when you want to release a new version. Here is the procedure I use. [EDIT 2012-09-14: See the Addendum below for an improved workflow for this step.] First, rebase the svn trunk to your current branch.

[code]
git rebase trunk
[/code]

This small bit is crucial, and it took me many months of frustration before I finally stumbled upon this (cache only!) blog post, which put me on the right track. The concept here – so far as I understand it, at least – is that git-svn actually rewrites the MD5 hash that Git uses to identify the changeset, and when you rebase the trunk into your current local branch, you forcing git-svn to match Git-changeset MD5s with svn-changeset MD5s. If you don’t do this, you’ll get infinite merge conflicts.

Now, let’s send those commits to wordpress.org svn.

[code]
git svn dcommit
[/code]

This sends all changesets (since the last time you dcommitted) up to the WordPress svn repository. (In other words, you’re mirroring the revision history.) Once this is done, the revision history on your svn trunk will match that of your current git branch.

Now we’re ready to tag the release in svn. (I’m assuming that you’ve already changed current version and stable tag numbers in your plugin files before dcommitting. If not, make those changes, git commit them, git rebase trunk, and git svn dcommit.)

[code]
git svn tag 1.1
[/code]

This will do the same thing as when you svn cp your trunk into tags/1.1.

I like to keep tag history in Git as well. Git tags are metadata (while svn tags are really just branches), so they have to be created separately, and pushed up to Github.

[code]
git tag -a 1.1 -m “Tagging 1.1”
git push –tags
[/code]

Finally, before making any more changes that can be pushed back to Github, you’ll have to rebase from Github – again, to make sure that Git understands that your Git MD5s have been overwritten by git-svn. Assuming you’re on your master branch:

[code]
git pull –rebase origin master
git push origin master
[/code]

Again, this rebase business is scary and dangerous, so try to understand the possible ramifications if you are working on projects that involve other people.


Conclusion

This might seem like a lot to learn. But developing in Git is hugely beneficial, well worth the learning curve. Git’s agile branching allows a kind of focused, compartmentalized development strategy that can’t easily be replicated with svn. And having Github as a bugtracker and changeset-viewer is also really great. Plus, working with Git in my own development means that I don’t have to code-switch (pardon the pun) when working with clients who use Git for collaborative work, which, I’m finding, is increasingly common. Learning about Git with your own WP plugins is a great way to learn some of the finer points of Git.


Addendum (14 Sep 2012): Be a better wordpress.org citizen and squash

The biggest headache in the git/wordpress.org workflow has always been lining up the revision histories. Git revision histories are non-linear, and SVN does not understand them. So the process of rebasing the development branch into the trunk-tracking branch is always precarious, as trunk is a flattened, svn-friendly branch. Moreover, even when the rebase does work, you end up reduplicating revision histories in both Git and SVN, when the real purpose of wordpress.org SVN here is really just distribution. (This makes Otto sad.)

So, for the last six months or so, I’ve used a modified version of the release workflow described in Part Three. First, I have a local branch, which I call svn, which tracks trunk:

[code]
git checkout -b svn trunk
[/code]

At release time, I check out the svn branch, and do a squash merge. This means that all changes since the last commit to the svn branch are laid on top of svn as if they were a single set of changes. You can then commit these changes as a single changeset (thus keepin’ it linear, and keepin’ it short for Otto’s sake):

[code]
git checkout svn # if you’re not already on it
git merge –squash master
git commit -m “Merging changes from Git for 1.1 release”

[/code]

Note that you might get a message from Git that there were merge conflicts, in which case you’ll need to use mergetool to clean up. But this is a subject for another post.

Then, do your git svn dcommit and git svn tag from the svn branch. It’s important that you never rebase to or from the svn branch, or do any development there; all changes on that branch should be squash-merged from a git-only dev branch.

New WordPress plugin: Boone’s Sortable Columns

Boone’s Sortable Columns is a new WordPress plugin to make it easier for developers of WordPress plugins and themes to create sortable data tables and lists. Like my recent Boone’s Pagination, this is not a plugin for end users but for developers. (And, by the way, Boone’s Sortable Columns goes with Boone’s Pagination like strawberries go with rhubarb. More on that in a minute.)

If you’re building a client site, you can activate the plugin directly in the WordPress Dashboard, and instantiate the class anywhere in your installation. Or, if you’re the developer of a theme or plugin that you’ll be distributing for wide use, you can simply copy the file boones-sortable-columns.php into your own plugin/theme (I recommend a directory called ‘lib’), and then require it manually when you want to do some sortin’.

The plugin is extensively documented inline. I highly recommend that you crack open the source if you have questions about the kinds of options that Boone’s Sortable Columns provides. But, as a quick introduction, here’s a simple example of how you might use the class in your own plugin. Let’s say you have a custom post type called ‘restaurant’, and you want to display a list of restaurants that is sortable by restaurant name, the date when the restaurant was added to the site, and the name of the person who submitted the restaurant (the post author). Here’s the code you might use for a simple table, with my comments and explanations inline.

[code language=”php”]
// Include Boone’s Sortable Columns. You only need to do this if you’re not running it as a
// standalone plugin. Obviously, you’ll need to put the proper path for your plugin.
require_once( WP_CONTENT_DIR . ‘/my-plugin-name/lib/boones-sortable-columns.php’ );

// Define an array of column data.
// For more details on these (and more!) arguments, see the plugin’s inline docs.
$cols = array(
array(
‘name’ => ‘title’,
‘title’ => ‘Restaurant Name’,
‘css_class’ => ‘restaurant-name’,
‘is_default’ => true
),
array(
‘name’ => ‘author’,
‘title’ => ‘Creator’,
‘css_class’ => ‘creator’
),
array(
‘name’ => ‘date’,
‘title’ => ‘Date Added’,
‘css_class’ => ‘date-added’,
‘default_order’ => ‘desc’
)
);

// Create the sorting object based on this column data.
$sortable = new BBG_CPT_Sort( $cols );

// Use some of the data from the $sortable object to help you build a posts query.
// In this example, I’ve intentionally chosen sortable options that can be passed directly to the
// ‘orderby’ param, because they are accepted directly by WP_Query (see http://codex.wordpress.org/Function_Reference/WP_Query#Order_.26_Orderby_Parameters for more details).
// In real life, your query might require something more complex, like the building of a meta_query.
$query_args = array(
‘post_type’ => ‘restaurant’,
‘orderby’ => $sortable->get_orderby,
‘order’ => $sortable->get_order
);

// Fire the query
$restaurants = new WP_Query( $query_args );

// Now let’s create the table markup. Here’s where the magic really happens.
?>

have_posts() ) : ?>

have_columns() ) : ?>
have_columns ) : $sortable->the_column() ?>

have_posts() ) : $restaurants->the_post() ?>

“>the_column_title() ?>

[/code]

Boone’s Sortable Columns handles everything else for you. It figures out what the current orderby/order parameters are. It figures out what the href on the column headers should be. It even creates CSS selectors for the <th> element that match what WP itself uses in the ‘widefat’ tables on the Dashboard, so that you can take advantage of all the pretty JS and CSS built into the WP admin interface. In fact, if this were a Dashboard page, you could simplify the <thead> described above as follows:

[code language=”php”]

have_columns() ) : ?>
have_columns ) : $sortable->the_column() ?>
the_column_th() ?>

[/code]

The method the_column_th() will build the markup for you. Ain’t that the bee’s knees?

Together with Boone’s Pagination

Boone’s Sortable Columns is made more scrumptious when combined with Boone’s Pagination. Here’s a compressed (uncommented) version of the example above, this time with some pagination code.

[code language=”php”]
require_once( WP_CONTENT_DIR . ‘/my-plugin-name/lib/boones-sortable-columns.php’ );
require_once( WP_CONTENT_DIR . ‘/my-plugin-name/lib/boones-pagination.php’ );

$cols = array(
array(
‘name’ => ‘title’,
‘title’ => ‘Restaurant Name’,
‘css_class’ => ‘restaurant-name’,
‘is_default’ => true
),
array(
‘name’ => ‘author’,
‘title’ => ‘Creator’,
‘css_class’ => ‘creator’
),
array(
‘name’ => ‘date’,
‘title’ => ‘Date Added’,
‘css_class’ => ‘date-added’,
‘default_order’ => ‘desc’
)
);

$sortable = new BBG_CPT_Sort( $cols );

$pagination = new BBG_CPT_Pagination();

$query_args = array(
‘post_type’ => ‘restaurant’,
‘orderby’ => $sortable->get_orderby,
‘order’ => $sortable->get_order,
‘paged’ => $pagination->get_paged,
‘per_page’ => $pagination->get_per_page
);

$restaurants = new WP_Query( $query_args );

$pagination->setup_query( $restaurants );
?>

have_posts() ) : ?>

have_columns() ) : ?>
have_columns ) : $sortable->the_column() ?>

have_posts() ) : $restaurants->the_post() ?>

“>the_column_title() ?>

[/code]

Sweet, huh? If you want to see some real-life, more complex examples of Boone’s Pagination and Boone’s Sortable Columns in use, check out Invite Anyone (where the data is a custom post type, as in the example above – see method invite_anyone_settings_mi_content()) or Unconfirmed (where the data actually comes from a custom query of the wp_signups table – look for the admin_panel_main() method).

You can get Boone’s Sortable Columns from the wordpress.org repo or follow its development on Github.

New WordPress plugin: Unconfirmed

If you’ve ever been responsible for supporting an installation of WordPress Multisite with open registration, you know that the activation process can be a significant source of headaches. Sometimes activation emails get caught by spam filters. Sometimes they are overlooked and deleted by unwitting users. And, to complicate matters, WP’s safeguards prevent folks from re-registering with the same username or email address. This can result in a lot of support requests that are not particularly easy to handle. Aside from reaching manually into the database for an activation key, there’s not much the admin can do to help the would-be member of the site.

The Unconfirmed Dashboard panel

The Unconfirmed Dashboard panel

My new WordPress plugin Unconfirmed eases this problem a bit, by providing WPMS admins with a new set of tools for managing unactivated registrations. (By naming it “Unconfirmed”, I fully expect that the plugin will join some great movies and books in the pantheon of Important Cultural Objects.) Unconfirmed adds a new panel to your Network Admin Dashboard (under the Users menu). When you visit the Unconfirmed panel, it gives you a list of all pending registrations on your system. The list is easily sortable by registration date, username, email address, and activation key. For each unactivated registration, there are two actions that the admin can perform. “Resend Activation Email” does exactly what it says: it sends an exact duplicate of the original activation email, as created by the WordPress core activation notification functions. “Activate” allows admins to activate a pending registration manually, which will trigger the activation success email to the user.

At the moment, Unconfirmed is compatible with WordPress Multisite (aka Network mode) only. In the future, I may expand the plugin to work with non-MS installations of WP. Unconfirmed works with BuddyPress, too. The plugin was developed for use on the CUNY Academic Commons.

Download Unconfirmed from the wordpress.org repo or follow its development on Github.