Skip to content

New BuddyPress plugin: BP Include Non-Member Comments

07-Feb-10

I wrote a plugin this afternoon that solves a small but potentially annoying limitation of BuddyPress: its inability to show comments from non-members in the sitewide activity stream. In a streak of extreme creativity, I dubbed the plugin “BP Include Non-Member Comments”. Read more about it, and download it for your own use, here.

Class blogrolls: No sweat

25-Jan-10

Last week, in the post where I announced my new WPMU plugin Shared Blogroll, I briefly mentioned the use case that I had in mind, which was of course education-focused. Yesterday and today I did some more work on the plugin itself (MORE AJAX 4EVA) and some of the supporting players. I thought I’d spell it out a little more so that others could implement what is probably the coolest system for shared blogrolls on earth, or at least on WPMU, which amounts to pretty much the same thing.

The plugins

  • Shared Blogroll. This creates a widget that allows bloggers to embed a link category from any other blog on the system on their own blog.
  • Add Users Sidebar Widget. This plugin is already pretty great, as well it should be seeing as it’s written by good-looking Canadians. I made some edits to the plugin to make it a bit more flexible.
    1. First I removed the RSS box from the Add User widget. For most of my users, it’ll confuse; for all of them, it’ll be redundant, since they’ll all be using Wordpress blogs and thus will have feeds that are very auto-discoverable.
    2. As the plugin stands in the repository, links are automatically put into the blog’s default link category (or, if they’re using FeedWordPress, the FWP link category). For most users, that’s something unhelpful like “Links” or “Uncategorized”. I altered the plugin so that the blog owner can choose which link category the added links will be put into. As I’ll discuss below, I think that this will add a lot of flexibility to the way that the plugins can be used together. You can download the text of my modified version of Add Users Sidebar Widget here: add-link-sidebar-widget.txt. Save as .php before uploading – and make sure that you uninstall previous versions of the plugin before uploading, or you might get whitescreened to death.
  • Optional step. The default WP Links widget is set up so that you can’t select to display an empty category of links. As you’ll see below, I want to have instructors create a new category for their blogrolls, and I figured it’d be pretty confusing if they couldn’t create a sidebar widget corresponding to a link category until at least one student had posted a link (thus populating the category). So I wrote a little plugin that replaces the default Links widget with one that allows you to pick an empty links category. Drop this into mu-plugins: link_widget_allow_empty_cat. Be warned, though, that this plugin deregisters the default Links widget, which might have the effect of removing every links widget on your installation of WPMU. (I haven’t tested it.) For me, it’s OK, because I don’t have any active users yet. As an alternative, you could edit the core of WP (making sure to back up, take note of where you made the edit for future upgrades, blah blah blah) in the following way. In wp-includes/default-widgets.php, line 139 reads
    $link_cats = get_terms( 'link_category');

    Replace it with

    $link_cats = get_terms( 'link_category', 'hide_empty=0');

    That should leave all of your pre-existing links widgets in place.

The process

The immediate goal of this setup is to allow a class blogroll to be shared effortlessly between members of a class. (Though I can imagine lots of other very cool uses.) Here are the directions I’m going to give to instructors and students on how to leverage these two plugins to make it happen.

Instructors

  • Create a new Link Category for your class blogroll – let’s say you call it “ENG 110 Blogroll”.
  • Add a Links widget to the sidebar, making sure to select “ENG 110 Blogroll” from the category dropdown.
  • Add an Add Links widget to the sidebar. Again, be sure to select “ENG 110″ blogroll as the target category for added links.
  • Give your blog’s ID number to your students and give them the following directions.

Students

  • After creating a blog, visit the professor’s blog and enter your site’s URL into the Add Link sidebar widget.
  • Add a Shared Blogroll widget to your own blog’s sidebar. Enter the professor’s blog ID number as the source blog, select “ENG 110 Blogroll” from the dropdown list, and Save.

I hope that the instructors and students get into this blogroll sharing thing. It distributes what would otherwise be a huge amount of work for the instructor, or *worse yet*, for me.

New WPMU plugin: Shared Blogroll

21-Jan-10

I just wrote a widget that lets a blog admin pull a link category from any blog on the same WPMU installation. It is pretty much the bomb, and you are going to love using it so much that you may have to take downers in order to get yourself under control.

Check it out.

