Nonces That Are Used Only Once

A while back in this article on wptuts I talked about nonces, and how they work. Normally, nonces are ‘one use only’ – once they are used they are stored, and never accepted again. WordPress, on the other hand, generates a new nonce every 12 hours, each with a life span of 24 hours. They can be used as many times during those 24 hours as needed. And that is, usually, all that is necessary. However instances may occur when you want to create and check nonces that are actually only used once.

Telling the time()

So how can we achieve this? First we want to create a fresh nonce for (essentially) every page load – since if our nonce can only be used once, then you’ll want to be able to do more than one action every 12 hours. I could force WordPress to generate new nonces by shortening the life of the nonce – but this is not really what I want and I might end up with a nonce, valid for one second. Not great.

Instead the idea is to create a standard nonce, whose ‘action’ includes a timestamp. This ensures a fresh nonce is generated every second (say) – which is enough for our purpose (nonces are unique to the user, and should also be unique to the action being taken, and if applicable, the object the action is being applied to). Of course to validate the nonce, we’ll also needed to send the timestamp.

So to create our nonce, we just use wp_create_nonce, but after concatenating it with a timestamp. The returned ‘nonce’ now consists of two parts: the nonce value and timestamp, which we join with hyphen

function sh_create_onetime_nonce($action = -1) {
    $time = time();
    $nonce = wp_create_nonce($time.$action);
    return $nonce . '-' . $time;
}

We can then embed the nonce and timestamp together in the form/url – or however the action is being triggered.

 <form>
    <input type="hidden" name="nonce" value="<?php echo sh_create_onetime_nonce( 'this-action' );?>"/>

    <input type="submit" value="Perform this action">
 </form>

Validating the nonce

Now to verify our nonce. The nonce consists of the original nonce generated by WordPress, combiend witht he timestamp of when it was generated (separated by a hyphen). So first we need to extract the constituent parts.

Concatenating the timestamp part with the action, we use the wp_verify_nonce function agains the nonce part. This checks that the nonce is valid. Of course, it already has a validity lifespan of 24 hours – but in order to reduce the number of used nonces we might have to store, I’ve opted to impose a 1 hour life span as well.

If the nonce is valid, we then check that it hasn’t be used. Used nonces are stored in the database as a serialised array. The array is of the form array( $nonce => $expires_timestamp ) and ordered by timestamp. (I did consider storing them in a separate table, but this is beyond the scope of the article and if we try to keep the number of nonces that might be stored down – say by setting the 1 hour life span, storing them in array shouldn’t present any problems).

If the nonce value hasn’t be used, we proceed to remove any ‘expired’ nonces (ones that would now fail the 1 hour life check) and add this used nonce into the array – and then sorting.

function sh_verify_onetime_nonce( $_nonce, $action = -1) {

    //Extract timestamp and nonce part of $_nonce
    $parts = explode( '-', $_nonce );
    $nonce = $parts[0]; // Original nonce generated by WordPress.
    $generated = $parts[1]; //Time when generated

    $nonce_life = 60*60; //We want these nonces to have a short lifespan
    $expires = (int) $generated + $nonce_life;
    $time = time(); //Current time

    //Verify the nonce part and check that it has not expired
    if( ! wp_verify_nonce( $nonce, $generated.$action ) || $time > $expires )
        return false;

    //Get used nonces
    $used_nonces = get_option('_sh_used_nonces');

    //Nonce already used.
    if( isset( $used_nonces[$nonce] ) ) )
        return false;

    foreach ($used_nonces as $nonce=> $timestamp){
        if( $timestamp > $time )
            break;

        //This nonce has expired, so we don't need to keep it any longer
        unset( $used_nonces[$nonce] );
    }

    //Add nonce to used nonces and sort
    $used_nonces[$nonce] = $expire;
    asort( $used_nonces )
    update_option( '_sh_used_nonces',$used_nonces );
}

And there we have it, nonces that can actually only be used once.

Git & the WordPress Repository

A while back I wrote an article on WP.Tuts on using Git to publish plug-ins on the WordPress repository. The wordpress.org plugin repository runs on Subversion, but I, for various reasons prefer to use Git. It’s also incredibly useful for putting your plug-on GitHub or BitBucket where you can collaborate with other developers.

The trouble is two-fold:

  • Git & SVN don’t play particularly nice
  • My local (and Github) Git repository are focussed on development, the wordpress.org is solely for distribution.

Let me explain the second point a bit more. If you’ve worked with Git you’ll probably be aware that you are to commit little and often (see for example, Tom McFarlin’s recent post). But the WordPress repository is for distribution – they don’t need or want all the those commits.

In fact, as you probably know, Otto has said:

“If I catch you at it [pushing each commit separately], then I will ban you from WordPress.org. The SVN only needs your final working version committed to it, not the entire history of the hundreds of changes you made using Git. Flatten your changes to a single commit.”

Now in my original article I outlined a workflow in which you develop in a ‘development branch’ and then when ready to release something, merge and squash those changes into your master, before pushing to the SVN. Unfortunately, beyond you current ‘development branch’ you loose all your history.

A Better Workflow

I’m not sure why this didn’t occur to me earlier, but by essentially reversing this workflow, we can preserver our history, but also commit to the WordPress subversion times only once or twice for each tagged release. We do this by developing in the master (or some other branch), and merge and squash into a release branch. We push from the release branch to the SVN repository.

This isn’t actually different from what we were originally doing since from a git point a view (but not a Github point of view) the master branch is just another branch. But we do need to set up our release branch to track the remote SVN repository.

How It Works

(I’m posting this as much for my own reference as anything else). I’ll assume that you’ve been working on a project for some time, and let’s suppose its in Github, but now you want to publish it to the WordPress repository. Once you’ve been accepted you’ll receive an e-mail containing a link to your wordpress.org hosted SVN repository, something like http://plugins.svn.wordpress.org/your-plugin-name.

Step 1: Clone the SVN Repository

The WordPress repository is big, to clone our plug-in we’ll first tell git where to find it. The following will get the first log of our SVN repository (when it was originally added):

 svn log -r 1:HEAD --limit 1 http://plugins.svn.wordpress.org/your-plug-in-name

It will think for a while and then you should see something like this:

 r651844 | plugin-master | 2013-01-13 05:33:38 +0000 (Sun, 13 Jan 2013) | 1 line

That rXXXXXX (revision) number is what we’ll use to ‘find’ our repository. It’s not necessary, but speeds things up somewhat. So next we clone our repository:

  git svn clone -s -r651844 --no-minimize-url http://plugins.svn.wordpress.org/your-plugin-name

This should take a few minutes, but it will initialise a git repository with the folder your-plug-name. Let’s view the branches in that repository:

  cd your-plugin-name
  git branch -a

This should list master (your local repo – this will probably be starred as its the branch you’re in currently). As a remote repository it will also have (the SVN) remotes/trunk. Currently our repository is empty (since our plug-in’s SVN repository is). (If it wasn’t we could fast-forward through the changes and have an up-to-date copy.)

Step 2: Pull Our Project From Github

Our plug-in is currently sitting on Github, so the idea is to pull it into our newly created repository. So let’s add our Github repository (which I’ll call origin – but it can be anything) and then pull it into our repo:

 git remote add origin git@github.com:your-github-username/your-repo-name.git
 git pull origin master

Our plug-in should now be in our repository, along with its complete history. We can commit further changes if we desired.

Step 3: Create A Release Repository

Next create, and checkout our release repository:

 git checkout --track -b release remotes/trunk

This now tracks our SVN trunk sitting in the WordPress Repository. Everything is now set up. We can return to the master branch and make any changes if desired.

Step 4: Committing to SVN Trunk

Let’s suppose we’re ready to push to the SVN branch the latest and greatest changes we’ve made in our master branch. We checkout our release branch and merge (and squash!) our master branch

 git checkout release
 git merge --squash master

Note: after the first merge you’ll notice that you start getting merge conflicts – assuming you don’t develop on the ‘stable’ branch, these aren’t really conflicts at all, and its much easier to do the following which is the same as the above, but any ‘conflicts’ are automatically resolved in favour of the master branch:

 git merge --squash -Xtheirs master

Just to be sure we don’t loose anything on SVN we can perform a rebase (though I find this is never necessary and if you’re the only commiter you’ll probably find this too)

 git svn rebase

Hopefully you’ll get a message saying Current branch master is up to date. Then we’re ready to push:

 git svn dcommit

This may take a few minutes.

Step 5: Tagging A New Release

Our trunk is now up to date, but if we were tagging a new release (and so had updated the plug-in’s readme.txt stable tag) we also need to create that tag. This is very simple, for tagging “1.6.1” for instance:

 git svn tag "1.6.1"

Again, this may take a few minutes. You shall probably receive an e-mail notification from WordPress.org too. In about 5 minutes time the WordPress plug-in repository should be updated with your new release.

I hope this helps! If you’ve any suggestions on better workflows, I’d love to hear about them, so please leave a comment :).

Date Intervals in PHP 5.2

