A little background

A number of our WP plugins utilize configuration files that customize how the plugin operates on our various properties. The files are a convenient way to quickly spin up a VM with all the appropriate settings needed to mimic our production environment without the need for manual setup.  Sometimes we want our configuration files to be objects, but throwing new stdClass all over the place is pretty ugly and hard to read.

The test

The three approaches to formatting config files that we tested were:

  • Arrays cast as an object
  • Config data stored as a JSON object (we expected this to be the slowest)
  • Explicit object declarations

The results

Casting was fastest. With 1,000,000 iterations, the results were as follows:

Average for casting: 0.92707586288452s ( 9.2707586288452E-7s per iteration)
Average for json_decode: 4.1746528148651s ( 4.1746528148651E-6s per iteration)
Average for stdClass: 1.7674691677094s ( 1.7674691677094E-6s per iteration)

The source

Here’s the gist.

<?php
$loops = 1000000;

$start = microtime( TRUE );

for ( $i = 0; $i < $loops; $i++ ) {
	$thing = (object) array(
		'cat' => (object) array(
			'name' => 'Mr. Giggles',
			'age' => 3,
		),
		'door' => (object) array(
			'age' => 1,
		),
	);
}//end for

$total = microtime( TRUE ) - $start;
$avg = $total / $loops;

echo "Average for casting: {$total}s ( {$avg}s per iteration)\n";

$start = microtime( TRUE );

for ( $i = 0; $i < $loops; $i++ ) {
	$thing = '{ "cat": { "name": "Mr. Giggles", "age": 3 }, "door" : { "age": 1 } }';
	json_decode( $thing );
}//end for

$total = microtime( TRUE ) - $start;
$avg = $total / $loops;

echo "Average for json_decode: {$total}s ( {$avg}s per iteration)\n";

$start = microtime( TRUE );

for ( $i = 0; $i < $loops; $i++ ) {
	$thing = new stdClass;
	$thing->cat = new stdClass;
	$thing->cat->name = 'Mr. Giggles';
	$thing->cat->age = 3;
	$thing->door = new stdClass;
	$thing->door->age = 1;
}//end for

$total = microtime( TRUE ) - $start;
$avg = $total / $loops;

echo "Average for stdClass: {$total}s ( {$avg}s per iteration)\n";

We open-sourced a simple plugin to allow users with the Contributor role to upload image files.

Background

WordPress does not allow users with the Contributor role upload image files because “the images are immediately public and can be shared on the Internet”, which contradicts the definition of the role, that a Contributor can “create and edit only their own posts, but cannot publish them”. While VIP does provide a plugin to allow Contributors to upload files, it doesn’t help blogs not hosted on VIP.

To enable the upload permission, we can simply add the “upload_files” user cap to the Contributor role in a “user_has_cap” filter, and this is exactly what the go-allow-contributors-to-upload-images plugin does.

After installing the plugin as you would with any WordPress plugin. Then activated it to allow Contributors to upload files, and deactivate it to prevent Contributors from uploading files.

We’ve open sourced our Gigaom Copy Active Plugins plugin! (A sister plugin to Gigaom Copy Layout)

A little background

When dealing with multiple production and development sites – with multiple developers – knowing what plugins you need to have active can be an annoyingly manual process. After many sessions of Zach Tirrell and me reading off our lists of active plugins on our respective development instances, we became annoyed enough to find a solution.

Like our Gigaom Copy Layout plugin, this plugin provides an export and import page for – you guessed it – exporting and importing the list of active plugins. Due to the simplicity of the data being exported, we opted to not base64 encoding the data to allow it to be easily diffable in whatever versioning solution you use (if you choose to version control your list of plugins that you use, of course).  Here’s an example export:

bcms/bcms.php
co-authors-plus/co-authors-plus.php
go-copy-active-plugins/go-copy-active-plugins.php
go-copylayout/go-copylayout.php
go-local-coauthors-plus/go-local-coauthors-plus.php
wp-mail-smtp/wp_mail_smtp.php
wp-ticket-framework/ticket-framework.php

Exporting

  • Go to Plugins > Copy Active Plugins
  • Copy the contents of the first textarea  (we commit “production-level” plugin activations into our Git repository).

Importing

  • Go to Plugins > Copy Active Plugins
  • Paste the contents of a Copy Active Plugins export into the second textarea and click Save.

