Posts
Search
Contact
Cookies
About
RSS

Creating a simple WordPress Plug-in

Added 9 Dec 2020, 1:14 p.m. edited 18 Jun 2023, 1:12 a.m.

I'm going to show a very simple plug-in, it will show the years, months and days since a given day, to ensure it has a reasonably unique name (which is important) I've called it sincer. Sincer will use wordpress short codes to insert the date interval into any post, so first it's worth looking at just what a short code is.

[myshortcode param1=foo param2=bar]some content[/myshortcode]

This short code has two parameters and some content, usually the plug-in providing the implementation of "myshortcode" would in some way modify the content inside the short code depending on the parameters.

However for sincer, I have just one mandatory parameter and the content is being created not modified, this means we can do without the content and also the closing tag. Handily you can also get away without even naming your parameters (not a great idea if you have more than one!). The upshot of this is that the short code can be much reduced.

[sincer 2000-12-16]

This makes it quick and convenient to insert into a post. Depending on the actual date the aim of the plug-in is to replace this tag with some output along the lines of

20 years, 11 months, 4 days

Before looking at any code its worth pointing out that you need to set up a local copy of WordPress, at the least while developing you'll see ugly error or warning messages (even potentially all over the site) and at worst you could break your site altogether (although "rescue" is often trivial). The only real issue with setting up your local machine as a development server is correctly configuring PHP, WordPress requires a few extensions that by default are often either disabled or need installing and enabling, MySql and OpenSSL (for updating) are a few that come to mind. For extra fun(!) you could even set up a WordPress installation on a Raspberry PI... There are no end of ways of setting up your permissions, but I find it convenient to add my user account to the same group as the web server, you could also restrict your web server to only serve to the local network.

Having set up your development server, to make a start let's create a non-functional plug-in that we can see in the plug-ins section of WordPress. Inside your WordPress installation you will see wp-content and inside there is the plugins directory. Create a directory inside the plugins directory called sincer this directory will hold the files for the plug-in, including any resources it might need. Create a file called sincer.php and add the following code

<?php
/**
 * Plugin Name:       sincer
 * Plugin URI:        http://bedroomcoders.co.uk
 * Description:       short code current days since a date. [sincer 2000-12-06] will show the years, months and days since 6/12/2000 
 * Version:           0.1
 * Requires at least: 5.2
 * Requires PHP:      7.2
 * Author:            codifies
 * Author URI:        http://bedroomcoders.co.uk
 * License:           GPL v2 or later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 */

?>

This is more than "just" a comment and this block is both mandatory and must only appear in one file. Check in the WordPress Plugins menu and you should see a sincer plugin (you might as well activate it now - its not doing anything just yet but it will be soon!). For testing we need a post, it doesn't need to be published, you can simply refresh a preview of the post while testing. Add something like the following text to the test post.

 Xmas 2001 was [sincer 2001-12-25] ago.  
 New year 2000 happened [sincer 2000-1-1] ago.   
 An error [sincer a-b-c] !
 another error [sincer]  again [sincer  ] 

Notice that as well as a few tests (we expect to work eventually) there are also some short code tags that should cause problems. Its very important with a plug-in to make it as robust as possible, you absolutely must test carefully, plug-ins are powerful but with that power comes the ability to shoot yourself in the foot (or worse still an end user at a later date...)

There is an API specifically for short codes, but before we get to it, let's look at how the short code handler is added. WordPress provides a set of "actions" or hooks that a plug-in can use to trigger code at certain points, as WordPress collates and outputs a page, the "init" action happens just before any headers are sent, but everything else is ready (the user is authenticated for example, theme available)

// add the slicer short code handler during init. 
add_action( 'init', 'sincer_shortcodes_init' );

function sincer_shortcodes_init() {
    add_shortcode( 'sincer', 'sincer_shortcode' );
}

It seems a bit long winded to add an action that then adds a short code, but it's actually good practice to do this. Just adding the short code without using an action, could potentially cause issues, using an action puts everything into a predictable order and reduces the possibility of difficult to track bugs that could be intermittent or you might not even see on your setup.

// actual implementation of the short code
function sincer_shortcode( $atts = [], $content = null, $tag = '' ) 
{
    $d='';
    
    if (is_array($atts)) {
        $d = $atts[0];
    }
    
    // in case the input shortcode date isn't valid 
    if (validateDate($d))
    {
        $ds = date_create($d);
        $di = date_diff($ds, date_create(date('Y-m-d')));
        $d = '';
        if ((int)$di->format('%y')>0) {
            $d = $di->format('%y year');
            if ((int)$di->format('%y')>1) {
                $d .= "s";    
            }
            $d .= ', ';
        }
        if ((int)$di->format('%m')>0) {
            $d .= $di->format('%m month');
            if ((int)$di->format('%m')>1) {
                $d .= "s";    
            }
            $d .= ', ';
        }
        if ((int)$di->format('%d')>0) {
            $d .= $di->format('%d day');
            if ((int)$di->format('%d')>1) {
                $d .= "s";    
            }
        }
    } else {
        $d=''; // fail silently
    }

    return $d;
}
 
// returns true if the given date string is a valid date
function validateDate($date)
{
  $tempDate = explode('-', $date);
  if (sizeof($tempDate)!=3) return false;
  // checkdate(month, day, year)
  return checkdate((int)$tempDate[1], (int)$tempDate[2], (int)$tempDate[0]);
}

Its worth looking at the prototype for the short code function

function sincer_shortcode( $atts = [], $content = null, $tag = '' )

$atts (attributes or parameters) are the parameters given in the short code tag, with $content being the text between the start and end tags, $tag is simply the name of the tag in this case it should be sincer. As we are creating the content and not modifiying or filtering it, we can just overwrite $content.

notice that $atts is checked to see if it's even an array, it can just be empty, depending on your set up, not checking to see if it's an array first can cause ugly warning text to be displayed. Equally its important not to assume the end user has actually included a valid date.

Once we do have a valid date, then the rest of the implementation is just simply a date calculation and the production of the textual representation.

There are a number of things you could do to take this further (should you wish) For example you could allow an optional format string to be included (maybe in the content) for example "It's %a sleeps till xmas"

Finally I must point you in the direction of the WordPress references it might look overwhelming but on the whole its a good reference to something that is without doubt a powerful and complex ecosystem.