PHP provides a very useful DateTime class, and the related DateTimeZone, and DateInterval classes. (Most of) These have proven very useful when developing my plug-in Event Organiser, in particular making date generation from complex patterns fairly painless. However there is one problem = some of the more advanced methods of DateTime, and the entire DateInterval class are only supported in PHP 5.3. Quite a lot of websites are still hosted on the old PHP 5.2.

This means I’ve had to produce work-arounds in the cases where Event Organiser is run on PHP 5.2.

DateInterval

With events you might also want to describe how long the event is. In PHP 5.3 this is easy:

$date1 = new DateTime('2012-10-28 00:00:00',new DateTimeZone('Europe/London'));
$date2 = new DateTime('2012-10-28 03:00:00',new DateTimeZone('Europe/London'));
$interval = date_diff($date1, $date2);
$format = '%y years, %m months, %d days, %h hours, %i minutes, %s seconds, %a total days %R';
echo $interval->format($format);

You use the date_diff function which returns a DateInterval object. This can be formatted into string using any of the available place-holders.

Work around for PHP 5.2

It would be great to replicate this for PHP 5.2 – and it’s actually quite easy. We’ll produce a function sh_date_interval($date1,$date2,$format) which should return (almost!) the same as $interval->format($format) above.

To this, we’ll take the earlier date and increment by one year until it’s after our later date. We’ll then reverse the last increment (so the modified date is now less than a year before the later date) and record how many increments. This tells us how many years apart the dates are. We do this for months, days and hours.

For minutes and seconds do something different. There are a fixed number of seconds in a minute, and fixed number of minutes in an hour. Consequently rather than a while loop of an extra ~120 loops we just use simple calculations.

Note: Incrementing 2012-01-31 (1st January) by one month gives 2012-03-02 (2nd March). So these dates are a month apart. Incrementing 2012-02-29 (29th February) by a month gives 2012-03-29 (29th March) – so the 29th February and 31st March are 1 month and 2 days apart. This is expected behaviour and mimics that of DateInterval. The function handles leap years in the same way as DateInterval.

Note 2: The function does not handle daylight savings in in the same way as DateInterval. If at 01:00 you are to move the clocks forward to 02:00, DateInterval says that there are three hours between 00:00 and 03:00. The below function says there are two (which I believe to be correct – at least in human terms).

Note 3: I’m using this in a WordPress context – so I’m using the function zeroise which is not a native PHP function.

function sh_date_interval($_date1,$_date2, $format){

    //Make sure $date1 is ealier
    $date1 = ($_date1 <= $_date2 ? $_date1 : $_date2);
    $date2 = ($_date1 <= $_date2 ? $_date2 : $_date1);

    //Calculate R values
    $R = ($_date1 <= $_date2 ? '+' : '-');
    $r = ($_date1 <= $_date2 ? '' : '-');

    //Calculate total days
    $total_days = round(abs($date1->format('U') - $date2->format('U'))/86400);

    //A leap year work around - consistent with DateInterval
    $leap_year = ( $date1->format('m-d') == '02-29' ? true : false);
    if( $leap_year ){
        $date1->modify('-1 day');
    }

    $periods = array( 'years'=>-1,'months'=>-1,'days'=>-1,'hours'=>-1);

    foreach ($periods as $period => &$i ){

        if($period == 'days' && $leap_year )
            $date1->modify('+1 day');

        while( $date1 <= $date2 ){
            $date1->modify('+1 '.$period);
            $i++;
        }

        //Reset date and record increments
        $date1->modify('-1 '.$period);
    }
    extract($periods);

    //Minutes, seconds
    $seconds = round(abs($date1->format('U') - $date2->format('U')));
    $minutes = floor($seconds/60);
    $seconds = $seconds - $minutes*60;

    $replace = array(
        '/%y/' => $years,
        '/%Y/' => zeroise($years,2),
        '/%m/' => $months,
        '/%M/' => zeroise($months,2),
        '/%d/' => $days,
        '/%D/' => zeroise($days,2),
        '/%a/' => zeroise($total_days,2),
        '/%h/' => $hours,
        '/%H/' => zeroise($hours,2),
        '/%i/' => $minutes,
        '/%I/' => zeroise($minutes,2),
        '/%s/' => $seconds,
        '/%S/' => zeroise($seconds,2),
        '/%r/' => $r,
        '/%R/' => $R
    );

    return preg_replace(array_keys($replace), array_values($replace), $format);
}

Testing it out

The following dates are chosen to provide an example of leap year and daylight savings. Clocks are due to go forward an hour on Sunday, 31 March 2013, 01:00.