We use a lot of custom post types in WordPress. Often we have wanted to use mixed post types in the hierarchy on those various post types. For example, we might want to make a "page" a child of an "event" custom post type. Perhaps we even want to have custom post types that are children of other custom post types.

As a general rule, this is not supported by the core of WordPress, but it mostly works without an issue.

Problems with get_page_by_path

One of the reasons you may want to do this in the first place is to get really nice permalinks for post types that are directly dependent on others. This part works fine, until you try to use get_page_by_path. The way the query was structured in that function, all posts in the hierarchy needed to be of the same type (or be attachments).

With that problem encountered, we submitted ticket #24763 with a patch to make this workable for us. In the meantime, we made a copy of the function in our plugin and modded it to work as we needed it to. After a few iterations on the ticket and our patch, this change is now in trunk and will be available in WordPress 3.9!

More flexibility and get_page_by_title

As a side effect of this change, get_page_by_path will now accept an array of post types allowing it to be used in new ways we might not have even imagined. Additionally, get_page_by_title was modified in this change as well. It did not need changes to support mixed post type hierarchy, but it was decided that it would be best for it to also support accepting an array of post types to keep parity with get_page_by_path.

On a personal note, after having used WordPress for about a decade, this is my first patch that has been merged to core and I’m pretty excited to have finally contributed something back.

We’ve open sourced our Gigaom Copy Layout plugin - a simple plugin that exports/imports widget configurations as a base64 encoded string!

A little background

WordPress widgets do a wonderful job at providing a way to customize the content that is displayed on your site without requiring the deployment of code. Here at Gigaom, we use widgets heavily on all of our properties. On any given day, we have at least 10 development sites for each of those properties and spin up new virtual machines at the drop of a hat to do quality assurance.

As you can imagine, keeping the configuration of widgets in sync between all of those resources can be a huge pain. Historically, synchronizing those configurations was done one of two ways:

  1. Importing wp-options data from one site into another.
  2. Manually comparing two sites and hoping nothing is missed.

Neither option is ideal and both are prone to errors.

A developer at Plymouth State University fought with this frustration and came up with a solution tailored to the WordPress environment that they were running.  The beauty of open source has allowed us to take that idea and turn it into something distributable to a wider audience. Enter our open source WordPress plugin: Gigaom Copy Layout. It isn’t a magical solution that keeps your site widget configurations in sync. Instead, it provides a portable configuration set that can be consumed on your myriad of development (and production) sites.

Exporting

  • Go to Appearance > Copy Layout
  • Copy the base64 encoded string (we commit “production-level” widget configurations into our Git repository)

Importing

  • Go to Appearance > Copy Layout
  • Paste a base64 encoded export string into the second textarea and click “Save”

Gigaom was invited as a beta publishing partner of Facebook’s new Paper app. It was certainly an honor to be included in select handful of technology publishers called up for the beta. The implementation was so simple — a few meta tags on our side and sending them an image file of our logo of the appropriate dimensions for overlaying on our content. That was it… seemingly…

The frustrating thing was that the meta tags duplicated tags used by other standards… even the OpenGraph ones… and Facebook’s own validator didn’t like these new tags and was spitting all sorts of vaguely written error messages that we couldn’t interpret. It all made for a lot of self-doubt but, in the end, it all worked out.

Needless to say, the impact on launch was tremendous. Facebook became our #1 social referrer for that (2/2) and the next few days…Eventually, it settled at about twice our usual referral traffic.papereffect

However, Facebook is still in 3rd place behind Twitter and Stumbleupon… and an occasional Reddit…

If you have seen Andrew Nacin talk about capabilities in WordPress you know how simultaneously powerful and frustrating they can be. In that talk he states:

When you are dealing with roles and capabilities directly in the database – which is very likely the only way most of you know how to do it – it’s really tough to play nicely in the ecosystem. It doesn’t work very well.

Nacin then describes how to use the 'user_has_cap' and 'map_meta_cap' filters to add and remove capabilities from users without having to store your changes in the database. This is a fantastic way to use fewer capabilities with greater flexibility.

But, what about roles?

Before we address that, let’s describe why we would want to use roles in the first place. Roles do two things that are unique and wonderful in WordPress.

1. They provide a visual way in the Dashboard to view users in a categorized manner.

Imagine you have various types of subscribers: Trial, Premium, etc. It sure would be nice for people who are doing support to be able to peek into the Dashboard and see exactly what type of subscriber someone is, or even a list of all subscribers of a given role. Since roles already provide a sweet WordPress UI to do this, we should use it.

2. They provide a way to manually set permissions.

Typically you want to do your permission checking through capabilities, but if all your critical capabilities are being defined dynamically based on other user meta, we are going to need a way to do manual overrides. Inevitably you’ll have a situation where someone needs a capability to do something on the site. Let’s consider a site with paid subscribers, you may need to grant someone the capabilities of a subscriber without charging them and without mixing them up with paid subscribers. We certainly don’t want to hard code the adding of that capability for the user(s), but if we have a role we could assign them in the Dashboard, that’d be perfect.

Fine. Roles are awesome. How can we add these dynamically?

In a perfect world, WordPress would have an easy filter we could simply hook into and add our dynamic roles. Alas, there is nothing quite that simple. All is not lost though, because roles are stored as options. That means we can filter the option with something like this:

add_filter( 'option_' . $wpdb->prefix . 'user_roles', 'gigaom_filter_user_roles');
function gigaom_filter_user_roles( $roles ) {
	$roles['subscriber-lifetime'] => array(
		'name' => 'Subscriber, Lifetime',
		'capabilities' => array(
			'read' => 1,
			'level_0' => 1,
		),
	);

	return $roles;
}

This added the role dynamically, but it is still less than ideal. What happens when WordPress gets an update that adds another capability to “subscriber”? At best we have a maintenance headache; at worst we have a bug with our “subscriber-lifetime” role that could be very difficult to track down. (Note: “subscriber” is a simple example, but try considering “editor”, it has 34 capabilities!)

What would be really nice is if we could say something like 'extends' => 'subscriber' and have it dynamically pull all current subscriber caps and give those to this new role. How about if we could also say 'add_caps' => array( 'read_private_posts' ), or 'remove_caps' => array( 'read' ) (OK that last one is a bad example, but we still might want to remove a capability in the future).

With those ideas in mind, we wrapped it all up in a nice little plugin called Gigaom Roles. Once activated, it’s as simple as this:

add_filter( 'go_roles', 'gigaom_filter_user_roles' );
function gigaom_filter_user_roles( $roles ) {
	$roles['subscriber-lifetime'] => array(
		'name' => 'Subscriber, Lifetime',
		'extends' => 'subscriber',
	);

	return $roles;
}

It is still good advice to use roles sparingly. However, this is a clean way to maintain custom roles when you need them.

We use Zendesk as our ticketing system for various groups here at Gigaom — for bug reporting, external support, errors in our tags and even to track our internal IT requests. To ensure the people responsible for each ticket queue have all the information they need, we decided to create forms for the reporters/requestors to fill out. For forms, we  have always used Wufoo here at Gigaom. It all sounded so simple…we create a form in Wufoo and set the “mail to” address to whatever@gigaom.zendesk.com and then create a “trigger” on zendesk that assigns the ticket to the right person depending on what “whatever” was (support or bugs or tags…or, um, whatever).

But the emails wouldn’t come in to the right queue. After a bunch of head-scratching and help from Zendesk’s help team. We realized the emails were being classified as spam (due to the no-reply@wufoo.com email address) and being put into a “suspended” folder. The solution seemed easy — just whitelist *@wufoo.com. No go…Way more head-scratching. More back and forth with Zendesk help.

It turns out we had configured our Wufoo form to add an (ever-incrementing) number to the email subject…eg. “Bug report [#28]“.  This seemed like a good idea originally because then people internally could refer to the request number. However, Zendesk thought that this was a ticket in its system and tried to assign it to the agent that handled that ticket originally. Not finding such a person, it sent the email to the suspeneded queue.

Solution — remove the form request in Wufoo…and it all worked nicely. Not that any of this gets us fixing  bugs any quicker….

Our readers come to Gigaom to read. This email reminded us of that after we made a mistake:

I overall like your site redesign, but one suggestion I have is to NOT auto focus on the search box when the page loads. Because the text field has the focus, I’m unable to scroll down the page with my keyboard when the page loads. I typically load different pages in my browser all using the keyboard and scroll down using the keyboard, but now I always have to click outside the search box. Thanks.

We actually recognized the mistake pretty quickly ourselves and may have reverted the change before I spotted this email, but I love that we can trust our readers to remind us of what matters.

123page 1 of 3