Table of Contents for the series

So let’s get started.

For reasons we’ll see in the future, I’m going to create a custom post type (CPT) for WordPress (as well as a number of other odds and ends). There are two places we could do this – in a plugin, or in the theme we’ll eventually build. Since the CPT and some of the surrounding features relate to how we store the data, as opposed to how we present it, it feels more “best practice” to me to implement this in a plugin.

I should point out the counterargument – if my theme depends on features provided by the plugin, what happens if the plugin isn’t installed, or isn’t activated? That’s a valid argument, but we’ll handle that when the time comes.

So, for the moment, we’ll put the basic scaffolding in place for our plugin.

You’ll find lots of material out on the web on how to do this. Most of the examples I’ve seen, however, do not use PHP in an object-oriented manner. Instead, they use lots of “raw functions.” This poses the real potential for collisions between functions we define and functions that are either in the WordPress core, or else are in some other plugin. The convention is to “prefix” all of these functions with some 3-4 character sequence, and then basically hope nobody uses the same character sequence.

I, however, am going to take the object-oriented approach, which means that as much as possible of what I write is going to be in terms of classes. In addition, to reduce the impact on the global namespace still further, I’m going to put all my classes inside a PHP namespace.

Now – there is a price for this, and that is a minimum requirement of PHP 5.3. As I write this, the WordPress Statistics page says that almost a third of WordPress installations are still running on some version of PHP 5.2. If you’re developing a plugin that’s supposed to have broad market appeal, you might choose not to use PHP namespaces as a result. In that case, you’d certainly want to fall back to prefixing the names of each of your classes.

I’m going to choose to call my plugin ‘hfhd-plugin‘. (The “HFH” standing for “Hunter Family History” and the “d” for “Data”.) The minimal components for my plugin are the following files:

hfhd-plugin/
    index.php
    hfhd-plugin.php
    autoloader.php
    src/
        index.php
        HFHDPlugin.php

The index.php files are there just to prevent the directory containing the plugin from being listed – we can’t guarantee that someone’s web server will be configured to prevent this, so we just put an (effectively) blank file in each directory to intercept any snooping by script kiddies:

<?php
// Prevent directory listings

The HFHDPlugin.php file contains the skeleton for the class that will implement the plugin itself. For the moment, it looks like this:

<?php

namespace HFHD;

class HFHDPlugin {
	function __construct() {
	}
}

Not particularly exciting – just a bare class with a constructor, with a namespace declaration. In case you’re wondering why I prefixed the class with HFHD, the answer is that I plan to make this the “public” interface for the plugin, so it seemed a good name, despite the namespace. (Other code could just use this, without having to use ... as to come up with a nice name.

The hfhd-plugin.php file is the one that WordPress will use to load up the plugin we’re writing.

<?php

/*
 * Plugin Name: HFH Data Plugin
 * Description: Plugin to manage the custom data storage features for my genealogy site.
 * Version: 0.0.1
 * License: GPLv2 or later
 * Text Domain: hfhd
 */
namespace HFHD;

// Keep script kiddies at bay
if (! defined ( 'ABSPATH' )) {
	exit ();
}

require_once 'autoloader.php';

$GLOBALS ['HFHD\\HFHD_PLUGIN'] = new HFHDPlugin ();

The WordPress Codex says that the name of this file is supposed to be the same as the directory, with the .php extension. Interestingly enough, I’ve discovered (by accident) that isn’t strictly required – it appears that WordPress may recognize a plugin where that isn’t the case. I suspect that it actually scans all the first-level PHP files looking for the “Plugin” comment block. That might change in the future, however, so we’ll stick with the standard.

The plugin file consists of:

  1. The comment block that identifies this as a plugin.
  2. Our namespace declaration.
  3. A little bit of code to make sure someone doesn’t invoke this file externally. There is nothing to prevent someone from crafting a URL that points directly to this file and then trying to use it – that’s just the way that PHP works. If we were loaded by WordPress, however, the constant ABSPATH will have been defined long before we get here. If the script is invoked directly, on the other hand, it will not have been. Thus, in the latter case, we just get out of Dodge.
  4. A reference to our autoloader. More about that in a moment.
  5. Creation of an instance of our plugin class. This is the line of code that is (eventually) going to do all the dirty work.

I have a slight preference for using the $GLOBALS object explicitly, as opposed to creating simple global variables. Among other things, this way I can look at a block of code and know what is global and what is not, as opposed to having to look earlier to see if a variable was tagged as global. That’s simply a matter of preference.

The last bit of code is our autoloader. In order to cut down on the number of times we have to type require_once, we’re going to arrange for PHP to automatically load classes as required, using the spl_autoload_register feature. This feature allows us to register a function that will be called whenever a class needs to be loaded, so that we can check to see if it’s one of ours and load it up accordingly. The source code for this looks like this:

<?php
define ( 'HFHD\\HFHD_PLUGIN_DIR', plugin_dir_path ( __FILE__ ) );
define ( 'HFHD\\HFHD_PLUGIN_URL', plugin_dir_url ( __FILE__ ) );

spl_autoload_register ( function ($classname) {
	$namespacePrefix = 'HFHD\\';
	$namespacePrefixLen = 5;
	
	if (substr ( $classname, 0, $namespacePrefixLen ) === $namespacePrefix) {
		$classnameWithoutNamespace = substr ( $classname, $namespacePrefixLen );
		$classnameRelativePath = str_replace ( '\\', '/', $classnameWithoutNamespace );
		
		require_once HFHD\HFHD_PLUGIN_DIR . 'src/' . $classnameRelativePath . '.php';
	}
} );

We start off by defining constants that provide the path to our plugin directory, and the URL for it. Both of these constants are defined within the HFHD namespace, just like our classes. (Notice that autoloader.php does NOT have a namespace declaration in it.

We the register an anonymous function that does the following:

  1. Checks to see if the classname to be loaded starts with our namespace prefix. If not, we’ll return without doing anything.
  2. Removes the namespace prefix
  3. Converts any ‘\’ characters that remain in the classname to ‘/’ characters. For any of our classes, this gives us the path, relative to the src directory, where we’re going to expect to find the PHP file containing that class.
  4. require_once‘s the corresponding file.

Assuming we follow our naming convention and file layout properly, this should cause any of our classes to be found and loaded without requiring explicit require_once statements all through our code. If we make a mistake in file naming, require_once will throw an exception. This is why we use it instead of include_once.

With all this in place and placed within our WordPress installation’s wp_content/plugins folder, we can mosey on over to the WordPress “Plugins” panel, and (ta dah!) our plugin now shows up:
HFHD-plugin-created

We can activate and deactivate the plugin if we want. Of course, it doesn’t do anything interesting, but at least we’re now connected to the WordPress scaffolding.

The code for this post may be found at https://github.com/SilverBayTech/WordpressCustomization/tree/master/hfhd-plugin/v1.

In our next post in the series, we’ll have this actually do something meaningful by enhancing the plugin to create the custom post type that we want.

 

WordPress Customization Series – Basic Plugin Setup originally appeared on http://www.silverbaytech.com/blog/.