Author Archives: Boone Gorges

Setting up a WordPress/BuddyPress development environment on OS X

A local development environment is a collection of software and files on your local computer that replicates a server environment. There’s a number of reasons why doing web development in a local environment and then pushing it to a remote server is a good idea:

  • Convenience: You don’t need an internet connection
  • Speed: Because you’re not transferring files remotely, there’s no save or reload lag
  • Power: You have total control over the environment, in a way you don’t on, eg, shared hosting
  • Safety: You can set up as many parallel environments as you’d like on your local machine, and if you destroy one of them, you can wipe it out and replace it in just a few clicks

I just got a new computer and so have been going through the process of rebuildling my local dev environment. For the benefit of those just getting into web development, here’s how I set it up, with a bit of explanation. Keep in mind that I’m working with OS X 10.6, developing for WordPress; if you’re running a different operating system, or developing for a non-PHP based framework, your setup will differ from mine.

  1. Create a /sites directory: To make navigation from the command line a bit easier, I like to keep all my development environments in first-level directory called sites. Open a Terminal window and type:
    [code language=’text’]mkdir /sites[/code]
  2. Download and install MAMP: Strictly speaking, MAMP isn’t required on OSX, since the OS comes with Apache, MySQL, and PHP installed (enabled through System Preferences > Sharing > Web Sharing). But MAMP has a nice preferences interface, and comes with useful tools like PHPMyAdmin, so I use it. Get MAMP and install it.
  3. Configure MAMP: Open MAMP and click the Preferences button.
    • Configure Start/Stop. I like to uncheck the “Stop servers when quitting MAMP” box, so that I don’t have to keep MAMP open all the time.
    • Switch the ports. You can use the port settings that MAMP comes preconfigured with, but I like to change it because it can make managing domain names a bit easier. Click “Set to default Apache and MySQL ports”. The downside of changing this setting is that each time you start up MAMP (for me, that’s every time I start the computer, which is once every week or so), you’ll need to type in your OSX administrator password. That’ll happen when you save your settings at the end of this step, too – don’t be alarmed.
    • Switch the Apache root directory. On the Apache tab, change the root directory to /sites.

    When you click on OK to save your preferences, you will probably be asked for your admin password. Your local environment is now up and running, and it’s time to configure it to handle WordPress.

  4. Configure your hosts file: By default, you can reach your local installation in a browser by visiting http://localhost or http://127.0.0.1. The first option doesn’t work very well with WordPress (WPMU, at least), and the second one isn’t very attractive. We can set up a more attractive host name by editing the /etc/hosts. Open /etc/hosts, ideally at the command line with
    [code language=’text’]sudo nano /etc/hosts[/code]
    ‘sudo’ is important here, as you’ll need admin rights to change this file. Modify the line that says
    [code language=’text’]127.0.0.1 localhost[/code]
    so that it says
    [code language=’text’]127.0.0.1 localhost boone.is.awesome[/code]
    Now clearly you don’t have to use ‘boone.is.awesome’ (though you probably should, because I am awesome). You can use any combination of words you want, separated by periods, like a URL – ‘local.dev’, perhaps. Don’t use a real URL. Save the file (if you’re at the command line, hit Ctrl-X, and then Y when you’re prompted to save) and test your new hosts file by visiting http://boone.is.awesome (or whatever) in a browser window.
  5. Create a database: In MAMP, click the “Open Start Page” button, which will open the MAMP start page in the browser. Click on the PHPMyAdmin link on the start page. PHPMyAdmin is a graphical interface for your MySQL database that you might find handy as you do development. Click the Databases tab, and create a new database – I’m calling mine ‘wp-trunk’. You may also want to choose a default text encoding: ‘utf8_general_ci’ works pretty well if you think you might be doing development in different character sets (Cyrillic, Arabic, etc).
  6. Download WordPress: I like to get WP via SVN, which makes it easy to keep track of any core hacks I might make. Here are the Terminal commands to create an installation called ‘wp-trunk’:
    [code language=’text’]cd /sites
    mkdir wp-trunk
    svn co http://core.svn.wordpress.org/trunk wp-trunk/[/code]
    You’ll see a bunch of files being downloaded. In this example I’m downloading the trunk, or development, version of WP, rather than the stable version. If you’d like to get a specific version, say 2.9.2, use svn co http://core.svn.wordpress.org/tags/2.9.2 wp-trunk/ instead. (More on using svn with WordPress, from Mark Jaquith)
  7. Install WordPress: In your browser, go to http://boone.is.awesome/wp-trunk (or the corresponding path on your machine). This should load the WordPress installer. If you’ve followed along with my instructions, the settings in this image ought to work for you. You’ll notice that I’m using the root MySQL account, with the default password, because it automatically has all privileges on all databases. You should obviously never do this on a database that is connected to the internet. I should also note here that I’m installing the beta of WP 3.0, but the same process will work for any version of WP, even WPMU. With MU, though, you may have some problems if you choose the subdomains option for secondary blogs.
  8. That’s it! You should now be able to log into your installation at http://boone.is.awesome/wp-trunk/wp-admin. When I plan to use an installation of WP to develop for BuddyPress, I check out the trunk version of BP in a similar fashion to step 6:
    [code language=’text’]cd /sites/wp-trunk/wp-content/plugins
    mkdir buddypress
    svn co http://svn.buddypress.org/trunk buddypress/[/code]