Side note: I’m going to start creating separate pages (as opposed to posts) for each of my software releases. That way all comments/support regarding a given plugin will be in the same place, with a pretty URL. That’s why I’m turning off comments on this post.

Blog-specific email plugin for WPMU users

21-Jan-10

A quick WPMU hack that I think will help a lot of people using an installation of WPMU for multiple classes.

The plugin Email Users by Vincent Prat allows blog authors/admins to email users in two different ways: 1) by emailing a group of users (such as those corresponding a particular role on your blog), or 2) by emailing individual users. The problem, though, is that this second option brings up a list of every single user on the installation of WPMU. This can be a bit of a pain for the normal blog user, as teachers or students in a class would probably only want to see a list of those people who are in the class, or on the blog.

Here’s a hack that will make the Email Users plugin show list only the members of the current blog for everyone except for the site admin:

  1. In the main plugin file (email-users.php), find the function mailusers_get_users. It should start around line 404.
  2. Look for the lines of code (414-417 in my version) that define the variable $users in the first conditional clause:
    $users = $wpdb->get_results(
    			  "SELECT id, user_email, display_name "
    			. "FROM $wpdb->users "
    			. $additional_sql_filter );
    
  3. Replace that line with the following code:
    if ( is_site_admin() ) {
    			$users = $wpdb->get_results(
    			  "SELECT id, user_email, display_name "
    			. "FROM $wpdb->users "
    			. $additional_sql_filter );
    		} else {
    			$wp_user_search = new WP_User_Search('', '', '');
    			$user_list = $wp_user_search->get_results();
    			$user_array = join(',', $user_list);
    			$users = $wpdb->get_results(
    			  "SELECT id, user_email, display_name "
    			. "FROM $wpdb->users "
    			. "WHERE id IN ( $user_array ) " );
    		}
    

Here’s the use case I envision. The instructor for a class places the Add User Sidebar Widget (by my boys at UBC’s OLT!) in the sidebar of his or her blog. As part of the first assignment of the semester, the instructor asks each student to register for an account, and click the “Add Me” button on the instructor’s blog. That will automatically populate the email list above.

File this tip under “who needs Blackboard?”.

True cross-platform comment syncing with Disqus and Wordpress

13-Jan-10

FeedWordPress works well if you want to syndicate content from various sources into a single Wordpress blog. Syndicating comments is, of course, more difficult. I’m finishing up a job for a client who wanted real-time synced comments, and suggested that Disqus might do the trick. I quickly discovered that Disqus is clearly not made to do what I wanted it to do. But, being the cool guy that I am, I hacked something together that is more or less functional.

Here were the requirements: Comments on a blog post needed to be synchronized between the source blogs and the hub blog. Readers had to be able to comment in both places and have the comments sync. While I’d be using Wordpress to create the hub blog, the source blogs would be hosted on various platforms: Tumblr, Typepad, Blogger, self-hosted Wordpress. (The distributed requirement is especially important. If the blogs were all on the same installation of WPMU, the job would be trivial and would not require a third-party solution like Disqus.) Because bloggers would be coming from different platforms, I not only had to be able to accomodate those platforms, but I also had to make sure that the system would work with the platforms’ stock configuration. That is, since I (and, generally speaking, the bloggers) don’t have access to the platform code, all custom modifications need to happen at the hub blog.

I don’t particularly recommend that anyone try to replicate what I’ve done here. But hopefully it will point the way toward what might be a viable third-party system for true comment syncing.

The details

Here’s my strategy with regard to Disqus. If all the source blogs were registered to the same Disqus Comments account (ie corresponding to a single shortname), then they’d all have the same forum_key, which is to say they’d be accessible by the same API request. Thus the strategy is to make Disqus unable to distinguish between API calls from the source blogs (which are, recall, making stock API calls to Disqus) and API calls from the corresponding posts on the hub blog.

I installed the Disqus Comment System plugin for the Wordpress hub blog and registered with the same credentials that would be given to the source blogs. When feeds starting syndicating to the hub blog, however, I found that the comment sections on the source post weren’t matching the comment section on the hub post. The URL for each comment thread’s RSS feed showed me why: Disqus indexes a forum’s comment thread based on some post information that it gets from the client platform, and each platform was formatting the information in a different way.

First problem: The Wordpress Disqus plugin uses a post variable called $thread_meta, which is set in disqus-comment-system/lib/api.php thus:

$thread_meta = $post->ID . ' ' . $post->guid;

Disqus would then create a comment thread based on this string. The problem is that $post->ID is the post ID number for the hub blog, and has nothing to do with the source blog (which, depending on platform, does not include post ids in its API request at all). So the source blog’s thread would be identified as test_post (for example) while the hub blog would be 34_test_post. I replaced the code above with

$thread_meta = $post->guid

which manages to stay pretty consistent across platforms. (NB: The same change has to be made on the source blog version of the Disqus plugin, if the source blog is running a self-hosted installation of Wordpress.)

Second problem: Getting a stable and unique identifier for each post thread is only the first step. You also need to make sure that the identifier is concatenated correctly when the actual API request is made. Disqus comment sections work by loading a piece of Javascript that is concatenated from an API request to disqus.com for the proper thread, then finds the comment section on the post page, and replaces the native comment code with the code returned from disqus.com. But I found (again, by looking at the URL for the RSS feeds) that each platform was making the request a little bit differently. At the end of disqus-comments-system/comments.php, the stock WP plugin reads

<script type="text/javascript" charset="utf-8" src="http://<?php echo strtolower(get_option('disqus_forum_url')); ?>.<?php echo DISQUS_DOMAIN; ?>/disqus.js?v=2.0&amp;slug=<?php echo $dsq_response['thread_slug']; ?>&amp;pver=<?php echo $dsq_version; ?>"></script>

Through a fair degree of trial and error, I replaced it with a big block of code that figures out (via some metadata created by FeedWordPress) which platform that particular post came from, and then modifies the javascript accordingly:

<?php $ok = get_post_meta($post->ID, 'syndication_permalink'); ?>
<?php $name = get_post_meta($post->ID, 'syndication_source'); ?>
<?php $name = str_replace(" ", "_", $name[0]); ?>
<?php $theslug = $dsq_response['thread_slug']; ?>
<?php $theslug = str_replace( '8211_', '', $theslug ); /* Removes em dash UGH */ ?>
<?php if ( preg_match( "/_[0-9]{2}$/", $dsq_response['thread_slug'] ) ) {
		$thesluglen = strlen($dsq_response['thread_slug']);
		$theslug = substr( $dsq_response['thread_slug'], 0, $thesluglen-3 );
		}
	?>
<?php if ( strpos( $ok[0], 'typepad' ) ) : ?>
	<script type="text/javascript" charset="utf-8" src="http://<?php echo strtolower(get_option('disqus_forum_url')); ?>.<?php echo DISQUS_DOMAIN; ?>/disqus.js?v=2.0&amp;slug=<?php echo $dsq_response['thread_slug'],'_',strtolower($name); ?>&amp;pname=wordpress&amp;pver=<?php echo $dsq_version; ?>"></script>
<?php elseif ( strpos( $ok[0], 'tumblr' ) ) : ?>
	<script type="text/javascript" charset="utf-8" src="http://<?php echo strtolower(get_option('disqus_forum_url')); ?>.<?php echo DISQUS_DOMAIN; ?>/disqus.js?v=2.0&amp;slug=<?php echo strtolower($name),'_',$dsq_response['thread_slug']; ?>&amp;pname=wordpress&amp;pver=<?php echo $dsq_version; ?>"></script>
<?php else : ?>
	<script type="text/javascript" charset="utf-8" src="http://<?php echo strtolower(get_option('disqus_forum_url')); ?>.<?php echo DISQUS_DOMAIN; ?>/disqus.js?v=2.0&amp;slug=<?php echo $theslug; ?>&amp;pver=<?php echo $dsq_version; ?>"></script>
<?php endif; ?>

In the first few lines, I do a bit of string manipulation to standardize the post title (ie the unique post identifier from Disqus’s point of view). Then I do some very ugly stuff. Wordpress was converting the em-dash (which was all over the client’s blog) into an ASCII code, which was screwing up the post identifier, so I just str_replaced it out. The next part (with the preg_match) is a bit tricky: in some cases, when Disqus receives requests from two blog posts with the same title (as is the case with the source blog post and the hub blog post), it differentiates between the two by assigning an apparently random two digit number to the second request it gets. Since the syndicated Disqus request will generally be sent after the source blog’s Disqus request (in virtue of its being syndicated), and therefore will be the one to be appended with the two-digit number, I figured I could just look for ‘_xx’ (where xx is a two digit number) at the end of the post title and strip it off. Ugly ugly ugly, but it works. The rest of the code just rearranges the javascript according to which platform the original post comes from, which in some cases requires the addition of source blog name.

