Measuring the utility of WP_REST_Posts_Controller

A good measure of the utility of WP_REST_Posts_Controller and brethren would be to test how much (or little) time it takes for a developer to correctly model their custom post type data by extending it. If it’s easy to do, then we’ve established a great abstraction. If there are pain points or places we need to work around, then we should refine the abstraction.

Simple WP-CLI backup and restore

It would be neat if WP-CLI included a rudimentary backup and restore process for this use case:

richard.tape [8:19 AM] anyone used wocker? I’m looking to set up a dev environment that I can share with someone else so they’re able to more easily help me debug a problem and I want to modify the base containers and then package the whole thing up so I can just pass that to them and they just spin it up and are in the same shape I’m in… ideas?

wp backup would create a tarball of the database, WordPress files, and (optionally) the uploads directory. wp restore could then read said tarball, and expand it to a working WordPress install.

We could even potentially parse the original wp-config.php into a manifest file, which would permit the restoration process to override some details.

Love and profit for wp search-replace — thanks Pantheon!

Moving databases between environments is tough. Many things can break in the process, and a single issue can sink hours of your valuable time. Migrating WordPress databases between environments is especially tricky for two reasons:

  • Instead of relative paths, WordPress stores full URLs in the database, in many different columns and tables.
  • These URLs, along with other data, can be stored as PHP-serialized blobs. Because PHP serialization includes the string length in the blob, replacing one value with another value of a different length also needs to update the encoding as well.

WP-CLI’s search-replace command addresses both of these problems for you, with its awareness of WordPress’ tables, and intuitive handling of serialized data.

Last month, Pantheon generously sponsored 15 hours of my time to address some of the long-standing bugs in the backlog, and make a few substantial enhancements too. On Pantheon, wp search-replace is an integral part of the Pantheon Workflow.

Let’s take a look at how search-replace works, and then we’ll review the new features coming in WP-CLI v0.22.0.

Making search-replace an integral part to your workflow

WP-CLI search-replace only requires two parameters: <old-string> and <new-string>. On Pantheon, here’s how it could be used to transform a database cloned from Live into Test:

wp search-replace '' ''

By default, WP-CLI searches through all tables registered to the $wpdb object. In each column of each table, it first inspects the column’s rows to see if serialized data is present. If it discovers serialized data, then it iterates through all of the rows, de-serializes data as relevant, recursively performs a search and replace procedure, and updates the row in the database. When no serialized data is present in any of the rows, the replacement procedure is a much simpler MySQL UPDATE statement.

On multisite, WP-CLI defaults to performing search-replace on a single site. You can search-replace across all sites in the network with the --network flag.

wp search-replace '' '--network'

Want to inspect the results of your search-replace command without making changes to the database? Use the --dry-run flag to mock the entire operation, and see a summary of how your database would’ve been modified.

Pantheon’s sponsored improvements to search-replace

Here are a few of the improvements you can expect to see in the forthcoming WP-CLI v0.22.0:

  • A huge performance boost! Instead of running a MYSQL LIKE statement every 1000 rows, WP-CLI now just runs it once. On a post meta table of ~3.5 million rows where 75,610 rows were affected, this change improved execution time from 734.926s to 225.509s (3.3x faster).
  • Use the --export=<filename> argument to create a SQL file of your transformed data, instead of making updates to the database. This is a helpful feature when you want to prepare a database for a new environment without having to import and then run search-replace.
  • Wildcards can be used in table names. search-replace against meta tables with wp search-replace <old-string> <new-string> '*meta*'. Note: the table pattern needs to be quoted, as * is a special character in Bash.
  • Execution time is indicated when running search-replace with the --verbose flag, in case you’re curious to see how long each replacement operation is taking.

Happy to see these new features? Please share the love on Twitter 🙂

Back on

If you’re seeing this, then my blog is back to being hosted on

The primary reason for this? I want to blog more often. The writing interface in is now much, much better than what you get in a standard WordPress install. Plus, there’s also something to be said about not having the mental overhead of site management every time you go to write a blog post.

This domain’s history: switched from 1&1 to WebFaction in June 2009, to Slicehost in May 2010, back to WebFaction in September 2010, to in November 2011to Digital Ocean in March 2014, and back to Webfaction in January 2015.

Thoughts on online conduct

The latest outrage within my sphere of the internet seems to be the PHP project’s proposed Code of Conduct (PHP internals threadreddit thread). My cursory opinion: I like the idea, and the language of this particular proposal seems a bit draconian. While the PHP CoC doesn’t directly impact me, this seems like a good opportunity to jot down some thoughts on online conduct.

