Tag Archives: BuddyPress

Five years of BuddyPress

I started working with BuddyPress by accident. In February 2009, I responded to a tweet from my friend Matt Gold asking for help with a CSS issue on a site he was working on. That site was the still-in-beta CUNY Academic Commons, running on the still-in-beta BuddyPress. Within a few weeks, I was doing paid work for Matt’s project, working with BP (and WP, and web software in general) for the first time. And BuddyPress 1.0 came out just a few weeks after that.

Over the last five years, BuddyPress has taken over my professional life. I began by writing BP plugins. I started to contribute to BP itself through support and patches. I became a member and eventually a lead on the core team. My consultation work involves BuddyPress almost exclusively; this success (in terms of both money and impact) emboldened me to drop out of graduate school. People know me as “the BuddyPress guy”. When you type “boone gorges” into Google, it suggests “boone gorges buddypress”.

I feel very grateful to have stumbled into the project when I did. It aligns with many of my philosophical and political positions: the primacy of people over content, the importance of data ownership and free software, the fight against parasitic software vendors in public institutions. I’ve met some good friends through my association with BP. I’ve leveraged my expertise into a fun and comfortable career.

But the fact remains that it’s all been a fluke. When I realized it’s been five whole years, I couldn’t shake the thought: WTF. How strange to devote such a large part of one’s life to something that was such an accident. [Something something destiny something something forks in the road something.] I got lucky because I happened to stumble into something that was a particularly good fit for me. But I also took many leaps of faith along the way: agreeing to work on the CUNY Academic Commons when I had pretty much no idea what I was doing, submitting my first patches to BP, quitting my job, upping my rates, donating huge amounts of time to the free project instead of doing paid client work. I’m glad I had the guts to make each of these leaps.

Happy birthday to BuddyPress, and happy anniversary to me. Here’s to many more happy accidents!

Any major dude with half a heart surely will be at WordCamp Connecticut on May 10

A few months ago, I had the pleasure of speaking at the WordPress Stamford Meetup, organized by Clint Warren. I musta put a bug in his ear or something, because I got a follow-up email last month letting me know he was organizing the very first WordCamp Connecticut. I’ll be giving a talk about BuddyPress.

The organizers are still looking for speakers, so if you’re a WordPress person in the CT vicinity (Stamford is an easy Metro-North ride from NYC), please consider applying to present! And if you’re just looking to nerd out for a day, add yourself to the mailing list so you’ll know when tickets are available. DO IT

Default Gravatar images and SSL

I have a client who runs a number of WordPress/BuddyPress sites over SSL. He noticed in the last few days that default Gravatar images – the images that Gravatar serves when there is no Gravatar associated with the queried email address – were not being served. The browser showed broken images, and when you attempted to load the associated https://secure.gravatar.com URL in a separate tab, you’d see the message “We cannot complete this request, remote data could not be fetched”.

After a bit of futzing around, I found this recent post by Eric Mann describing a similar issue with the Photon CDN feature in the Jetpack plugin. He managed to figure out that Automattic’s CDN service wasn’t fetching items that were served over HTTPS. (The fact that it ever worked was, apparently, a bug; that “bug” was recently fixed.)

It turns out that the same thing is true for Gravatar’s “Default Image” feature (unsurprising, as I assume it uses the same CDN as Photon). Gravatar lets you specify a local file that will be served if no actual Gravatar is found: <img src="https://www.gravatar.com/avatar/00000000000000000000000000000000?d=http%3A%2F%2Fexample.com%2Fimages%2Favatar.jpg" /> But, as of the last few weeks, if the value of the d= param is served over HTTPS only, Gravatar throws an error.

There are a couple strategies for working around the problem.

  • Use Gravatar’s defaults instead – Gravatar hosts a number of default images that you can use, instead of a local image. This is especially pertinent in the case of BuddyPress. BP’s default behavior is to construct Gravatar requests like this: https://www.gravatar.com/avatar/00000000000000000000000000000000?d=http%3A%2F%2Fexample.com%2Fimages%2Fwp-content%2Fplugins%2Fbuddypress%2Fbp-core%2Fimages%2Fmystery-man.jpg. The thing is that this mystery-man.jpg that ships with BuddyPress is the same image as what you get with ?d=mm. So an easy way around the problem of Gravatar reading from your SSL-protected site is to avoid Gravatar from making any requests to your site at all. In BuddyPress, use the following:

    [code language=”php”]
    function bbg_use_gravatar_mm() {
    return ‘mm’;
    }
    add_filter( ‘bp_core_mysteryman_src’, ‘bbg_use_gravatar_mm’ );
    [/code]

  • Allow non-SSL access to your default – As suggested in Eric’s post, you can tell your webserver that some of your content can be served over HTTP rather than HTTPS. For example, on one of the sites I’m working on, we force HTTPS for all requests using an .htaccess rule. I can amend it to allow an exception for the custom Gravatar default:

    [code]
    RewriteCond %{HTTPS} off
    RewriteCond %{REQUEST_URI} !^/wp-content/themes/yourtheme/images/default-gravatar.jpg$
    RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R,L]
    [/code]

    Then, force BuddyPress to tell Gravatar you want the non-SSL version of the fallback:

    [code language=”php”]
    function bbg_custom_default_avatar() {
    return set_url_scheme( get_stylesheet_directory_uri() . ‘/images/default-gravatar.jpg’, ‘http’ );
    }
    add_filter( ‘bp_core_mysteryman_src’, ‘bbg_custom_default_avatar’ );
    [/code]

Even if you’re not using BuddyPress or WordPress, the same strategy applies: if you’re serving your whole site over HTTPS, tell Gravatar to use either one of its own images or one of your non-SSL-available images as its default.

WP-CLI tools for BuddyPress

I think we can all agree that WP-CLI is the cat’s pajamas. Starting today, I’ll be maintaining a small (but growing) library of BuddyPress commands for WP-CLI: wp-cli-buddypress. Available commands are currently quite meager (and quite biased toward my needs as a developer rather than a site admin), but I’ll be building more, and would be delighted to receive pull requests.

Commit messages, tickets, and inline docs

As a Trained Academicâ„¢, I try to think about software documentation in terms of audience and purpose. Who is going to read technical docs? What will they be trying to learn by reading them? I use these questions as a lens for writing different kinds of documentation.

I like to think of commit messages as the canonical technical narrative of the project. These messages matter most for two groups of people: those following the ongoing development of the project, and those intrepid future souls who are combing through logs to track the lineage of given bit of code. The needs of the two groups are similar, which suggests certain content and formatting for commit messages. Both groups are scanning sizable streams of changesets, and thus need a quick way to disregard those that are irrelevant to them. That’s where the one-line summary is helpful, for git log and GUIs like this. Beyond the summary, they usually need a bit more context, a bird’s-eye summary of the problem the changeset is intended to fix. They need pointers to full discussions (ie, linked tickets). And because in projects like WordPress the changelog is also an attribution log, they need reference to the person responsible for the fix (“props”). It’s these kinds of needs I’m thinking about when I structure commit messages like this. (Side note: I’m a big fan of this post arguing for a similar commit message format.)

Tickets are bug notices or feature requests as they appear in the project’s issue tracker. The primary audience here is the developers, designers, and users who are currently involved in the ongoing development of the software. It’s a workspace, and it’s messy. Tickets may contain extended discussions, with numerous digressions and dead-end patches. It’s for this reason that issue tickets are not a replacement for good commit messages. Commit messages contain justification for changesets, while trackers contain the process that led to that justification.

Inline docs, primarily in the form of function/method/class docblocks, are intended first and foremost for developers who are currently trying to figure out how the software works. As a rule, these people don’t care about the history of the project, or the reasoning that led to a given piece of code. The documentation should answer questions like: where is this function used in the codebase? if I put x into the function, what will I get out of it? etc. While it’s often good to have pointers to the project history in certain cases – such as a link to a ticket that explains why an unintuitive bit of code works in the way it does – it probably does more harm than good to litter inline documentation with details about the project’s intellectual history. That’s what blame tools are for.

It goes without saying that there are gray areas. Commit messages, tickets, and inline docs all have the same “text” as their subject: the codebase. And the intended audiences for the three kinds of documentation are frequently overlapping. Still, I think it’s helpful to keep the distinctions in mind. When you write documentation, you’re writing the story of the project as it’ll be understand by future coder-historians. You want to make sure that the story makes sense.

A less finicky BuddyPress search

BuddyPress search, out of the box, is not very good. Say you’re looking for a group called “History of Wars in America”. The search term Wars in America will return the group, but America Wars will not. (Technical reason: search terms get lumped as a single string into a MySQL LIKE clause.)

I have some ideas about how to improve this behavior in BuddyPress itself, including stealing some of the goodies that recently went into WordPress. But for now, here’s a simple drop-in filter that fixes the word-wise problem.

(if the formatting is messed up, view the original at https://gist.github.com/boonebgorges/8301715)

Something very similar would work for members searches, though the query variables passed along to the filters probably have a slightly different syntax. (I made these changes for City Tech OpenLab, whose members queries are custom anyway.)

Again, this filter is not perfect – it doesn’t try to do any caching, it doesn’t look for literal strings in quotes, etc – but you might find it useful until some real fixes are in place in BP.

WordPress/BuddyPress registration and the Office 365 email filter

Just tore through the following problem on a client site (independently discovered by Martha Burtis here). WordPress/BuddyPress sites that allow for self-registration send out emails with activation links of the form: http://example.com/activate/?key=12345 (for BuddyPress) and http://example.com/wp-activate.php?key=12345 (for WordPress multisite). This format trips up the link filter that Microsoft’s Office 365 email service uses. After some experimentation, I figured out that the problem is the word ‘key’ in a URL parameter – once this term is removed from the URL, it passes right through the filter.

So, you can fix the problem by changing the URL parameter in the activation emails. That means (a) changing the text of the email, and (b) changing the server-side logic to expect something other than ‘key’. Here’s how to do it in BuddyPress:

[code language=”php”]
function bbg_activation_email_content( $message ) {
return str_replace( ‘?key=’, ‘?activationk=’, $message );
}
add_filter( ‘bp_core_activation_signup_user_notification_message’, ‘bbg_activation_email_content’ );

function bbg_screen_activation() {
global $bp;

if ( !bp_is_current_component( ‘activate’ ) )
return false;

// Check if an activation key has been passed
if ( isset( $_GET[‘activationk’] ) ) {

// Activate the signup
$user = apply_filters( ‘bp_core_activate_account’, bp_core_activate_signup( $_GET[‘activationk’] ) );

// If there were errors, add a message and redirect
if ( !empty( $user->errors ) ) {
bp_core_add_message( $user->get_error_message(), ‘error’ );
bp_core_redirect( trailingslashit( bp_get_root_domain() . ‘/’ . $bp->pages->activate->slug ) );
}

// Check for an uploaded avatar and move that to the correct user folder
if ( is_multisite() )
$hashed_key = wp_hash( $_GET[‘activationk’] );
else
$hashed_key = wp_hash( $user );

// Check if the avatar folder exists. If it does, move rename it, move
// it and delete the signup avatar dir
if ( file_exists( bp_core_avatar_upload_path() . ‘/avatars/signups/’ . $hashed_key ) )
@rename( bp_core_avatar_upload_path() . ‘/avatars/signups/’ . $hashed_key, bp_core_avatar_upload_path() . ‘/avatars/’ . $user );

bp_core_add_message( __( ‘Your account is now active!’, ‘buddypress’ ) );

$bp->activation_complete = true;
}

bp_core_load_template( apply_filters( ‘bp_core_template_activate’, array( ‘activate’, ‘registration/activate’ ) ) );
}
remove_action( ‘bp_screens’, ‘bp_core_screen_activation’ );
add_action( ‘bp_screens’, ‘bbg_screen_activation’ );
[/code]

You’d have to do something in the same spirit when not using BuddyPress. For the email, filter ‘wpmu_signup_user_notification_email’. Catching the request and overriding ‘key’ will be trickier. I haven’t experimented with it, but maybe you can hook to ‘activate_header’, detect the presence of $_GET['activationk'], and then redirect to the ‘key=’ URL that wp-activate.php expects.

Hopefully this is enough to help if you’re having the problem.

BuddyPress Docs 1.4 and attachment support

I’ve just released version 1.4 of BuddyPress Docs, my collaborative editing plugin for BuddyPress. The big new feature is the one that users have been asking for since the plugin was first released: file attachments. I’m using a nifty trick (involving the autogeneration of .htaccess files) to ensure that Doc privacy levels are extended to their attachments. I think it’s going to be useful to a lot of people.

In the future, I plan to write a tool to migrate content created by the abandoned BP Group Documents to this new system. Stay tuned.

This round of development was generously sponsored by the Center for Applied Research and Environmental Systems at the University of Missouri. They are long-time users of BuddyPress, and they were pleased to support the development of this feature for the community. Special thanks to David Cavins, who set up the connection between me and CARES, and also contributed huge amounts of technical, conceptual, and design help to Docs 1.4. (He also builds beautiful guitars.) Thanks to CARES and to David!

Get your Boone fix

Mostly for my own records, here are a few recent Boone-related videos and interviews from around the web:

  • Code Poet interview – April 18, 2013. In which I speak at length (ramble?) about BuddyPress, the university, and the value of free software
  • WordSesh panel – April 13, 2013. A livestreamed discussion about BuddyPress with John, Paul, Ray, and Tammie.
  • BuddyCamp Miami presentation – April 5, 2013. A brief talk where I talk about how to use BuddyPress’s Group Extension API to add BP features to a WordPress plugin. The slides are at blo.so/bcmia.
  • WPNYC presentation – January 15, 2013. A talk I gave on the big new features in BuddyPress 1.7