Tag Archives: BuddyPress

“Posts per page” dropdown for BuddyPress single forum topic view

This morning I whipped up a little BuddyPress ditty for the CUNY Academic Commons that allows your members to select how many posts they’d like to see at a time when viewing a single forum topic. It’s not particularly beautiful (for one thing, it requires Javascript to work correctly, though it degrades gracefully by not showing up when no jQuery is available). For that reason, it’s probably not really appropriate for distribution in BuddyPress itself, at least not without some heavy cleanup. Anyway, here it is:

In your theme’s functions.php, place the following function:

[code language=”php”]
/**
* Echoes the markup for the “number of posts per page” dropdown on forum topics
*/
function cac_forums_show_per_page_dropdown() {
global $topic_template;

// Get the current number, so we can preselect the dropdown
$selected = in_array( $topic_template->pag_num, array( 5, 15, 30 ) ) ? $topic_template->pag_num : $topic_template->total_post_count;

// Inject the javascript
?>

jQuery(document).ready( function() {
jQuery(‘div#posts-per-page-wrapper’).show();
jQuery(‘select#posts-per-page’).change(function(){
var url = ‘?topic_page=1&num=’ + jQuery(this).val();
window.location = url;
});
});

Posts per page:

They’ve got Wally covered

We came back from a mini-vacation in Wisconsin yesterday to find a package on our table addressed to Wally. Inside was this beautiful quilt:

The very cute card was inscribed, in part: “Commissioned by Paul Gibbs. Made by Andrea Rennick”. Paul and the Rennicks are a few of my friends from the WordPress and BuddyPress world, each of whom I’ve met in person exactly once. Lately there has been no shortage of reminders that online friends are the real deal; having some of that kindness directed toward me and my family brings it all home. It’s a nice reminder that our geographical distribution – Paul is in Old Blighty, and the Rennicks are in the frozen north – doesn’t change the fact that we’re real coworkers, and real friends.

As a bonus, you can check out a set of making-of photos.

Thanks, Paul, Andrea, and Ron!

Building a baby photo site with WordPress

My wife and I just had our first baby, which is the occassion for much nachas and, by extension, picture sharing. Facebook is, for better or for worse (emphasis on the latter), the de facto place for such sharing to happen. For a number of reasons – a desire to be somewhat selective about who sees my family pictures, my Project Reclaim sensibilities, the fact that I don’t have a Facebook account and generally think that Facebook is an evil company – I don’t want to use FB for this purpose. As in the case of my Twitpic-like photoblog, I figured I could use WordPress to set something up that was nearly as seamless as Facebook, or Google+, or Flickr, or whatever.

The criteria

There were a few things I wanted out of the baby site.

  1. Easy (or zero) login for users
  2. Control over who has access
  3. Optional email notification for new content
  4. Easy, javascripty gallery browsing

When I started, I was pretty sure that I’d be able to get all of these things pretty easily, using existing WordPress plugins. I was both right and wrong about this: plugins exist for all of these purposes, but none of them were very easy to implement. As a result, I ended up building several pieces from scratch. I’ll go through each of the criteria, talk a bit more about what I was looking for, and then say something about how it was achieved. By doing this, and sharing the code (spoiler alert: https://github.com/boonebgorges/Hard-G/tree/master/wp-content), I’m hoping that I can help others with similar sensibilities to get started on their own sites.

Non-sucky registration and login

I love WordPress, and I understand the important reasoning behind the decisions that led to the design, but WP’s user registration system sucks. I didn’t want just anyone to be able to create and activate an account. I didn’t want users to have to click an activation link. I didn’t want users to have randomly generated passwords that would need changing later on. And I wanted users to have the option of logging in a non-WP way.

Several of these problems could be solved by using Facebook logins. I’m not willing to give my photos over to the horrific FB leviathan, but I’m happy to piggyback on their login APIs if it will save my family and friends a few headaches. I wanted my users to have the option of clicking a single button that would give my site the ability to provision them based on their persistent Facebook login.

I started by looking at some popular Facebook Connect plugins from the wordpress.org plugin repository. I didn’t really like them. Most were linked to the Comments section of blog posts, while I wanted to use the logins for overall site access. Most were dependent on Javascript for logins, while I wanted to handle logins on the server side. Most used an outdated version of FB’s API (or at least of the PHP API classes that FB offers). And, to be blunt, most were too much of a mess, having been retrofitted many times over, and as a result next to impossible to extend. I tried modifying one or two of the more popular FB-WP plugins to do what I wanted, but I ended up writing so much garbage spaghetti code that I decided to cut my losses and start from scratch.

So I boned up a bit on the FB API, and wrote a small plugin that I call Wally Login. Together with the registration page template from my custom theme (a child of TwentyEleven), it does a couple of key things.

Your choice

Your choice

  • Rudimentary access control · If a non-logged-in user tries to visit any page on the site (other than the registration page), he is redirected to the Register page.
  • FB login integration · If a user clicks the “Log me in using Facebook” link, they’re directed to the FB authorization page for my website (which is registered as a Facebook app). There, they’re asked to approve the app – a one-time process – and are then returned to my site. Based on the display name, email address, etc that I get from FB, I create a WP user corresponding to the FB account. On future visits, approved users who are logged into Facebook will be automatically logged into my WP site whenever they visit it (an important point, because FB cookies are persistent over browser sessions, while WP logins, by default, are not). As a result, in the best-case scenario, a user will authorize their FB account with my site one time, and will never again have to think about authorization on Wally’s page.
  • A customized WP registration process · If users opt not to go the FB route, they can create a WP account directly on the site. I wanted to avoid sending users to an unthemed wp-login.php or wp-signup.php page, so I cribbed a few lines of code from BuddyPress and made my own registration and login dialogs. Wally’s site is part of a larger WP network, but I wanted to bypass WPMS’s built-in registration stuff (which requires users to activate their accounts, and is thus generally too hard for newbies to grok). My custom registration therefore creates the user directly (with wp_insert_user()), using a password that he provides, and skips the activation email. (By bypassing account activation, I’m removing an important spam prevention tool. More on that in the next section.)
  • Customized email notifications · Because I’m not using the built-in registration process, I needed to write my own email notifications for account applications and approvals.

If you decide to use my code, keep in mind that it’s not particulary beautiful. I wrote it for my own use, which means that it will take a bit of elbow grease to get it to work on your own site. In particular, if I were writing something for more general distribution, I would not be so reliant on a theme template as I am here. But if you’re looking to create a site like mine, this code is a great place to start – especially the FB integration stuff, which has made the registration and login process about as smooth as it can get.

Access control

The final important thing that the Wally Login plugin does is to provide me (the site admin) with control over who has access to the site. There are a couple ways I could have approached this issue. One is to whitelist users ahead of time. The problem with this is that I’m bound to forget some names, get email addresses wrong, and run into other problems that stem from my unfortunate lack of omniscience. Another strategy is the invitation code. When unique to the individual, this method suffers from the same drawbacks of the whitelist; when non-unique (ie when everyone uses the same invitation code) it takes away much of the security, as the code can be passed around quite easily; either way, invitation codes are clunky, easily misplaced, and all too often mistyped.

Thanks for applying

Thanks for applying

As a result, I ended up going with a third option: an application and approval process. Here’s the idea, conceptually. Anyone who wants can create an account on my site (either through Facebook or natively; see the previous section). However, the account does not actually allow access to the site unless the account is also approved by the administrators. Thus, after the initial application, two emails are sent: one to the applicant saying “thanks for applying, please be patient”, and one to me saying “there’s a new applicant, please approve them”. Then I go to my approval interface and click the Approve button (if I want), which marks the user as approved in my database and sends them an email saying “You’re in!”

Here’s a brief description of how it works technically. All applicants have a WP account created for them. Every new account is marked, at the time of creation, with user_status = ‘2’, and I make sure that no page other than Register can be viewed by an account with user_status = ‘2’. In this way, I am turning the idea of activation around a bit – natively, WP makes the user do the activation, but in my case I do it. The admin tool I use to activate users is my Unconfirmed plugin, designed for a slightly different purpose but quite at home here. (For technical reasons, Unconfirmed needs users to have activation keys; thus Wally Login also generates some dummy keys during the user creation process so that Unconfirmed will work right.) Unconfirmed, in turn, does the work of flipping user_status to 0 upon approval.

Taken together, Wally Login and Unconfirmed (with custom WP registration, FB integration, user approval by admin, etc) has given me a comfortable level of access control, without making the process unduly difficult for my users.

Email notification for new content

One of the biggest drawbacks of creating a standalone picture site instead of using an all-purpose social network (in practice, this means Facebook) is that the standalone site is likely to be forgotten. FB collects all of your network’s activity into a single stream; it’s highly unlikely, on the other hand, that Wally’s site will become part of anyone’s daily routine, so that they stop by to check for new content. For that reason, good email notification of new content is essential to making the site work.

Dead simple email subscription

Dead simple email subscription

I first tried using the popular Subscribe2 to handle these notifications. But I ran into a bunch of problems. For one thing, I didn’t like that S2’s subscription management happened in the Dashboard – I want to keep my users on the front end. S2’s category-based subscription is too complicated for my site, where people are either going to want to subscribe to all posts or to none at all. And the widget that comes with S2, for display on the front-end of the site, is pretty much atrocious. (Sorry. The rest of the plugin is nice. But that widget sucks.) At first I tried solving these problems just by building my own widget for S2, one that would tell the user whether he was currently subscribed, and show an Unsubscribe/Subscribe button, as appropriate. But, given the structure of S2’s data (which is somewhat arcane, and in any case far too complicated for my purposes), it ended up being a lot harder than it should have been.

So – wait for it – I wrote something from scratch. It is dead simple. Two parts: (1) a widget, which does exactly what I describe in the foregoing paragraph; and (2) hooks into publish_post to send an email to all subscribed users (along with some gentle checks to make sure dupes are not sent). This plugin has no admin UI and no options, because I don’t need any of those things.

Pretty galleries

Since the main point of the site would be to look at lots of pictures, it was quite important to have an easy, pretty way to do so. By “easy” I mean, primarily, navigable by keyboard; by “pretty”, I mean, primarily, bigger than the content area of a typical blog post. Less important, but still desirable, was the admin interface: I wanted it to be easy to upload lots of pictures at once, to add captions and other metadata if necessary, and to turn it all into a gallery that would look good on the front end.

Pretty, easy

Pretty, easy

You know the drill: I tried a couple of the more popular free plugins, but all of them were annoying in one way or another, and each one was way overengineered for my meager needs. I was especially disappointed by the back-end admin for the popular gallery plugins, which I found lugubrious, unintuitive, and impossible to extend. After some consideration, I decided that I actually preferred WP’s native Add Media interface for uploading photos and adding metadata, and that I was perfectly happy with the way that WP’s gallery shortcode displayed content on the front end, at least when viewing thumbnails.

So the only thing I really needed was to implement the javascript that would allow for keyboard navigation and lightboxing of gallery photos. Thanks in part to his extremely uncreative and literal plugin naming schema, I found Viper007Bond’s jQuery Lightbox For Native Galleries plugin. It does almost exactly what I want, right out of the box.

I did make a few minor mods, though. First, the plugin is a bit greedy in the way that it filters the output of get_attachment_link(), which was either breaking things (as in the case of comment_post_redirect on attachment posts) or making it hard to display links to the attachment page instead of the raw attachment file. The former problem I solved with a filter; for the latter problem, I was a bit lazy, so I modded the plugin itself in addition to adding an explicit ‘lightbox’ class to attachment links. This combination of hacks makes it work perfectly for my purposes.

Odds and ends

A little bonus

A little bonus

With my absolute requirements met, I was able to add a few other goodies to the site. My theme is a child of Twenty Eleven, which I’m pretty much using as-is. But I’ve added a few fun bits. First, on each attachment page, I added Download links, so that users could download images of various resolutions for printing or editing. I messed with the WP Admin Bar so that users coming from Facebook wouldn’t see Log Out and some other inappropriate links. And under each thumbnail in Gallery view, I’ve added Download/Comments links, so that users could bypass the jQuery lightbox and go straight to the attachment permalink if they wanted.

It took some work, but I think I’ve ended up with a site that is nice to use and easy to maintain, without resorting to the extreme discomfort associated with Facebook. Hooray!

Unconfirmed 1.2: non-Network support; delete options

I’ve just tagged version 1.2 of Unconfirmed, my WordPress plugin that allows for easy management of unactivated registrations on your WP site.

Unconfirmed 1.2 has two new, handy features:

  • WordPress non-Network support Previous version of Unconfirmed supported only WP Multisite (Network mode). That made sense, because WP “single” does not have native support for user activation in the same way that MS does. However, BuddyPress, when run on WP “single”, apes Multisite’s activation functions, and in those cases, it makes sense to use Unconfirmed. Version 1.2 introduces support for this kind of setup.
  • A “delete” option A lot of people have asked for a “delete” button, which would allow admins to delete unactivated registrations altogether (usually used in case of spam registrations). In Unconfirmed 1.2, those wishes have been granted. The new version allows you to delete spam registrations, one at a time or in bulk.

Download Unconfirmed from the wordpress.org repo, and follow development at https://github.com/boonebgorges/unconfirmed.

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.

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: 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.

Invite Anyone 0.9: Admin management and stats

Stats

Stats

I just released version 0.9 of Invite Anyone. IA is a a BuddyPress plugin that lets users send email invitations to friends who may be interested in joining the site. IA has always kept track of sent invitations at the user level, but there’s never been a good way for get an overall administrator’s view of invitations – until now.

Invite Anyone 0.9 includes a revamp of the plugin’s Dashboard panel, including two brand new tabs. Manage Invitations lets administrators see all of the invitations that have been sent on the system, complete with sortable columns for easy lookups. And Stats lets you see, at a glance, how successful your invitation campaigns are going. Bonus: If you’ve got CloudSponge integration turned on – which you should really try, as it’s a great driver of traffic and membership – CS-specific invitations are broken out into separate Stats columns, allowing you to compare overall invitation acceptance rates with those coming from CloudSponge.

Download Invite Anyone.

Announcing BuddyDrop

//

Hopefully, readers of this blog will know that I have a keen interest in social software. For some time, I’ve been
a leader in the development of BuddyPress, a plugin that lets users take control of their social networking ex-
periences. Up to now, I’ve focused on BuddyPress http://buddypress.org, the free plugin for WordPress that
puts a number of social networking features on top of an existing WP installation. I love WordPress;
yet lately I’ve been wondering if there’s a way for BuddyPress to break free of some of the WP’s inherent limitations.

BuddyDrop

BuddyDrop

And so today, I’m making my move, and announcing an exciting new project: BuddyDrop. BuddyDrop is a
port of BuddyPress to Drupal, and represents a move away from WordPress-centric development and into the
realm of truly powerful content management. WordPress has been, without question, an outstanding
incubator for BuddyPress. But WP has also held BP back. The move to Drupal introduces true CMS features,
like global taxonomies and fine-grained user access control, that are the foundation of the best social software.

Fans of BuddyPress may greet this news with mixed emotions. BuddyPress development will probably carry
on, at least for a while. For now, I’m leading the BuddyDrop development team, but I won’t be alone: a number of
other prominent members of the BuddyPress and WordPress development communities will be announced in the weeks
leading up to our initial beta release. I’m confident that, as they experiment with Drupal and BuddyDrop, devs and
site owners will migrate their sites, and their development resources, from BP to BD.

Don’t want to wait for the first public beta of BuddyDrop, scheduled to be released in the first part of May? I’m accepting
a small number of applications for a private alpha testing phase that will begin in a week or so. If you’re interested,
you can sign up by visiting buddydrop.com, where you’ll also find screenshots and learn more about BuddyDrop.