$date1 = new DateTime('2012-02-29 00:00:00',new DateTimeZone('Europe/London'));
$date2 = new DateTime('2013-03-31 03:00:00',new DateTimeZone('Europe/London'));

$interval = date_diff($date1, $date2);
$format = '%y year, %m month, %d day, %h hours, %i minutes, %s seconds, %a total days';
echo $interval->format($format); 
echo sh_date_interval($date1,$date2,$format); 

    /*
    * Prints
    * 1 year, 1 month, 2 day, 3 hours, 0 minutes, 0 seconds, 396 total days
    * 1 year, 1 month, 2 day, 2 hours, 0 minutes, 0 seconds, 396 total days
    */

How to Get the Current URL in WordPress

Note: The original post wouldn’t work for WordPress on sub-domains, so I’ve updated it to include a solution that will

The other day I needed to get the current url the user was on – and I was convinced that there would be a better way than handling $_SERVER directly.

I found this solution by Konstantin Kovshenin, but which unfortunately gave me

http://example.com/blog/category/cata1?category_name=cata1 

when on

http://example.com/blog/category/cata1

Now add_query_arg, when passed no url uses the current url but, unfortunately, when on www.example.com/page/subpage/ it gives you: /page/subpage/. To get around that, you can use home_url.

To get the ‘current url’ in WordPress:

 $current_url = home_url(add_query_arg(array()));

Unfortunately if you WordPress install lives on a subdomain this won’t work, since:

  • home_url() gives you something like www.example.com/blog
  • add_query_arg(array()) gives you something like blog/page/subpage

So you get a repeat of blog. A more general solution would be

 $current_url = home_url(add_query_arg(array(),$wp->request));

Deactivate Other Plug-ins On Deactivation

Note: The original proposed fix might cause undesirable effects if more than one plug-in is deactivated at once. The reason being that ‘aborting’ a deactivation, will abort all subsequent deactivations when deactivating more than one plug-in. I’ve included a better workaround which is far more reliable.

In this article I considered the situtation where you were developing an add-on plug-in, B, for a plug-in A, where B will obviously requrie A to be installed and active to function correctly. That article focused on how you can check that A was active, when activating B and if not displaying an admin notice.

Now we flip the problem on its head. Let’s suppose that the user is now deactivating A. We want to make sure that we then deactivate B (obviously only if it’s active – but WordPress handles these checks).

How we might like it to work but it doesn’t…

We might hope that we can just use deactivate_plugins inside the deactivation callback for A… unfortunately this doesn’t work and inspecting the code reveals why.

When the user deactivates A, WordPress calls deactivate_plugins(A).This function does the following:

  1. Gets an arary of all the current active plugins from the database.
  2. Performs some checks (e.g. is plugin A actually active?)
  3. Removes A from this array
  4. Fires the hook deactivate_A (which we hook onto using register_deactivation_hook)
  5. Updates the array to the database.

Now at step 4, we call deactivate_plugins(B) to deactivate B. 1-5 run through for B and is completed. The eagle eyed will notice that at this point the database is updated to consider B inactive, but A still active – but this isn’t the problem, in fact the reverse.

Once that’s completed we proceed to step 5 (in the original deactivate_plugins() call for A). Now this array is updated to the database – but this array was the very original one retrieved in step 1 and only has A removed. In particular we retrieved it at the beginning when B was still active, and so it contains B.

Note: your deactivation callbacks for B are fired, even through WordPress still thinks its active next time the page loads.

Solution – see better solution below

The fix is simple. In the callback of A, deactivate B as before. Then retrieve the updated active plug-ins array, and remove A from it and update the database. The database now has both A and B as inactive. Finally, to prevent WordPress undoing this, wp_redirect and exit to ‘abort’ the original deactivate_plugins process:

//This goes inside plugin A.
//When A is deactivated. Deactivate B.
register_deactivation_hook(__FILE__,'my_plugin_A_deactivate'); 
function my_plugin_A_deactivate(){
     $dependent = 'B/B.php';

    if( is_plugin_active($dependent) ){

        $dependent = plugin_basename( trim( $dependent) );
        $parent = plugin_basename( __FILE__  );

        //Deactivate the dependent 'add on'.
        deactivate_plugins($dependent);

        //Here comes the work around.... Manually remove THIS plugin from updated active_plugins
        $current = get_option( 'active_plugins', array() );
        $key = array_search( $parent, $current );
        if ( false !== $key ) {
            array_splice( $current, $key, 1 );
        }
        update_option('active_plugins', $current);

        //Now redirect to prevent WordPress from adding 'dependent' back in...
        wp_redirect(admin_url('plugins.php?deactivate=true&plugin_status=all&paged=1'));
        exit();
    }
}

