How to debug email-related theme and plugin functionality in WordPress

Let's say you're having trouble with a WordPress theme or plugin that uses wp_mail. How can you inspect the email that wp_mail composes or verify that it is actually sending (or at least attempting to send)?

Well, one simple way is to tell WordPress to use Python's smtpd DebuggingServer to "send" email.

The DebuggingServer doesn't actually send email, so don't go checking your inbox. It's only meant to show you the email that would be sent, headers included, if it were an actual SMTP server.

Note that this guide assumes you're debugging wp_mail issues during local development.

Let's get started.

Set up the smtpd DebuggingServer

If you have Python installed (comes with Mac OS X and most distributions of Linux by default), this is the one-liner you can use to get the debugging mail server running. From the command line, run:

$ python -m smtpd -n -c DebuggingServer localhost:1025

So that you don't have to remember that command, you can add an alias to your shell profile (e.g., ~/.profile), making it super easy to run the debugging mail server at a moment's notice.

To do this, open your shell profile in your favorite text editor and add the following line:

alias mailserve='python -m smtpd -n -c DebuggingServer localhost:1025'

Save your shell profile and source it in your shell to make sure the new mailserve alias is available:

$ source ~/.profile

Note: ~/.profile is probably the most common shell profile location. If you don't have this file, you can create one by running:

$ touch ~/.profile

Keep in mind that you might already have a shell profile for your specific shell. For example, ~/.basrhc for bash or ~/.zshrc for zsh. If you have a ~/.bashrc or ~/.zshrc, you can try adding the mailserve alias to one of them instead.

Once you have the mailserve alias defined and your profile sourced, running the server is as simple as:

$ mailserve

Note: there won't be any output from running this command initially. The debugging server runs, waiting for an application to connect and attempt to send a message.

Tell WordPress to send mail via the DebuggingServer

Now, in your WordPress theme or plugin, you can add some debugging code that will tell WordPress to send email via the debugging server you have running.

To accomplish this, add the following code to your theme's functions.php or to your plugin's main file:

function phpmailer_debug_settings($phpmailer) {
    $phpmailer->isSMTP();
    $phpmailer->Host = 'localhost';
    $phpmailer->Port = 1025;
}
add_action('phpmailer_init', 'phpmailer_debug_settings');

This code changes the configuration of the $phpmailer object used by wp_mail, telling it to use the SMTP server on localhost, port number 1025. If you look back at the Python command used to fire up the debugging mail server, you'll see the $phpmailer settings correspond to the arguments passed in that command:

$ python -m smtpd -n -c DebuggingServer localhost:1025

Once you have the debugging mail server running and the code above included in your theme/plugin, you can try sending mail with WordPress and see the entire message contents, SMTP headers, etc in your shell. Here's some example output:

vagrant@precise64:~$ mailserve
---------- MESSAGE FOLLOWS ----------
Date: Thu, 12 Mar 2015 16:21:54 +0000
Return-Path: <ryan@inn.org>
To: "\"Investigative News Network\"" <webmaster@investigativenewsnetwork.org>
From: Ryan <ryan@inn.org>
Cc: info@investigativenewsnetwork.org
Subject: [INN Website Contact] This is a test email subject line
Message-ID: <e538a998dbba308e2e6437a0b3ca4a50@vagrant.dev>
X-Priority: 3
X-Mailer: PHPMailer 5.2.7 (https://github.com/PHPMailer/PHPMailer/)
X-Originating-IP: 192.168.33.1
X-Mailer: WP Clean-Contact (vagrant.dev)
MIME-Version: 1.0
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Peer: 127.0.0.1

This is the test email body.

------------ END MESSAGE ------------

Why do I need this?

This can be helpful if you're trying to track down missing parts of an email (e.g., hey, where'd my "from" address go?) or need to verify the contents or formatting of an email that your theme/plugin sends to users.

Keep in mind that, although this post describes how to use the Python smtpd DebuggingServer with WordPress, you can also use this guide with other applications as long as you can configure said applications to connect to the DebuggingServer.

New Plugin — Easier DoubleClick Ads for WordPress

This week we’re happy to announce a new WordPress plugin to make serving DoubleClick ads easy.

In the past we’ve used (and will continue to use) Automattic’s ad code manager to control ad tags. This plugin comes with a plethora of options, including support for different providers. While its fine for some users, for most of our applications it’s downright unwieldy.