With all this in place, I’ve got the following: A blogger posts on, say, his Tumblr blog, where Disqus is enabled. The post is fetched by FeedWordPress on the hub blog, where Disqus is also enabled, with the same user credentials. Then the hacks listed above trick Disqus into thinking that the syndicated post is the very same as the source post, so that the very same comments section is sent to each post. Kind of like magic, when it actually works.

Clearly, though, it would be much, much easier with a system that is built to do what I’m trying to do. That means, in part, having a single system for identifying posts across platforms (some appropriate htmlization of the post name, I presume) and then a single, unified system for making API requests.

2009 by the numbers

31-Dec-09

What’d I do in 2009? Some of my numbers are paltry and lame, but here they are anyway.

I posted 51 posts to this blog, teleogistic.net (and a handful of posts in other places). Those posts brought 183 legit comments. 3,299 unique visitors stopped by from 84 countries and 49 US states (WTF South Dakota?). The most popular search terms that led people here were: 1) read it later kindle, which led people to this post, 2) os x migration “less than a minute remaining”, which led people to this post, and 3) boone gorges, which led people to my beautiful face. The most popular posts on this blog were 1) Help me alpha test BuddyPress Forum Attachments (which is listed as the help page for a BuddyPress plugin I released, and so probably gets a lot of confused eyeballs), 2) Displaying the BuddyPress Admin Bar in Other Applications, which got added to StumbleUpon and, appropriately enough, contains hacks that did not originate with my paltry brain, and 3) Hub-and-spoke Blogging with Lots Of Students, which was interlinked with a lot of other great posts on the issue of classroom blogging. Not terrible for the first year of a blog, considering that BLOGS ARE DEAD.

I learned a lot about coding during 2009. When 2009 started, I knew quite a bit about HTML and CSS, as well as a smattering of PHP. I opened my first WordPress code file in about March. Since then I have released seven WordPress/BuddyPress plugins, a MediaWiki extension, and a handful of smaller hacks through the GPL, comprising some 4300 lines of code (about half of which was modified from existing code, and half of which is more or less from scratch).

I tweeted around 3300 times this year.

I racked up somewhere in the neighborhood of 180 hours of time this year commuting to and from work. Less impressively, I ran a pathetic 675 miles.

As some of you know, I do lots of crossword puzzles. According to my back-of-the-envelope calculations, I did around 1,960 crosswords this year, a number that is made up mostly of the first 13 puzzles listed on this page. I made a pledge at the beginning of the year to do my crosswords with pencil and paper (rather than on the computer) to improve my lackluster performance at ACPT. I stuck to that pledge: I can remember doing about three crosswords on the computer this year, as the rest were done on paper. We’ll see how all the practice pans out in February.

Here’s to a better 2010!

TinyMCE in Buddypress

20-Dec-09

I threw a little something together today to add WYSIWYG editing to BuddyPress, using TinyMCE. I want to be careful about the tags I allow, so I’m whitelisting, which is a bit tedious. As a result, there are only a few buttons available: a, em, strong, ul, ol, li. It’s a start, though.

Seems to work everywhere in BP: forums, wire, messages, profile pages.

A note about TinyMCE: WP ships with TinyMCE, and I thought it made sense to use that version instead of attaching one to this plugin. I think that the path to TinyMCE (line 20 of the plugin) should work on all installations, but you may have to tinker if you don’t see it popping up in the head of your BP pages. Moreover, the language files for WP’s version of TinyMCE are misnamed, which means that they don’t work right out of the box (at least for me they don’t). You may need to change the name of wp-includes/js/tinymce/langs/wp-langs-en.php to en.php in order to get the hover and help text in the TinyMCE box to work.

Download the plugin here. Don’t use in a production environment unless you are very certain that you are satisfied with the security of this plugin!

New BuddyPress plugin: Invite Anyone

18-Dec-09

invite-anyone

Some members of the still-young CUNY Academic Commons, eager to start groups in support of various projects, have been getting hung up on the process of putting a group together: first, each person has to sign up for the Commons; second, each person has to become friends with the group admin; third, each person has to request membership or wait to be invited (in the case of private groups). I just released a plugin called Invite Anyone that cuts out the second step: with the plugin activated, group admins can invite anyone from the installation, not just friends.

