Tag Archives: WordPress

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

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

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

Recent Anthologize updates

Anthologize, you are neglected, but not forgotten!

In the past week or so, I’ve done two maintenance releases (0.7.2 and 0.7.3) for Anthologize. A few highlights:

  • Fixed some issues with the way TCPDF saves image files in a temporary cache. This should help to avoid the dreaded “TCPDF ERROR: Can’t open image file” fatal error when exporting to PDF on some server configurations.
  • Fixed some issues with the way that Anthologize’s JS and CSS files are loaded, for better compatibility with other plugins and with SSL wp-admin.
  • Fixed a bug that gave non-admins the ability to change settings on some multisite configurations.

Speaking of not forgotten, I haven’t forgotten my friends who supported my Anthologize campaign back in 2012. This post goes out to Eric A Mann, an outstanding WordPress developer and blogger. Thanks for supporting Anthologize, Eric!

Default Gravatar images and SSL

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

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

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

There are a couple strategies for working around the problem.

  • Use Gravatar’s defaults instead – Gravatar hosts a number of default images that you can use, instead of a local image. This is especially pertinent in the case of BuddyPress. BP’s default behavior is to construct Gravatar requests like this: http://www.gravatar.com/avatar/00000000000000000000000000000000?d=http%3A%2F%2Fexample.com%2Fimages%2Fwp-content%2Fplugins%2Fbuddypress%2Fbp-core%2Fimages%2Fmystery-man.jpg. The thing is that this mystery-man.jpg that ships with BuddyPress is the same image as what you get with ?d=mm. So an easy way around the problem of Gravatar reading from your SSL-protected site is to avoid Gravatar from making any requests to your site at all. In BuddyPress, use the following:
    function bbg_use_gravatar_mm() {
        return 'mm';
    }
    add_filter( 'bp_core_mysteryman_src', 'bbg_use_gravatar_mm' );
    
  • Allow non-SSL access to your default – As suggested in Eric’s post, you can tell your webserver that some of your content can be served over HTTP rather than HTTPS. For example, on one of the sites I’m working on, we force HTTPS for all requests using an .htaccess rule. I can amend it to allow an exception for the custom Gravatar default:
    RewriteCond %{HTTPS} off
    RewriteCond %{REQUEST_URI} !^/wp\-content/themes/yourtheme/images/default\-gravatar.jpg$
    RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R,L]
    

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

    function bbg_custom_default_avatar() {
        return set_url_scheme( get_stylesheet_directory_uri() . '/images/default-gravatar.jpg', 'http' );
    }
    add_filter( 'bp_core_mysteryman_src', 'bbg_custom_default_avatar' );
    

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

Convert multi-db WordPress mysqldump to single-db

On a number of client sites, I use HyperDB or SharDB to spread a WordPress Multisite installation across multiple databases on a single server. However, in my local dev environments, it’s annoying to have thousands of databases. So I use the following technique to create a copy of the remote site that operates in a single database locally.

  1. Use mysqldump to get a backup file. The following command ensures that you don’t pull in information_schema or any other unrelated databases; you can add other DBs to ignore to the NOT IN list:
    $ mysql -u [username] -p -B -N -e "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mysql','tmp','innodb','information_schema','performance_schema')" | xargs mysqldump -u [username] -p --add-drop-table --skip-lock-tables --quick --extended-insert --result-file=[path/to/your/dumpfile.sql] --databases
    
  2. Use sed to remove all the ‘CREATE DATABASE’ and ‘USE’ lines in the dumpfile. This prevents the multiple databases from being created when importing locally.
    $ sed -i '' -e'/^CREATE DATABASE /d' /path/to/dumpfile.sql
    $ sed -i '' -e'/^USE /d' /path/to/dumpfile.sql
    
  3. Get the dumpfile to your local machine, and import:
    $ mysql -u [username] -p -e "create database foo"
    $ mysql -u [username] -p foo < ~/path/to/local/dumpfile.sql
    

    (or whatever technique you use for mysql imports) (don’t know why my code formatter is converting < to &lt; but you get the idea).

Getting started with WordPress plugin development

I got an email with the following question, and figured I may as well answer publicly. The question comes from someone who’s an experienced programmer, but has never worked with WordPress before.

[...] I wondered if you had some helpful advice on learning the basics of WP plugin development. I’m mostly hoping there are frameworks/libraries that the community is currently using.

I don’t know of a widely-used library of general WP plugin development tools. Partly this is because WP itself partially qualifies as a “library”, insofar as it provides ready-to-use functions for saving data to the database, URL routing, template loading, user management, etc. And partly it’s because the architecture of WP is so wide open that it’d be difficult to build a more generalized library that covered even a majority of the possible modifications you might make to stock WordPress.

That said, here are a few useful tools that I know of:

  • The official WP documentation on writing a plugin is good for learning about plugin manifests as well as a top-level overview of the aspects of plugin development.
  • The official Plugin API page is also a good starting point. It explains WP’s hook system, which is the foundation for plugin development.
  • Pippin Williamson has written a series called Plugin Development 101 that features a set of video tutorials on common plugin development techniques. Costs a couple bucks, but Pippin is a smart dude and I’m sure the videos are a really good way to get started.
  • There are a couple of tools that can be used to generate boilerplate and basic file setup for plugins. The ones I know of are https://github.com/tommcfarlin/WordPress-Plugin-Boilerplate and the wp scaffold plugin command in WP-CLI.
  • The book Professional WordPress Plugin Development is very solid, and a good investment for those who like to learn this kinda stuff through books.

My #1 piece of advice to people getting started with WP plugin development is to find a plugin that does something sorta like what they are trying to do and to reverse engineer it. For me, this is far faster and more practical than any hello-world tutorial or sequential set of lessons. YMMV.

If anyone has other suggestions, please feel free to add them in the comments.

Commit messages, tickets, and inline docs

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

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

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

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

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

Vim function for correcting whitespace to WP standards

When doing client work, especially in a team, I like to urge adherence to the WordPress coding standards. This is especially important with whitespace, in particular when other members of the team have their IDEs set up in certain ways that frustrate the standards. I wrote this quick little functions for your .vimrc that does some whitespace cleanup in the currently open buffer. (I’m sure there are a thousand better ways to do it, and you should feel free to let me know in the comments. This is just what I put together in 15 minutes.)

I’ve mapped it to F8. Modify as you’d like.

WordPress/BuddyPress registration and the Office 365 email filter

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

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

function bbg_activation_email_content( $message ) {
	return str_replace( '?key=', '?activationk=', $message );
}
add_filter( 'bp_core_activation_signup_user_notification_message', 'bbg_activation_email_content' );

function bbg_screen_activation() {
	global $bp;

if ( !bp_is_current_component( 'activate' ) )
		return false;

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

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

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

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

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

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

$bp->activation_complete = true;
	}

bp_core_load_template( apply_filters( 'bp_core_template_activate', array( 'activate', 'registration/activate' ) ) );
}
remove_action( 'bp_screens', 'bp_core_screen_activation' );
add_action( 'bp_screens', 'bbg_screen_activation' );

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

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

A recursive sorta-version of wp_parse_args()

WordPress trick: wp_parse_args() is a helpful function for taking configuration arrays passed to a function and combining them intelligently with the default arguments for the function. I needed a recursive version, for use with multi-dimensional arrays of arbitrary depth, so I wrote the little ditty below. As I note in the docs, there are fundamental ambiguities in the process of rectifying multi-d arrays, and the technique I’ve chosen is specific to my implementation. Use at your own risk.

Get your Boone fix

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

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