Delete All Your Spam Comments with WP_CLI

I had 8,000+ spam comments that needed to be cleaned up and I certainly wasn’t going to delete them 100 at a time … sheesh.

wp comment list --fields=comment_ID,comment_approved --status=spam | xargs -I {} wp comment delete {}

Kudos to Virgin America

Kudos to VA for rethinking airline UX

Kudos to VA for rethinking airline UX

It takes balls to do something completely different. Virgin America has completely destroyed all the “rules” to online airline ticket purchasing. Love it! I know it’s been around for a few months, but I just now used it. So … you know … I’m late as usual.

Daily Lesson

I’ve discovered that listening to Stevie Ray Vaughn requires a certain emotional and aesthetic context. But when it’s right, it’s just so damn right … #texasflood

Quick List: Things WordPress Plugins Developers Can Do to Help Their Plugins Scale

1) For heavy backend operations like generating reports, don’t generate the screen on the init hook. Schedule a cron job and generate it periodically … if the administrator needs it right away, give them a refresh button.

2) Don’t autoload options unless they are really needed on every page load. And if you do autoload the option then make sure it isn’t too big 10KB should be plenty. Keep in mind if you create your option for the first time using the update_option(); [codex] function it will be autoloaded by default. So you should instead intiate the option using add_option('myoption','myvalue', false);

3) Don’t use wp_postmeta fields for numeric calculations. WordPress strongly encourages developers to work within their custom post type API, which is good, but that doesn’t mean the Metadata API is equally good for all data types. For instance a post_type, “order”, in which the record will have fields like ‘subtotal’,’tax’,’discount’,’grand_total’, which will likely be summed and counted and multiplied etc, go ahead and use a custom table with a foreign key on post_id.

Use the WordPress Heartbeat API

A new WordPress performance bottleneck is looming:  admin-ajax.php.

More and more plugins are relying on the admin-ajax.php and the wp_ajax_ hook to deliver their content and functionality making WordPress more dynamic than ever. The problem is that if you have multiple plugins running all making their own wp_ajax calls without concern for what the others do, you end up with 4 or 5 server requests being required to render one page. This is a nightmare for server admins, especially since wp_ajax_ is often implemented as a POST request which allows it to bypass caching from cloudflare or varnish or what have you.

The solution is not to abandon wp_ajax_ but to come up with a better way to manage it. I really like what the Heartbeat API is doing. Instead of each client plugin managing it’s own request, you can tie into an existing “heartbeat” to get the info you need. I would recommend all plugin and theme developers use the Heartbeat API approach if at all possible. At least until wp_ajax_ gets  streamlined.

Should I Use WordPress Multisite? Why Not?

WordPress Multisite ( a.k.a WPMU )  has been alluring ever since it was introduced. Sweet! Now I can start my own blog network like, next stop global domination!

Ah, were it that easy I would be an enormous fan. But global domination doesn’t come without hard work unfortunately and if you’re not ready for that then WordPress Multisite can be a curse rather than a blessing.

First let’s establish what is awesome about WordPress Multisite and when you should use it. As a developer you always get talked into building sites for friends and family. To save myself time I have a multisite install I use to host these charity sites. It makes it super convenient for me. Less maintenance. Less setup time. Add the WordPress Domain Mapping plugin and I’m rockin’. WordPress MU is great for this.

It’s also great if you really do need a “network” of blogs. In some cases this is exactly your goal and WP Multisite is the only tool that’ll get you there. Great! Use it!

But it’s the improper use that irks me. Too often development agencies see it a as a shortcut to hosting their client sites or, worse, someone who is not a server admin thinks they will make a quick buck throwing up a multisite on someone else’s servers and selling hosting.

So before using multisite there are a few things to know about it:

  1. It can be a bitch to scale. Each blog instance on your multisite creates it’s own set of 11 tables … no big deal for 50 sites. But once you hit 100 – 200 sites you’re going to start getting some headaches on shared hosting, and just 250 – 500 sites is enough to crater an entire VPS.
  2. Maintenance Costs Grow Exponentially. The cost to maintain your first 50 WPMU sites is relatively cheap. You definitely make some money up front. But the bloating database starts getting expensive to maintain when it has to have it’s own database server, and then even more when it has to be shared across several. Moreover, development slows down since you spend more time on performance issues … that cross site feed that worked fine for 50 sites is really dragging at 250. Also, try creating a dev environment for a network, not as easy as you think.
  3. Bugs Get More Dangerous. The cost of a mistake also grows. Now you have all your customers connected to one WordPress Multisite code base and database. But your growing customer base requires you to bring on some new developers. And guess what? One of them isn’t that great and commits some bad PHP to the code base. Now all of your customers are pissed, instead of just the one he/she was working on.

WordPress MU is appealing and sexy. It’s like magic. No more updating 100 installs manually, one and done, Woot! But it’s really just deferring costs until later. If you’re prepared for them, maybe it’s still worth the trade off, but in most cases it’s not. There are plenty of other services that will manage your code upgrades for you without having to use WordPress MU and that’s really the main benefit.

Other Reading

Obfuscate Your Code at Your Own Risk

Looks like ZippyKid no longer supports WishList Member. I think it raises a good point about obfuscating code. Hiding your code behind some sort of encryption like Base64 may prevent your code from being ripped off, but it also prevents it from being improved and supported. If WLM made it’s code transparent it could share the burden of support and innovation with other services and developers. ZippyKid/WP Engine/WPMU/ and on and on. But the obfuscation instead guarantees this vast community of resources can be of no benefit to WLM at all. I hope it’s worth it.

List your MySQL Tables According to Size or Row Count

If you’ve ever been debugging a large Multisite installation that’s having MySQL memory issues you know how maddening it can be. Sometimes you can turn on slow logging and find the source of the issue. But sometimes it’s not just about slow queries, it’s about the shear size of the tables and the number of queries being run against them. One trick is to generate a list of all the tables on the site and sort them by size. This will help you narrow down trouble spots.

SELECT table_name,table_rows,data_length FROM TABLES where table_schema = 'DBNAME' AND table_rows > 0 ORDER BY data_length DESC LIMIT 0,50;

This will produce a list like the following (see below). You can adjust the sort order and limit based on your needs. This query isn’t all that helpful in cases of small installs. But in an installation with 500+ tables it can help you narrow down the issue quickly. WARNING: this query can take a long time to run depending on the number of databases on your server and the number of tables in the Dbs.

table_name	table_rows	data_length
wp_options	125	65536
wp_blogs	1	16384
wp_sitemeta	25	16384
wp_site	1	16384
wp_posts	3	16384
wp_postmeta	1	16384
wp_users	2	16384
wp_comments	1	16384
wp_usermeta	31	16384
wp_links	7	560
wp_term_relationships	8	168
wp_term_taxonomy	2	84
wp_terms	2	72

Regex to Match Opening Slash

Just in case anyone needs a regex that tells you that a string does NOT have an slash at the beginning, here you go. This is useful for handling paths defined by users and you want to check whether it is a relative or absolute path.

  preg_match("#^(?!\/).*#", $string);

Giving WooCommerce a Try

Just a quick announcement. I’m now using WooCommerce for my eCommerce so please let me know if you have an issue. I was using Cart66 but it makes use of sessions, which are disallowed by WPEngine for both security and performance reasons. my WooCommerce setup looks ugly at the moment because I haven’t had time to work on the styles yet, so bear with me.