Read more about it, and download the plugin, at the CUNY Academic Commons Dev blog.

EDIT: Please leave further comments or questions regarding this plugin at its permanent home: Invite Anyone

Digital Literacy Across the Curriculum: Is it desirable? Is it possible?

15-Dec-09

I’ll be attending THATCamp Columbus next month. A few days ago I blogged my session topic on the THATCamp site. I’ve reproduced it below for posterity’s sake.


I spent a few years as a graduate fellow in a Writing Across the Curriculum program, and in my current full-time position as an instructional technologist I continue to collaborate frequently with WAC. In the time I’ve spent in close contact with the WAC program, I’ve come to find great value in some of the principles that lie at its core:

  1. The ability to write is of central importance to nearly all fields of study
  2. The various kinds of writing that are valuable in different disciplines can only be taught by practitioners of those diciplines
  3. There is a close connection between the way one writes and the way one thinks, such that explicit focus on writing techniques can result in increased academic clarity in general
  4. These considerations demonstrate that the position of writing is too integral to academic study for the teaching of writing to be the responsibility of composition programs and English departments alone

WAC programs are then organized in such a way as to provide tangible support for the teaching of writing, in the form of lesson plans, faculty development, pedagogical resources, and so on. And WAC’s mission is explicitly pan-departmental: one of the central tenets of the WAC philosophy is that students will only really learn to write if writing is meaningfully integrated throughout the entire curriculum.

I want to take seriously the idea that the WAC point of view can and should be applied, more or less wholesale, to the teaching of digital literacy.

There are a lot of problems to be worked out. First, I’d like to explore the extent to which the argument behind WAC can be adapted for digital literacy. Different disciplines require different kinds of engagement with the written word; likewise, we should be prepared to enumerate the different ways that the disciplines will require digital fluency (ranging from software know-how to programming skills to content filtering to multimedia composition to comfort with networks). I’d also like to flesh out the kinds of concrete support systems that would be required to make a digital analog to WAC function, be it faculty development or technology-intensive sections or whatever. And there will be the problem of politics: how do you argue to reluctant faculty and administrators that digital literacy education is as important as writing education? Here too I hope that we can look to WAC for strategies.

Streamlining Group Blogs

10-Dec-09

Cross-posted at the CUNY Academic Commons Dev Blog

Rodney Blevins and Marius Ooms wrote a fantastic plugin for BuddyPress called Groupblog, which allows BP groups to easily create a blog associated with their group. The killer feature of the plugin is the ability to add all group members to the blog (as authors, editors, subscribers, whatever you’d like) in a more or less automatic fashion – a far, far easier task than adding users manually through Dashboard > Add User.

I found, though, that the process wasn’t quite as automatic as I’d like. They’d based the code for adding users on a plugin by Burt Adsit called Community Blogs. Community Blogs only triggered the user adding process on a one-by-one basis: members of a group weren’t added to the group’s blog until they visited the blog. This is problematic for a few reasons. First, it’s an added step that creates some confusion among group admins and members, who assume that community blog membership should be automatic. Second, we’ve enabled various levels of privacy for blogs at the CUNY Academic Commons, and group members who were not yet members of a private group blog couldn’t really visit the blog to kick start the process. (Strictly speaking, that’s not true: the add user process was hooked to a process that took place when the blog’s login screen popped up, which happens when you persistently try to visit a blog to which you don’t have access. But this is extremely confusing.)

I took a bit of time today to rework how Groupblog handles the add user process. With the new setup, every member of a group is added to the group blog at once. The process is put into motion when the blog’s administrator updates and saves the group’s Group Blog settings. Other members of the BP community who join the group after the initial blog setup are added automatically to the blog as well, in accordance with the settings that the admin has determined for member permissions.

All the changes I made to the plugin are found in the main plugin file, bp-groupblog.php. You can download the modified file here: bp-groupblog.php.txt (don’t forget to make sure that the file is named bp-groupblog.php to make the plugin work). Just replace the stock version of the file with this one to make the changes. I intentionally did not clean up the plugin – all the original code is deactivated but still present beside the new code – because I wanted users to be able to differentiate what I had written from what the original authors had written (at least for now).