Note to self: WordPress comments are loaded in comments_tempate() not in WP_Query

This had somehow escaped my notice, but recently I was experimenting with a DRYing out my WordPress base theme and wanted to create some custom display logic for comments so I removed the call to comments_template() from my single post template.

I had assumed that all it really did was load the comments.php template from the theme or a fallback when needed. What I didn’t realise is that the comments for a given post or page are not loaded during the main query, but are queried directly in the comments_template() function. (The only exception is for RSS comment feeds which are loaded as part of the main query.)

The function is also responsible for stuffing the comments into the $wp_query global and setting the cpage query variables correctly. ┬áIt is a little frustrating as it means the theme must either some comment.php template even if it’s empty or recreate the comment display logic from comments_template().

De-duplicating MySQL rows in the WordPress post meta table

I recently needed to prune some duplicate rows from the WordPress post meta table. For reasons I won’t go into, there were two copies of many post meta values for most of the posts in the database and I wanted to remove the extra copies whilst keeping rest.

After trying various solutions (on a backup of the database) involving sub selects and unique keys, the simplest and fastest solution seems to be to create a new table and copy over rows I wanted to keep.

CREATE TABLE tmp_meta
LIKE wp_postmeta AS
SELECT MIN(meta_id) as meta_id, post_id, meta_key, meta_value
FROM wp_postmeta
GROUP BY post_id, meta_key, meta_value;

This creates a new table with the same specification as the wp_postmeta table and inserts only one copy of each row based on the post_id, key and value. Then it’s just a question of swapping the names of the tables and testing the result.

DROP TABLE wp_postmeta;
RENAME TABLE tmp_meta TO wp_postmeta;

Note that this will take the meta value with the lowest meta_id and drop the rest. As always, take a backup of the database before doing this on your actual site.

Check available PHP version in a WordPress Plugin

Currently, WordPress only requires PHP 5.2.4. There has been a lot of debate about this, and I personally think that the core team should bite the bullet and set a date for moving to PHP 5.3 and beyond for reasons of security, performance and the numerous new features it would make available.

However, it seems unlikely that’s going to happen any time soon. This presents a problem: I develop on 5.4 and almost every client site I build uses features that are only available in 5.3 and beyond. If any of my custom code unexpectedly lands on a server where 5.2 is the latest version it will go belly-up and leave me staring at a white screen of death.

Now, of course, I can go in and change the cPanel settings, htaccess or whatever is needed to get things working. But what if I want to ship a plugin? I don’t want someone else’s site to go down without any explanation, so I need to check the available version before including any code that will cause a fatal error.

DBisso_Version_Check

To help manage this I built a little class that can be included with any plugin (or added to the mu-plugins folder) which does the checking for you. It does two things:

  • On activate_plugin it checks the available version against whatever you specify as the minimum and prevents activation if it’s too low.
  • If the plugin has already been activated, it checks for the PHP version and prevents any further plugin code execution if it is insufficient.

In both cases, a message is displayed to the user if they are logged in or added to the the system error log if they are not.

At the moment the code and instructions are available on GitHub. I am looking into adding it to packagist.org so it can be installed easily via composer. In the meantime you can add the following to your composer.json:

"repositories": [
    {
        "type": "git",
        "url": "https://github.com/dbisso/wp-version-check.git"
    }
],
"require": {
    "dbisso/wp-version-check": "1.*"
}

Then composer update to bring in the code.

Use it in you plugin’s main file (ie. the one with the WordPress plugin data headers):

/*
Plugin Name: My plugin
Plugin URI: http://danisadesigner.com/wordpress/my-plugin
Description: Does something
Version: 0.1
Author: Dan Bissonnet <[email protected]>
Author URI: http://danisadesigner.com/
*/

if ( ! class_exists( 'DBisso_Version_Check' ) ) {
    include_once 'vendor/dbisso/wp-version-check/DBisso_Version_Check.php';
}

// Check for PHP version and then kick things off
DBisso_Version_Check::bootstrap( '5.3.5', __FILE__, dirname( __FILE__ ) . '/plugin.php' );

DBisso_Version_Check::bootstrap() takes three arguments:

  • (string) Minimum PHP version.
  • (string) The root plugin file – usually __FILE__ will do the trick.
  • (string) The initialising plugin file. This is where your plugin’s main code lives.

Your plugin needs to be organised in so that the main plugin file (the one with the data comment at the top) calls DBisso_Version_Checker first which will in turn include the file with the actual code.

Hopefully it helps out some other developers with the same problem.