We designed our plugin to be lighter-weight and to work out of the box with as little setup as possible. The minimum needed to start serving ads is to define your network code and place a widget in a sidebar. Then you set options for the DFP identifier and size of the ad spot and that’s all there is to it.

Responsive ads

It’s easy to serve different size creatives at different breakpoints. For example, in a leaderboard spot, it’s possible to add one widget to display 300x50 sized creatives on mobile and 728x90 size creative on tablets and desktops. Only one will be loaded and counted as viewed in DFP, depending on the breakpoint.

Targeting

This plugin sends information about the page to DFP to make targeting specific sections and pages of a site easy.

  1. inURL: Target a piece of the page path. (eg. targeting the string /dvd would match example.com/dvds/, example.com/dvds/page1 and example.com/dvds/page2)
  2. URLIs: Target the entire page path. (eg. targeting the string /books will only match example.com/books and not example.com/books/page1)
  3. Domain: Target based on the domain. (eg. run different advertising on staging.example.com and example.com.)
  4. Query: Target a ?query var. (eg. target the url example.com/?movie=12 with the targeting string movie:12)

See the documentation for more information on how to set these values up in DFP. We’ll be adding targeting criteria for post category, post type, template type and other criteria specific to WordPress in the future.

Theming

If you don’t maintain widget areas in your theme, you can hard code breakpoints and places ad units directly in your template files.

Defining breakpoints is simple. We suggest you do this for users in your theme’s functions.php since most users will not know pixel values for the theme's breakpoints.

function ad_setup() {

   global $DoubleClick;

   // Optionally define the network code directly in functions.php.
   // $DoubleClick->networkCode = "xxxxxxx";

   /* Define Breakpoints */
   $DoubleClick->register_breakpoint('phone', array('minWidth'=> 0,'maxWidth'=>720));
   $DoubleClick->register_breakpoint('tablet', array('minWidth'=>760,'maxWidth'=>1040));
   $DoubleClick->register_breakpoint('desktop', array('minWidth'=>1040,'maxWidth'=>1220));
   $DoubleClick->register_breakpoint('xl', array('minWidth'=>1220,'maxWidth'=>9999));

}
add_action(‘dfw_setup','ad_setup');

To place an ad in a given location, just call place_ad on the global $DoubleClick object.

   // Places a 728x90 leaderboard ad for all breakpoints but mobile.
   $DoubleClick->place_ad(‘site-leaderboard','728x90',array('desktop','xl','tablet'));

That’s it. We’re excited to see how you use it! Download the plugin from Github here.

Announcing Largo Version 0.4

largo-sqWe're excited to announce a new version of Largo, the open source WordPress framework we build and maintain for our member organizations.

Version 0.4 is a huge update that's been in the works for a while. In this release, we've more or less rebuilt the Largo theme from the ground up to make it more stable and easier to use. Here's a list of some of the things included in this update:

wcijProbably the most visible change is the addition of a number of new homepage layouts, which are much more visual and "magazine-like" to really highlight the feature reporting that many of our members are doing. We've also retained and polished up the previous homepage layouts (with the exception of the "carousel" layout, which is deprecated in version 0.4) and have added a new homepage framework to make it much easier to create your own custom homepage layouts from a child theme. Many of the new layouts also allow a user to switch between viewing "top stories" and "all recent stories" in a traditional "river" view, remembering their preference on subsequent visits.

Faith-based state group seeks Waupun prison abuse probe   WisconsinWatch.orgWe've also completely redesigned the article template to allow for more easy creation of immersive stories. The new default article template in Largo removes the sidebar to reduce distraction and adds a new featured media area at the top of the story with support for a large "hero" image, video or other embedded content (maps, audio, etc.). If you prefer the traditional two-column layout on story pages, we've kept that, too. You can simply select the template you'd like to use in the theme options and will have the option to override it on select stories. These improvements also include streamlining the publishing interface to make it easy to add and manage featured media by reducing the number of boxes you have to search through to find what you're looking for.

read-nextThe bottom of the article page template is now a WordPress widget area to make it easier to rearrange the elements that appear there. This includes the addition of a number of new widgets for related content, author bios, and an optional disclaimer that you can easily add to the bottom of all your stories, or selectively override on a per-story basis.

Site navigation is also cleaner, easier to manage and more mobile friendly, including an option to use a "sticky" header that remains visible when a user scrolls. Article pages now also have a sticky footer with social sharing links, the ability to easily follow authors and topics, and more.

follow

And we've replaced the clunky older/newer posts navigation used on many pages of the site with a simpler "load more posts" infinite scroll.

catCategory pages have been redesigned to give more prominence to featured stories and it is now possible to create and use custom sidebars on category and tag pages. In addition, we've added a new optional "content type" taxonomy to allow you to group stories by type. For example, if you'd like to have a page for just your data projects without having to use categories or tags, now you can!

User profiles are also now easier to manage with the option to upload avatar photos directly in WordPress instead of relying on Gravatar and with better validation for social media accounts to make sure your accounts get linked up correctly. We've also added a new widget to display a list of the writers and editors on your site with their avatar photos, titles, bios, etc.

optionsOn the admin side, we've tried to simplify wherever possible and have moved less-frequently used settings to an optional tab of the theme options to keep them easily available but out of the way. This includes things like optional taxonomies and a number of new integrations with services such as Google Custom Search that you can use to enhance the functionality of your site. One additional option allows you to easily change the color scheme of your site using a LESS/CSS customizer directly from the admin without having to edit your theme files directly.

For developers, we've reorganized the theme files in a way that we hope will make it a lot easier to develop child themes based on Largo. You'll also notice that we've begun to add unit tests for the theme, helper functions for debugging, and more hooks, filters and constants to make it easier to add, remove or modify various pieces of Largo functionality. We also have an updated sample child theme that includes ample documentation and recommended best practices for working with Largo. We welcome your feedback if there's anything else we can do to make your lives easier.

helpdeskAnd last but not least, we've completely revamped the Largo documentation, added a knowledge base with answers to our most frequently asked questions and implemented a new help desk system to better keep tabs on your questions for us.

Oh right, and the ubiquitous "assorted bug fixes."

Updating to the new version is as simple as downloading the new theme (zip) and replacing your existing copy of the Largo parent theme. Then, when you login to your site for the first time, you'll be prompted to apply a database update to make sure all of your settings are preserved. As this is a major update, we strongly recommend creating a backup of your site before making the update and, ideally, testing the new version on a staging site to make sure you have a handle on the changes before applying it to your live site. Just a reminder that if you require more assistance making this update, we offer paid services and we'd be happy to help. Details on that program can be found here.

For INN members who host their sites with us, this update is available today but we'd like to spend some time working with you to walk through the new features. Please drop us a line at support@largoproject.org if you'd like to be among the first sites to make the update, otherwise we'll be reaching out to you in the coming weeks to schedule these consultations.

Thanks to every member of the INN Nerds team who worked on this release, particularly Ryan Nagle, who took lead on this one, but also to Meredith Melragon who did a lot of the work improving our documentation, Kaeti Hinck who jumped in late in the cycle to help us polish the visual design, and our software apprentices Ben Keith and Will Haynes who both contributed a lot of code to this release. Thanks also to a couple of open source contributors, particularly Ben Byrne and Daniel Bachhuber.

The next release! 0.5 will be focused on improving performance, developer documentation and evaluating third-party libraries, as well as some continued improvements to the design of the default theme. It is scheduled for release at the end of March. We're now keeping the Largo roadmap public on GitHub, so you can see more of what's planned for future releases.

My Apprenticeship With INN Nerds – Part 2

It’s been a little over four months since I joined the Nerds team at INN as their second software apprentice. With just about four months to go, now is a good opportunity to reflect and set goals before the end catches up.

Apprenticeship

News Quiz/Interactables. For one of my first projects, I wrote a WordPress plugin wrapper around Mother Jones’ news quiz library. During the process we talked about what a framework for registering and maintaining more interactive features in the future would look like. This Winter I hope to build out those ideas.

Unit Tests. Early on, I researched options for building unit testing into our theme development process and wrote about it here. Since then Ryan Nagle has built this into our deploy tools and written up some testing examples. Much of Largo still needs tests written, which I want to make a point to help with.

Analytic Bridge. Born out of a weekend project, I wrote a WordPress plugin that pulls and relates metrics from Google Analytic to post objects in the WordPress database. As a proof of concept, I adapted this into a Popular Post widget (a highly demanded feature by members), but the functionality could be used in a variety of applications.

I expect to work out the bugs and extend the features of this plugin in the next couple of weeks, as well as tweak the algorithm to make the popular posts widget ready for prime time.

Fixes/enhancements to Largo. Recently I’ve been picking up some tickets related to getting our Largo Project ready for version 0.4. Learning a lot about the codebase in the process, this Spring I’ll no doubt have the opportunity to contribute more.

Documentation. Documentation for Largo currently exists in three or four different places. Since the addition of our Support Specialist Meredith Melragon to the team we’ve doubled down on our efforts to keep and update complete documentation for both administrators and users.

Recently I’ve been working with Meredith to add python driven sphinx to our deploy tools. The benefits of documentation being versioned along with our code, yet accessible as compiled html means all our contributors have access to writing docs and end users have a single web source to find help. One of the biggest unresolved issues is how to incorporate our existing php block comments into these docs, a problem I hope to research and solve.


This kind of stuff sound like fun? Looking for something to do this summer? Find out how you could be INN's next software apprentice here.

Updates to INN’s Deploy Tools

We've made a lot of changes and added a bunch of new commands to our deploy tools since the last time we checked in.

Most notably, we've added commands to help scaffold and run unit tests for your plugins AND your themes. Behind the scenes, our scaffolding and tests works as described by Will Haynes in this post.

Other changes include migration to Fabric's new-style task declaration and updated documentation.

Unit testing tools

To scaffold/set up tests for your theme:

$ fab dev wp.tests.setup:largo-dev

This command:

  • Drops and recreates your testing database (which should always be throw-away, ephemeral)
  • Copies essential test files (e.g. phpunit.xml and a tests directory with test-sample.php and bootstrap.php files) to your theme or plugin directory if they are not already present
  • Installs the WordPress test framework to /tmp/wordpress-tests-lib/includes
  • Configure a wp-tests-config.php file and place it in /tmp/wordpress-tests-lib

With those files in place, you can run tests for your theme or plugin:

$ fab dev wp.tests.run:largo-dev

Example output:

Screen Shot 2014-11-25 at 9.45.54 AM

Namespaces and aliases

The other big change we made was moving all commands to Fabric's new-style task declaration. Using new-style tasks gives us all the benefits described in Fabric's documentation on the subject.

While the deploy tools are not taking advantage of every feature of new-style tasks, they are better organized thanks to namespacing and aliases.

Here's some example output from fab -l:

Screen Shot 2014-11-25 at 10.00.07 AM

Here you can see each module (and submodules) along with defined tasks. Tasks use dot-syntax, which should feel more explicit and intuitive if you're familiar with Python (which is what Fabric is built on).

Also note that the command wp.migrations.s2m is an alias for the much-longer, sometimes-harder-to-remember command wp.migrations.single_to_multisite.

I'm very lazy, so anytime I can save some mental energy and type a bit less, I consider it a win. This is as true for commands I use very frequently as it is for commands I use once in a great while.

Documentation

We also expanded the deploy tools' documentation to include all commands. You can find the documentation on Github.

Notes

Remember, the deploy tools were built with our situation in mind. We deploy to WP Engine, so some stuff is very WP Engine specific.

For example, the wp.fetch_sql_dump command only knows where WP Engine stores recent SQL dumps. The wp.maintenance.start and stop commands assume you are deploying to a host that uses Apache and that you have a .htaccess file in the root of your FTP server.

With that said, much of toolkit will work with any host provided you have (S)FTP access, including the push-button deployment rig I wrote about previously.

If you are using or thinking about using the deploy tools, have questions or suggestions, let us know.

Batch Processing Data With WordPress via HTTP

For a recent project, we found ourselves in need of a way to verify the integrity of an entire site’s worth of posts after a mistake in the initial migration meant some of the posts in the database were truncated/cut-off.

Our options were limited. Since our host (WP Engine) doesn’t offer shell access and we can’t connect directly to our database, we would have to write a script to accomplish via HTTP requests.

We wanted something that was at least semi-unattended. We’d also need to be careful to avoid exhausting PHP’s memory limit or running up against any PHP or Apache timeout settings.

Given the constraints, processing of posts would have to happen over several HTTP requests.

Enter batchProcessHelper a class that provides ways to accomplish all of the above.

How it works

You can find all the details on usage at the project’s Github page.

batchProcessHelper is meant to be extended. There are two methods you must override: load_data and process_item.

The first method, load_data, is responsible for accessing the data you plan to process and returning an array of serializable data that will be the data queue. The array can consist of objects or associative arrays or be something as simple as a list of IDs or range of numbers. This is entirely up to you.

The only constraints is that load_data must return a data structure that can be serialized for storage in the database as WordPress transient. This is will be your data queue.

The second method, process_item, is where you put the business code to process individual items in the queue.

This method should return true if it succeeds in processing an item, false if it fails.

How to use it

Here’s a super simple example of a class extending batchProcessHelper. You can see and learn how to run the full example on the project Github page.

include_once('batchProcessHelper.php');

class userImportProcess extends batchProcessHelper {

    function load_data() {
        return csv_to_array(ABSPATH . 'example_data.csv');
    }

    function process_item($item) {
        $this->log('Processing item: ' . var_export($item, true));
        return true;
    }
}

This example doesn’t actually do anything. In load_data, we simply load the example data from csv, converting it to an array of associative arrays.

The process_item method logs each of the associative arrays to the batchProcessHelper debug/error log.

However, this code could easily modified to create a new user for each row in example_data.csv.

function process_item($item) {
    $result = wp_insert_user($item);
    if (!is_wp_error($result)) {
        $this->log(‘Successfully created new user: ‘ . $item[‘user_email’]);
        return true;
    }
    return false;
}

Instantiating and running

So, we’ve defined our userImportProcess class, perhaps in a file named userImportProcess.php. How do we run it?

$process = new userImportProcess(array(
    'blog_id' => 99,
    'batch_size' => 10,
    'batch_identifier' => 'User Import’,
    'log_file' => '/path/to/your/file.log'
));

$process->process();

The only requirement is a batch_identifier — a name for your process.

Optionally specify the batch_size. If you don’t, batch_size defaults to 10.

Also, optionally specify a log_file — a path where debug and error messages will be sent. If you don’t specify log_file, batchProcessHelper will try to write one in /tmp.

If you want your process to run in the context of a specific blog, specify a blog_id as well.

Finally, call the process method to start.

Where do I put this stuff?

You’ll need to create a new directory in the root of your WordPress install. It doesn’t matter what it’s called, it just has to be in the root of your WordPress install.

Let’s say you create a directory named wp-scripts. You’ll want to put batchProcessHelper.php and userImportProcess.php in that directory.

Also, if you’re loading data from the filesystem (as in the example above and on the project’s Github page), you’ll want to place the data file in the appropriate location.

Finally

Visit userImportProcess.php in your browser.

If all goes well, you should see a message along the lines:

“Finished processing 10 items. There are 390 items remaining. Processing next batch momentarily…"

At this point, the page will refresh automatically, kicking off work for the next batch.

Once all batches are done, you’ll see the message:

“Finished processing all items.”

It should all go something like this:

Notes

If you have a multisite install, you'll need a Super Admin account to run code that extends batchProcessHelper. If you have a standalone install, you'll need an account with Administrator privileges.

Also, if you plan on keeping your wp-scripts directory around for any length of time, you should consider allowing only a select few IP addresses to access the directory. Refer to the project's README for more information.

Unit Testing Themes and Plugins in WordPress

Nes_Test_Station

Over the past few weeks, we’ve been investigating the best way to incorporate a WordPress testing framework into our development process. With few developers out there writing tests for their plugins (and even fewer testing themes), we want to share our tribulations as we figure the process out.

Fortunately, WordPress ships and supports a unit testing framework. Unfortunately, this framework is designed mainly for development on WordPress core and not directly for WordPress plugin and theme developers. However, with enough prodding, it is possible to write your own tests on top of this library.

Step one: Installing PHPUnit

The PHPUnit library provides a base framework for writing tests in PHP. WordPress develops its own testing platform on top of this library.

Assuming you’re on a *nix system, installing PHPUnit is as simple as:

wget https://phar.phpunit.de/phpunit.phar
chmod +x phpunit.phar
mv phpunit.phar /usr/local/bin/phpunit

See the PHPUnit installation notes for installing the framework on Windows or including it with composer.

Step two: Pull in the WordPress framework

Before we go any further, I should note that wp-cli ships with a handy command that does a lot of this grunt work for you. However, it currently supports tests for plugins only (not themes). If that’s all you need, it’s the fastest way to get started, but the steps below should give you a better understanding of what’s happening behind the scenes and give you a setup that can be customized for your specific development environment.

WordPress bundles its testing framework in with its core development tools svn repo. We can download just the tools we want by checking out the includes directory. It’s up to you where you want to organize your testing library. For the sake of this tutorial, we’ll assume you clone it into your root WordPress directory.

cd <wproot>
svn co http://develop.svn.wordpress.org/trunk/tests/phpunit/includes/

You’ll need a second WordPress config file named wp-tests-config.php as defined here:

https://develop.svn.wordpress.org/trunk/wp-tests-config-sample.php

Configure the database details as you would a normal wp-config.php. It’s important to use a secondary database, as WordPress drops and recreates tables as part of its tests. In addition, ensure that ABSPATH is pointed to the correct WordPress install to use during testing.

Step three: Hook it all together

What we do now is create a phpunit.xml file. This file is what PHPUnit uses to load the testing environment and run its tests. It doesn’t matter where you create this file, but for the sake of this tutorial we’ll add it to the WordPress root directory (the same place we downloaded the WordPress test framework).

<phpunit 
	bootstrap=“./includes/bootstrap.php"
	backupGlobals="false"
	colors="true"
	convertErrorsToExceptions="true"
	convertNoticesToExceptions="true"
	convertWarningsToExceptions="true">
	<testsuites>
		<testsuite>
			<directory prefix="test-" suffix=".php">./tests/</directory>
		</testsuite>
	</testsuites>
</phpunit>

Now, if you run PHPUnit from the command line —

cd <wproot>
phpunit

— you should see this on the command line.

no-tests

If errors are thrown, check that your paths all point to the correct place.

Step four: Building tests

What we’ve got so far is the included framework that ships with WordPress. First, our phpunit.xml file is specifying a bootstrap.php file to load and install WordPress. Then, it's looking in ./tests/ for files in the format test-*.php to run actual tests. Since we don’t have any tests yet, no tests are executed.

This base configuration is only running tests on WordPress core functions. In order to test our own plugin and theme functions, we must create our own bootstrap.php file to specify which theme and plugins to activate before installing WordPress. Create a new file called ./tests/bootstrap.php. In this file, include the following:

<?php

require_once dirname( dirname( __FILE__ ) ) . '/includes/functions.php';

function _manually_load_environment() {
	
	// Add your theme …
	switch_theme(‘your-theme-name‘);
	
	// Update array with plugins to include ...
	$plugins_to_active = array(
		‘your-plugin/your-plugin.php’
	);

	update_option( 'active_plugins', $plugins_to_active );

}
tests_add_filter( 'muplugins_loaded', '_manually_load_environment' );

require dirname( dirname( __FILE__ ) ) . '/includes/bootstrap.php';

Update your phpunit.xml file to include this new bootstrap file, instead of the WordPress default.

Now you have everything you need to write unit tests on your theme. Create a new file named ./tests/test-sample.php and write your first test:

<?php
class SampleTest extends WP_UnitTestCase {
	function testSample() {
		$this->assertTrue( 'Your Theme' == wp_get_theme() );
		$this->assertTrue( is_plugin_active('your-plugin/your-plugin.php') );
	}
}

Running phpunit now, you should see the following:

tests

That’s it! You’re now able to write your own test functions to test your code.

Final words

It’s important to note that while this is one way to organize your testing code, it might not be the best for your development environment. You might, for example, prefer to keep your test suite (./tests/) in the root of a theme or plugin directory, so that it is included in version control. Or you might want to keep tests completely outside of the WordPress directory.

Diving deeper, you might want to activate and deactivate plugins directly in the testing classes to test what happens when plugins aren’t loaded. You might want to maintain multiple test suites for different plugins or themes.

Lastly, now that you are set up to write unit tests, you might be asking how you should go about writing a test. We’ll cover some unit testing best practices over the coming weeks as we write our own tests for our codebase. For now, take a look at some test classes that WordPress has written to get a feel for how tests are built.

Quiz Your Readers: Our New WordPress Plugin To Create Simple Quizzes

Today we're excited to announce a new embeddable interactive quiz tool built using Mother Jones' handy quiz tool but adapted specifically for the Largo platform and available now for any WordPress site.

[quiz key="0AvfAWkLLRik_dGtjRVNUamJwbE1wRWxtVVRURG1UU0E" layout="sidebar" answerstyle="alpha" align="alignright" title="Take the Quiz!" description="Think you've got what it takes?" source="Wikipedia" byline="Will Haynes/INN"]

Built on top of Mother Jones’ NewsQuiz.js library, this WordPress plugin allows you to build a quiz in Google Drive and embed it with a shortcode into a WordPress post. This could be used to test readers’ understanding of material, or just to expose them to the questions in an interactive way.

Grading of questions happens inline, at the bottom of the widget. Settings exist to control both the size and flow of the plugin, as documented in the project readme.

Try out the example quiz embedded in this post, or check out how INN member Youth Today is using it to support a piece exploring how the income gap affects scoring on college entrance exams.

To see how to build a quiz of your own using this plugin, how to format your Google spreadsheet, etc. please see Mother Jones’ documentation for the original quiz library.

We’re hoping to build more interactive features for Largo in the future.

So if you have an idea for what we should build next or suggestions for how to improve this tool, let us know in the comments or email us anytime at nerds@inn.org.

How To Migrate A Standalone WordPress Blog To A Multisite Install

Sigh. Database migrations — often nerve-wracking, always tedious, never a task I’ve been fond of. However, as you know, they’re often necessary. For us, they come up frequently.

One of the benefits available to INN members is the option to have their Largo-powered WordPress website hosted on our platform, largoproject.org. As such, we often find we need to migrate their standalone blog to our multisite rig.

To ease the process, I wrote a single_to_multisite_migration command that’s included in our deploy tools repo.

Note: if you’re using WP Engine, our deploy tools include a bunch of helpful goodies. You can read more about them here.

Assumptions

  • You have mysql installed on your computer
  • You’re using INN’s deploy tools with your multisite project
  • The standalone blog uses the standard "wp_" WordPress database prefix

What it takes to migrate a standalone blog

My teammate Adam Schweigert put together this gist that describes the changes required to prepare a standalone blog’s database tables for a new home amongst other blogs in a multisite install.

The process involves renaming all of the blog’s tables from wp_[tablename] to wp_[newblogid]_[tablename]. For example, wp_posts might become wp_53_posts.

This is true for all tables except for wp_users and wp_usermeta. More on this later.

This brings up the question of where the value for new_blog_id comes from. The easiest way to get this value is to create a new blog in your multisite install. By doing this, you’re creating a skeleton of database tables that your standalone blog will fill in.

Step one: create a new blog in your multisite install

After creating a new blog, find it in your Network > Sites list. Hover the site’s link and you’ll see an url in your status bar.

Screen Shot 2014-08-18 at 4.19.28 PM


The “id=53” is the part you want. Make note of the site ID as you’ll need it later.

Step two: retrieving a database dump and running the single_to_multisite_migration command

Let’s look at the signature of the single_to_multisite_migration command:

def single_to_multisite_migration(name=None, new_blog_id=None, ftp_host=None, ftp_user=None, ftp_pass=None):
    ...

The name and new_blog_id parameters are required. The name will be used when creating a database in your local mysql server. This is where we’ll load the single blog’s database dump. It doesn’t matter much what name is, but it should conform to mysql’s rules for identifiers.

The new_blog_id is the ID that you made note of earlier.

If you’re using WP Engine to host the standalone blog, deploy tools can retrieve a recent database dump for you automatically. For this to work, you’ll need to provide your FTP credentials when running single_to_multisite_migration.

Here’s an example:

$ fab single_to_multisite_migration:blogname,53,myinstallname.wpengine.com,ftpusername,ftppassword

If you’re not using WP Engine, you’ll need to get a database dump by some other means. Once you have it, place it in the root directory of your multisite project repo. The single_to_multisite_migration command expects a mysql.sql file in this location, so you may need to rename your dump file to meet this expectation.

After you have the mysql.sql dump in the root of your multisite project repo:

$ fab single_to_multisite_migration:blogname,53
Example of the output from the single_to_multisite_migration command
Example output from the single_to_multisite_migration command

Step three: wait… rejoice! Your multisite_migration.sql file is ready!

Depending how big your standalone blog’s database is, it may take a while for the command to finish.

Message indicating the single_to_multisite_migration command finished properly.
Message indicating the single_to_multisite_migration command finished properly

Step four: apply the multisite_migration.sql file to your multisite database

I leave it up to you to decide how to best to apply the migration file to your database. You may be able to import the sql using phpMyAdmin, or, if you’re using WP Engine, you might contact their lovely support staff and ask them to apply it for you. Be clear that you DO NOT want to drop all tables in your multisite database before importing the multisite_migration.sql file.

Aside from renaming the standalone blog’s tables, what does single_to_multisite_migration do?

Great question. Here’s the short list:

  • Finds the maximum user ID in your multisite database and uses that value to offset the ID’s of users in your standalone blog’s wp_users table so that they can be inserted into the multisite database without duplicate primary key errors.
  • Finds the maximum user meta ID in your multisite database and uses that value to offset the umeta_id's in your standalone blogs wp_usermeta table so that user meta can be inserted into the multisite database without duplicate primary key errors.
  • Retains the siteurl and home values in your multisite “skeleton” site’s wp_[new_blog_id]_options table. This means that you won’t have to (re)set your new multisite blog’s site url and home url values after applying the multisite_migration.sql file.
  • Looks through all of the standalone blog's posts to find "wp-content/uploads/" and replace it with "wp-content/blogs.dir/[new_blog_id]/files/" to help with migrating uploads to the multisite install.
  • Uses REPLACE, UPDATE and some tricky subqueries to insert or update rows. This means you can apply the multisite_migration.sql file to your multisite database and avoid duplicate wp_users and wp_usermeta entries. Helpful if you need to run several incremental migrations to get all of a blog’s content before making the official transition to the multisite install.

Migrating uploads

The other thing you'll need to do is move your standalone blog's uploads directory. The single_to_multisite_migration command doesn't do this for you. You'll have to manually move the contents of the standalone blog's "wp-content/uploads/" to the multisite install "wp-content/blogs.dir/[new_blog_id]/files/" directory.

Test your migrations thoroughly before deploying.

We’ve tested and used this method several times with great success. It works well for us.

That said, remember to thoroughly test migrations before applying them to any production environment.

Break your local development site or your staging server first and be happy about it! Then fix any mistakes and you'll be ready to apply to your production database.

Speaking On Accessibility At WordCamp Columbus 2014

Last week, a Twitter conversation started with Deborah Edwards-Onoro about web accessibility after we both retweeted this eye-opening post on An Alphabet of Accessibility Issues from the Pastry Box. About an hour later, I had agreed to speak two days later at WordCamp Columbus 2014.

Deborah wrote a blog post about the experience of agreeing to do the talk as well as another blog post the morning of our talk that outlined all that we wanted to discuss. This was my first conference speaking engagement, and tomorrow I'll share more about what I learned and offer some tips for overcoming the anxiety of being a first-time speaker.

Our Accessibility Roundtable was in the first round of talks after the introduction in a small room that held about 20 people, and we had a few fewer than that. It was a very friendly group, and while many were fairly knowledgable about Accessibility in general, everybody seemed to learn something from our talk.

We used Deborah's post, much of which centers around issues addressed by the WP Accessibility Plugin, as our visual aid for the talk rather than quickly cobbling together a slide deck.

We also discussed the following suggestions at length:

  • Add captions or transcripts to videos and podcasts (also great for SEO!)
  • Add meaningful text to links rather than simply using "Read More" or "Click Here" for people arriving at those links without visual context
  • Spell out acronyms the first time they appear on a screen
  • Make focus visible for keyboard users

In addition to her outline, I mentioned JAWS (Job Access With Speech), a tool that translates screen content to audio or braille for the visually impaired that I was introduced to when I worked at Nationwide Insurance. Because JAWS is expensive, it's primarily used by corporations for testing and by libraries for patrons rather than for personal use. There were a few people interested in looking into JAWS for their workplace.

And for people with Macs, VoiceOver is built right into OSX with support for refreshable braille displays. There are many options to help people see sites from a different perspective. If nothing else, just unplug your mouse and try to navigate your site once a week or so. It's cheap, effective and eye opening.

Since it was an informal talk, we had a lot of discussion and took questions from the audience. Between the two of us, I felt like we were able to either answer the questions presented, or at least point them in the right direction for further research. That addressed another fear of mine when I agreed to speak on Accessibility. I'm far from an expert on the subject. I'm more of a champion of empathy in general, and feel that it's important to empathize with people who experience the web in a very different way than most. But it's not about being an expert so much as it's about sharing your perspective and hopefully broadening the perspective of those in the audience as well.

I'm grateful to Angie Meeker, the organizer of WordCamp Columbus, for the opportunity to speak, and to Deborah Edwards-Onoro for her work, encouragement and support. She is a wonderful citizen of our community and I highly recommend you follow her on Twitter as her feed and blog are a wealth of helpful information on a variety of subjects including WordPress, User Experience design and Accessibility.