A better solution

For reasons given at the top of this post, the above solution is less than idea. However, a better work-around is at hand. When WordPress updates the database with active arrays it does so with the generic update_option function. Consequently update_option_{$option} is triggered (after the option has been updated). You can use this to hook to deactivate your plug-in.

(There is the pre_update_option_{$option} filter in which you could filter the active plug-ins – but this is a bit too low level, and among other things occurs after sanitize_option is applied. While that doesn’t do anything for this option, it might do in the future. Also, we still want to use deactivate_plugins rather than handle the database option directly).

Here’s the complete solution:

//This goes inside Plugin A.
//When A is deactivated. Deactivate B.
  register_deactivation_hook(__FILE__,'my_plugin_A_deactivate'); 
function my_plugin_A_deactivate(){
    $dependent = 'B/B.php';
    if( is_plugin_active($dependent) ){
         add_action('update_option_active_plugins', 'my_deactivate_dependent_B');
    }
}

function my_deactivate_dependent_B(){
    $dependent = 'B/B.php';
    deactivate_plugins($dependent);
}

A similar workaround exists for network wide deactivation for multi sites.

I’ve posted this as a solution to this question on WordPress StackExchange. A trac ticket is been opened for this bug.

How to check another plug-in exists and get its details

If you’re writing an add-on for one of your (or someone else’s) plug-in you want to make sure that that plug-in is active (and quite often, if it’s a sufficiently new version).

Is the plug-in active?

You can get tell if if a plug-in is active by using is_plugin_active($plugin) where $plugin is the sub-directory/file of the plug-in.

Getting the plug-in details

To get the details of that plug-in you could use get_plugin_data() but rather than taking the sub-directory/file as an argument (as above), it requires the path to the plug-in file. I’m not sure of way of doing this without relying on some constants – so an alternative is to use get_plugins().

get_plugins() returns an array, with the plug-ins as keys (more exactly, the sub-directory/file) and the plug-in’s details (including version) as a value. As an example, take my Event Organiser plugin.

 $plugin = 'event-organiser/event-organiser.php';
 if( is_plugin_active($plugin) ){
      $plugins = get_plugins();
      $plugin_data = $plugins[$plugin];
      print_r($plugin_data);
 }

This prints out something like the following:

Array ( 
 [Name] => Event Organiser 
 [PluginURI] => http://wp-event-organiser.com
 [Version] => 1.4 
 [Description] => Creates a custom post type 'events' with features such as reoccurring events, venues, Google Maps, calendar views and events and venue pages 
 [Author] => Stephen Harris 
 [AuthorURI] => http://stephenharris.info
 [TextDomain] => ''
 [DomainPath] => ''
 [Network] => ''
 [Title] => Event Organiser 
 [AuthorName] => Stephen Harris 
)

Putting it all together

Let’s suppose we have a plugin A (this is the ‘parent’ plug-in) and we we want to create an add-on for it, B. We’ll allow the add on to be activated – but if A isn’t activated, we’ll display an error message:

register_activation_hook(__FILE__,'B_add_on_plugin_activate'); 
function B_add_on_plugin_activate(){
     $parent= 'A/A.php';

    if( is_plugin_active($parent) ){
        $plugins = get_plugins();
        $plugin_data = $plugins[$parent];

        //The parent plug-in is installed - but is it the correct version?
        if( $plugin_data['Version'] < '1.5' ){
            update_option('pluginA_install_nag','wrongversion');
        }
    }else{
        update_option('pluginA_install_nag','needtoinstall');
    }
}

add_action('load-plugins.php','B_add_on_activate_check');
function my_add_on_activate_check(){
    if( get_option('pluginA_install_nag',false) ){
        delete_option('pluginA_install_nag');
        add_action('admin_notices', 'B_add_on_install_A_notice');
    }
}

function B_add_on_install_A_notice(){
    echo '<div class="updated"><p>
        This plug-in requires <strong>A</strong> (v1.5 or higher) to function correctly. Download <a href="">A</a>.
    </p></div>';
}

Alternatively you could redirect from the activation, and – in effect – abort it. But by doing so, you obviously cant display a message (since your add-on plug-in won’t be activated …). This is probably bad, because it gives the user no feedback.

Deactivating…

What if someone installs the add-on plugin B, and then deactivates the A. Suppose, in this scenario we’d like to deactivate our add on plugin too. We might hope that we can just use deactivate_plugins inside the deactivation hook for A… unfortunately this doesn’t work and inspecting the code reveals why. I talk about it in this article.