Adding an “email to members” checkbox to the BuddyPress group activity stream

During the recent upgrade from BuddyPress 1.1.x to BuddyPress 1.2.x, and the subsequent move away from group wires to interactive group activity streams, one thing that some users on the CUNY Academic Commons missed was the “Notify members by email” checkbox of the old wire.

This morning I wrote a bit of code to add that kind of functionality to group activity streams. There are three functions, each of which goes in your plugins/bp-custom.php file.

First, adding the checkbox to the activity box. Notice that it only shows up when you’re on a group page.

[code language=’php’]

function cac_email_activity_checkbox() {
if ( !bp_is_groups_component() )
return;
?>


Second, handling the data when it gets to the server and sending the emails. Obviously, you’ll want to change the text of the email to match your own site and your own preferences. The line “remove_action( ‘bp_activity_after_save’ , ‘ass_group_notification_activity’ , 50 );” is there to prevent an email notification from being sent if you’re using the Group Activity Notification plugin, a big official release of which is coming soon 🙂

[code language=’php’]

function cac_email_activity_handler( $activity ) {
global $bp;

if ( $_POST[‘mailme’] == ‘mailme’ ) {

$subject = sprintf(‘[CUNY Academic Commons] New update in the group “%s”‘, $bp->groups->current_group->name );

$message = strip_tags($activity->action);
$message .= ‘

‘;
$message .= strip_tags($activity->content);

$message .= ‘

——-
‘;

$message .= sprintf(‘You recieved this message because you are a member of the group “%s” on the CUNY Academic Commons. Visit the group: %s’, $bp->groups->current_group->name, $bp->root_domain . ‘/’ . $bp->groups->current_group->slug . ‘/’ . $bp->groups->current_group->slug . ‘/’ );

//print_r($message);

if ( bp_group_has_members( ‘exclude_admins_mods=0&per_page=10000’ ) ) {
global $members_template;
foreach( $members_template->members as $m ) {
wp_mail( $m->user_email, $subject, $message );
}
}
}

remove_action( ‘bp_activity_after_save’ , ‘ass_group_notification_activity’ , 50 );
}
add_action( ‘bp_activity_after_save’, ‘cac_email_activity_handler’, 1 );
[/code]

Finally, you’ll need some Javascript to make the AJAX activity submission work correctly. This is really just a copy of what’s in the bp-default JS file, with a few added lines to make it work.

[code language=’php’]
function cac_email_activity_js() {
if ( !bp_is_groups_component() )
return;
?>

var jq = jQuery;
jq(document).ready( function() {
jq(“input#aw-whats-new-submit”).unbind(‘click’);
/* New posts */
jq(“input#aw-whats-new-submit”).click( function() {
var button = jq(this);
var form = button.parent().parent().parent().parent();

form.children().each( function() {
if ( jq.nodeName(this, “textarea”) || jq.nodeName(this, “input”) )
jq(this).attr( ‘disabled’, ‘disabled’ );
});

jq( ‘form#’ + form.attr(‘id’) + ‘ span.ajax-loader’ ).show();

/* Remove any errors */
jq(‘div.error’).remove();
button.attr(‘disabled’,’disabled’);

/* Default POST values */
var object = ”;
var item_id = jq(“#whats-new-post-in”).val();
var content = jq(“textarea#whats-new”).val();
var mailme = jq(“#cac_activity_mail:checked”).val();

/* Set object for non-profile posts */
if ( item_id > 0 ) {
object = jq(“#whats-new-post-object”).val();
}

jq.post( ajaxurl, {
action: ‘post_update’,
‘cookie’: encodeURIComponent(document.cookie),
‘_wpnonce_post_update’: jq(“input#_wpnonce_post_update”).val(),
‘content’: content,
‘object’: object,
‘mailme’: mailme,
‘item_id’: item_id
},
function(response)
{
jq( ‘form#’ + form.attr(‘id’) + ‘ span.ajax-loader’ ).hide();

form.children().each( function() {
if ( jq.nodeName(this, “textarea”) || jq.nodeName(this, “input”) )
jq(this).attr( ‘disabled’, ” );
});

/* Check for errors and append if found. */
if ( response[0] + response[1] == ‘-1’ ) {
form.prepend( response.substr( 2, response.length ) );
jq( ‘form#’ + form.attr(‘id’) + ‘ div.error’).hide().fadeIn( 200 );
button.attr(“disabled”, ”);
} else {
if ( 0 == jq(“ul.activity-list”).length ) {
jq(“div.error”).slideUp(100).remove();
jq(“div#message”).slideUp(100).remove();
jq(“div.activity”).append( ‘

    ‘ );
    }

    jq(“ul.activity-list”).prepend(response);
    jq(“ul.activity-list li:first”).addClass(‘new-update’);
    jq(“li.new-update”).hide().slideDown( 300 );
    jq(“li.new-update”).removeClass( ‘new-update’ );
    jq(“textarea#whats-new”).val(”);
    jq(“#cac_activity_mail”).removeAttr(‘checked’);

    /* Re-enable the submit button after 8 seconds. */
    setTimeout( function() { button.attr(“disabled”, ”); }, 8000 );
    }
    });

    return false;
    });
    });

Google Summer of Code, WordPress, and BuddyPress

I’m extremely pleased to announce (after weeks of keeping mum until the official word was released!) that I’ll be co-mentoring several projects for Google Summer of Code and WordPress. For those of you who don’t know, GSoC is an initiative by Google to support summer coding projects by undergraduate and graduate students working on various established open-source projects. WordPress has 15 projects this year, several of which are related to BuddyPress. As a mentor on two of the projects, I’ll be helping to hone the project scopes, do code reviews, and in general lend a hand where I can to my two mentees. Here they are:

I am very excited to get started working with these great students!

More Import from Ning goodness – ( Ning to BuddyPress / WordPress )

As promised in my last post, I’ve reworked the Import from Ning WordPress plugin so that it is BuddyPress-aware. That means that, if you run the plugin on a blog where BuddyPress is activated, additional steps will be added to the import process, allowing you to automatically import whichever profile fields and data you’d like from the Ning export.

I also got rid of the pesky copy-and-paste requirement in favor of a direct .csv file upload.

Check out the plugin at its new homepage.

Importing Ning users into WP

Today Ning announced that it would be ending its free social networking service. I tweeted something to the effect that this event is a wake-up call: When you use closed-source, third-party hosted solutions for something as valuable as community connections, you are leaving yourself open to the whims and sways of corporate boards. It’s not that Ning is evil or anything – it goes without saying that they need to make a profit – but their priorities are importantly different from those of their users. In the same way that Ning moves from a freemium model to a paid model, Facebook could start selling your crap, Twitter could crash, Tumblr could go out of business, etc.

All this is a good argument to be using software solutions that are more under your control. Like – drumroll – WordPress and BuddyPress.

Enough moralizing. I whipped together a plugin this afternoon called Import From Ning that will allow you to get a CSV export of your Ning community’s member list (the only content that Ning has a handy export feature for, alas) and use it to import members into a WordPress installation.

As of right now, it does not have any BuddyPress-specific functionality. But the data that it does import – display name, username, email address – are enough to populate at least the beginnings of a BuddyPress profile. The next thing to add is the auto-import of certain profile fields. I might try to do this tomorrow. The plugin is based on DDImportUsers – thanks!

Instructions:

  • Download the zip file and unzip into your WP plugins directory
  • Look for the Import from Ning menu under Dashboard > Users (unless you’re running a recent trunk version of BuddyPress, in which case it will be under the BuddyPress menu)
  • Follow the instructions on that page

Download the plugin here.

Big new version of Invite Anyone for BuddyPress

My BuddyPress function Invite Anyone has always been misleadingly named. It expanded on BuddyPress’s default setup, which only allows members to send group invitations to people who they’re friends with, by allowing individuals to send invitations to anyone in the entire installation. This only qualifies as inviting anyone on a, er, very austere ontology of personhood. The new version of Invite Anyone, version 0.4, adds a new tab to BuddyPress profile tabs that allows invitation both to groups and to the site in general via email. It’s a big update, both in terms of features and in terms of sheer code (pretty sure the number of lines of code is close to triple what it was before).

And now you know what I did on my spring break.

If you know what’s good for you, you will Check It Out.

Social Media and General Education: My Queens College Presidential Roundtable talk

This week I gave a Presidential Roundtable discussion at Queens College. The talk was titled, somewhat anemically, “Teaching on the Coattails of Text Messages”, though arguably what I was saying didn’t really end up having much to do with text messages! (I justify my being misleading by reference to the fact that the Presidential Roundtable was not in fact a roundtable format.)

The thrust of the talk was that there are important structural similarities between social media like blogs and Twitter (their openness, their relative lack of imposed structure, their focus on audience and emergent conventions, their positioning of the individual as the locus of value and meaning) and the kind of general education that we’re seeking during this year of gen ed reform at QC.

I transcribed the video after the break, mainly so I’d have the text for my own purposes. It’s lightly edited to cut out some of the more egregious ums and ers and actuallys. Video of the talk is below for anyone who is interested. I spoke mostly extemporaneously and said some dumb things, so please be generous in your interpretation!!

Special thanks to Zach Whalen, who generously answered some of my questions about his Graphic Novel class. (And to his students, whose tweets served as fodder!)

Teaching on the Coattails of Text Messages from Boone Gorges on Vimeo.

Continue reading

Moving on

This week I resigned my position as instructional technologist at Queens College. May 27 will be my last day.

My main reason for leaving is my dissertation, or rather my lack of dissertation. I’ve been done with graduate classes for longer than I care to admit, with nothing between me and the degree but the dissertation (as if it were a small thing!). During my time at Queens College – two years as a CUNY Writing Fellow followed by two years as a full-time instructional technologist – I managed to consistently use the job as an excuse not to work on philosophy to the extent that I should. I plan to continue doing web development for the CUNY Academic Commons and elsewhere while I work on my thesis.

Вперед!

Вперед!

As a number of my dear readers are already aware, the path leading to my decision was paved with self-doubt and second guessing. Obviously, there is the stress of going from having a full-time job (and paycheck) to not having one. More surprising, to me at least, have been the nagging misgivings about my relationship with the world of educational technology.

Like a lot of other people I know in the field, I entered edtech on accident. But over the last four years I have found a place in several different kinds of communities built around the intersection of technology and the classroom: communities at Queens College, across CUNY, and beyond. To the extent that leaving day-to-day instructional technology means distancing myself from those communities, I am very sad to do so.

As for the work itself? Here my feelings are more mixed. Certainly the high points of the job have been quite high indeed: working in close collaboration on meaningful projects with great people. But even during the good times I’ve always had a lurking feeling (which has occasionally crossed my lips in mixed company!) that the position itself was an unnatural one. It’s in a broken system – mediocre software, insufficient resources, unthoughtful pedagogy, a stagnant culture surrounding the relevance of digital technology in the university – that the instructional technologist flourishes. Like a doctor or a plumber or a parent, a big part of my job was to get people not to need me anymore.

That’s not to say that edtech is somehow pointless, anymore than it is to suggest that medicine or plumbing repair or parenting are without value. You might even argue that a field that arises out of such genuine need deserves to exist even more in virtue of that very fact. And so it probably is with edtech. Still, a sort of (mild) existential angst has plagued me since I took the job, a feeling that I’ll be glad to leave to my more intrepid colleagues.

I have enormous respect for people doing the extremely important job of on-the-ground edtech. That I will be respecting from a distance leaves me feeling bittersweet. But mostly I’m excited, to watch, as an outsider, how the field evolves in the upcoming years. In the meantime, I’ll be being productive in new ways!

Вперёд!