I am a white, privileged male who grew up in an upper middle class family. I didn’t have to work in high school, and my college would’ve been completely paid for, had I chosen to complete it. I live in a comfortable house in well-developed suburbs, with easy access to many local services. I identify as fiscally conservative, socially progressive, and think politicians are a bunch of schmucks (so you could probably call me libertarian).

As someone of privilege, I try to refrain from discussing controversial topics on the web. All too often they devolve into a flame war, “a heated argument between two individuals, that results in those involved posting personal attacks on each other during or instead of debating the topic at hand.” But, as a maintainer of several open source projects and active contributor to many others, codes of conduct have a direct impact on my daily life.

I do believe in the golden rule, and do my best to treat others as I wish to be treated. I think communities, online and off, can benefit from explicitly stated expectations of behavior — even more so when leadership role models ideal conduct. I also understand it’s difficult to regulate away human behavior, and take an active concern with who holds the power to enforce rules. Power is a real thing. Lastly, I know that if a conversation turns into personal attacks, it can be effective to explicitly address emotions — “it hurts me when you say…” — because it brings empathy to the forefront.

Text-based communication, particularly as we practice it on the internet, is really hard. Let me say that again for emphasis: text-based communication is really hard. Merlin Mann and Dan Benjamin have a great podcast episode about emotional density, which conveys many of my thoughts on the subject. In short, text loses many of the voice intonation and body language nuances we humans actually use to communicate. Think about it this way: text is a medium where 2/3 of packets are lost in transmission. If we chose to collaborate on the web, this is a constraint we must acknowledge and embrace.

Be nice to others. Go out of your way to be helpful. And, if someone flames you, understand they might be operating a computer without their first cup of coffee for the day.

Verifying WordPress migrations

It seems like every time I do a migration with the WordPress importer, something about my data breaks. For instance, while writing my Year in Review post just now, I noticed last year’s post has an incorrect image:

2015-12-30 at 3.23 PM

The image should be the visualization.

It would be really neat if I could verify a migration with WP-CLI. Using the WXR file as the baseline, the command would iterate through all of the data in the file, compare it to what’s present in WordPress, and alert me if anything is missing or unexpectedly different.

Decisions, not options, in the WordPress Customizer

Earlier this month, I helped relaunch Pottery Barn’s blog. The homepage and each brand page (PBteen example) are moderately configurable through the WordPress Customizer. Building this functionality was an opportunity to make user-friendly decisions about the management experience.

Smarter Featured Gallery

2015-12-30 at 9.27 AM

By default, the topmost UI element on each homepage will display the most recent published post. In the Customizer, the Pottery Barn team can choose one or more posts for promotion with an AJAX post selection tool (plugin in-progress). If multiple posts are selected, then the UI element turns into a carousel (powered by Slick).

Look ma, no checkboxes!

Magical Pin Promotion

2015-12-30 at 9.39 AM

Further down the homepage, the Pottery Barn team wanted to promote their top Pins from Pinterest. Rather than create a more complicated workflow of uploading images and completing multiple fields per Pin, I decided to magically pull in Pin metadata from their Open Graph / Twitter Card tags.

Drop a link in — voila!

If you’re considering a similar approach, here are a few technical details I worked out:

  • Rather than make a number of on-going frontend HTTP requests, I decided to fetch the metadata when the links are saved, and store it in options.
  • Pinterest will block your IP address if it thinks you’re a bot. If your code mysteriously stops working, you might want to check the response.
  • Pinterest’s Twitter Card image source is better to work with than Facebook Open Graph because Pinterest forcefully crops the Open Graph image to a Facebook-friendly proportion. The Twitter Card image source appears to be the original proportion.

The pain of customizing WordPress themes

2015-12-15 at 9.06 AM

Choosing a WordPress theme from the Customizer is a bit painful.

First of all, “Search installed themes” doesn’t make sense as a string on a hosted WordPress service. As a user, I have no ability to install new themes. It could be edited to just “Search themes”

Second, as a user with a blog, I want to choose from themes that showcase my words. The first suggested theme appears to be a product portfolio, and the second suggested theme is for a restaurant website. I should be able to indicate I just want to see writing themes.

Third, the “371” indicator next to the “Customizing Themes” heading has no meaning whatsovever. 371 what? Is that power user UI?