How To Build A WordPress Plugin

I’ve recently been learning the ins and outs of basic WordPress development – mostly writing functions as part of a custom theme. One of those functions began as a simple automated post expiry process, because I couldn’t find a decent existing plugin to do the job.

As I worked on the function, I thought of other expiry criteria I’d like to use, so I worked on those, too. Eventually, I ended up with three or four sets of criteria and half a dozen other ideas in my head, so I thought I’d build a proper plugin.

Which brings me to this article, since I’ve had to learn how to build a WordPress plugin from scratch!

Before we start on any actual code and stuff, let’s define what the plugin should do. We’ll keep it very simple for the moment and add bits on later:

Check through all published posts and find those that are more than 30 days old. Move them to the trash.

The plugin will run a custom query against the database, return the list of posts and then let WP handle what to do with them. This is partly because I’m better at SQL than I am at php, but also because it’s a good process: by separating the function into the “find” and “do” parts, we can extend or change either part independently.

The basic structure

All plugins are made up of one or more files. At the simplest level, there’s just one php file with all the functions and everything inside it. My plugin is called TIEexpire, so my php file will be called TIEexpire.php and it will go in a folder called TIEexpire.

When this folder is uploaded to a WP installation, in the wp-content/plugins folder, “TIEexpire” will appear on the blog’s plugin list.

The header info

All “official” plugins (those available on WP.org) have a standard header in the php file. You don’t have to put this in your code, but it contains stuff like the description text which shows up on the WP plugins page, so it’s a good idea.

The standard header looks like this:

In my case, I don’t really need the Author URI (because I don’t have a separate site to point to) or the License info (because I won’t be releasing the plugin to the public through WP), so I’ll drop those from my php file.

The function

The bulk of the plugin is, of course, the function. As I mentioned above, I’m going to split it into two chunks: (a) getting the right posts and (b) trashing them.

First, let’s get the published posts over 30 days old: they have to be of type ‘post’ and status ‘published’ – that’s simple enough – but they also need to have a posting date over 30 days ago. Here’s the MySQL query to find the posts:

SELECT * FROM wp_posts
WHERE wp_posts.post_status = 'publish'
AND wp_posts.post_type = 'post'
AND wp_posts.post_date < DATE_SUB(NOW(), INTERVAL 30 DAY)

While this will work, it is too limited: there is no guarantee that the WP install uses "wp_" as its database table prefix (defined when WP is installed). So I need to use the "$wpdb" object instead:

SELECT * FROM $wpdb->posts
WHERE $wpdb->posts.post_status = 'publish'
AND $wpdb->posts.post_type = 'post'
AND $wpdb->posts.post_date < DATE_SUB(NOW(), INTERVAL 30 DAY)

This makes sure that whatever the prefix is, the function assigns it correctly. As a special note, using $wpdb without a qualifier only works on the base WP tables (as far as I can see). If you need to refer to a non-standard table, such as one used in another plugin, you must use "{$wpdb->prefix}" in the place of "$wpdb->".

So there's our SQL. To run this as a query in WP, we need to surround it with a bit of code. Here's how the first part of the plugin file looks in WP terms:

function expirebydays() {
  global $wpdb;
  $dayquery = "SELECT * FROM $wpdb->posts
               WHERE $wpdb->posts.post_status = 'publish'
               AND $wpdb->posts.post_type = 'post'
               AND $wpdb->posts.post_date < DATE_SUB(NOW(), INTERVAL 30 DAY)";
  $result = $wpdb->get_results($dayquery);

This returns a list of results in the $result array, which we can use to do whatever we want with the posts we found. In my case, I'm going to delete them, so I will use a simple "foreach" loop and tell WP to drop the posts into trash.

foreach ($result as $post) {
  setup_postdata($post);
  $postid = $post->ID;
  wp_delete_post($postid);
}

This bit of code says "take the $result array and treat each line as details of a post; set up all that post's data so that I can use standard WP functions on it; set the value of $postid to be the ID of the post we're dealing with; delete that post by moving it to trash; move on to the next post in the array."

You can stick that bit of code straight onto the end of the previous chunk, but you'll need to close the function's braces and the php tag to finish the job completely.

Here's the final code in TIEexpire.php:

posts
               WHERE $wpdb->posts.post_status = 'publish'
               AND $wpdb->posts.post_type = 'post'
               AND $wpdb->posts.post_date < DATE_SUB(NOW(), INTERVAL 30 DAY)";
  $result = $wpdb->get_results($dayquery);

  foreach ($result as $post) {
    setup_postdata($post);
    $postid = $post->ID;
    wp_delete_post($postid);
  }
}
?>

Testing the plugin

So we have a file called TIEexpire.php in a folder called TIEexpire. How can we test that it works? By uploading it to a test WordPress installation (with data to work on) and calling the function.

Use your FTP app to put the TIEexpire folder into wp-content/plugins, then log in to WordPress as admin: you'll see TIEexpire on the plugins list. Click the 'Activate' option and, assuming there are no errors in the code, the function will be available for use.

Because we haven't "hooked" the function into any standard WP processes, we'll have to call it manually, by putting a bit of php into one of the theme files - the header.php would work fine.

Go to the Appearance->Editor screen and find the header.php file for your test installation's current theme. At the end of the file, simply add this bit of code:

;

Make sure your trash is empty, then go to the main page of your test site as a visitor. That will be enough to run the function (since it exists and is available). Check your trash again and you should find that it holds all the published posts over 30 days old. Drafts, Pending and other posts will be left untouched.

We've just built a legitimate, working WordPress plugin!

Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *