In our last post "Enabling Action and Filter Hook Removal from Class-based WordPress Plugins" we offered the following as a suggested template for coding WordPress plugins:

  1. <?php
  2. /*
  3.  * Plugin Name: Your Plugin Name
  4.  */
  5. class Your_Plugin_Classname {
  6.   private static $_this;
  7.   function __construct() {
  8.     self::$_this = $this;
  9.     // Your constructor code goes here
  10.   }
  11.   static function this() {
  12.     return self::$_this;
  13.   }
  14.   // Your plugin methods go here
  15. }
  16. new Your_Plugin_Classname();
<?php
/*
 * Plugin Name: Your Plugin Name
 */
class Your_Plugin_Classname {
  private static $_this;
  function __construct() {
    self::$_this = $this;
    // Your constructor code goes here
  }
  static function this() {
    return self::$_this;
  }
  // Your plugin methods go here
}
new Your_Plugin_Classname();

Unfortunately there is an issue with this approach which we will fix in this post.

A De facto Singleton

The structure proposed is a de facto Singleton where Singletons are defined by Wikipedia to be:

A design pattern in software engineering that restricts the instantiation of a class to one object.

In our template the issue lies in the de facto part. Our class template is designed for only one instance but does not stop a developer from using new to create additional instances of the class. A second instance would overwrite the first in self::$_this which would create havoc for any code that expects self::$_this to be the same for the life of the "page load"[1]

Disallowing a Second Instantiation

It's really quite simple; since a class' __construct() method gets invoked whenever the new operator is used we need to test the static variable self::$_this to see if it has been set and if so call wp_die(). Note we used five lines below when we could have consolidated down to two but we wanted to ensure the code didn't wrap in this post:

  1. if ( isset( self::$_this ) ) {
  2.   $msg = &#39;%s is a singleton class and you cannot create a second instance.&#39;;
  3.  $msg = __( $msg, &#39;your-plugin-translation-domain&#39; );
  4.  wp_die( sprintf( $msg, get_class( $this ) ) );
  5. }
if ( isset( self::$_this ) ) {
  $msg = &#39;%s is a singleton class and you cannot create a second instance.&#39;;
  $msg = __( $msg, &#39;your-plugin-translation-domain&#39; );
  wp_die( sprintf( $msg, get_class( $this ) ) );
}

The Real Singleton

Adding the code snippet above to our template completes our singleton:

  1. <?php
  2. /*
  3.  * Plugin Name: Your Plugin Name
  4.  */
  5. class Your_Plugin_Classname {
  6.   private static $_this;
  7.   function __construct() {
  8.     if ( isset( self::$_this ) ) {
  9.       $msg = &#39;%s is a singleton class and you cannot create a second instance.&#39;;
  10.      $msg = __( $msg, &#39;your-plugin-translation-domain&#39; );
  11.      wp_die( sprintf( $msg, get_class( $this ) ) );
  12.     }
  13.     self::$_this = $this;
  14.     // Your constructor code goes here
  15.   }
  16.   static function this() {
  17.     return self::$_this;
  18.   }
  19.   // Your plugin methods go here
  20. }
  21. new Your_Plugin_Classname();
<?php
/*
 * Plugin Name: Your Plugin Name
 */
class Your_Plugin_Classname {
  private static $_this;
  function __construct() {
    if ( isset( self::$_this ) ) {
      $msg = &#39;%s is a singleton class and you cannot create a second instance.&#39;;
      $msg = __( $msg, &#39;your-plugin-translation-domain&#39; );
      wp_die( sprintf( $msg, get_class( $this ) ) );
    }
    self::$_this = $this;
    // Your constructor code goes here
  }
  static function this() {
    return self::$_this;
  }
  // Your plugin methods go here
}
new Your_Plugin_Classname();

A Complete Working Example

Grabbing our code from our last post and adding the singleton logic gives us this example; to test just drop[2]into your plugins directory:

  1. <?php
  2. /*
  3.  * Plugin Name: Thanks for Reading
  4.  */
  5. class Thanks_For_Reading_Plugin {
  6.   private static $_this;
  7.   function __construct() {
  8.     if ( isset( self::$_this ) )
  9.       wp_die( sprintf( __( &#39;%s is a singleton class and your cannot create a second instance.&#39;,
  10.        &#39;thanks-for-reading&#39; ), get_class( $this ) ) );
  11.  
  12.     self::$_this = $this;
  13.     add_filter( &#39;the_content&#39;, array( $this, &#39;the_content&#39; ) );
  14.  }
  15.   function this() {
  16.     return self::$_this;
  17.   }
  18.   function the_content( $content ) {
  19.     return $content . &#39;<p>Thanks for Reading!</p>&#39;;
  20.  }
  21. }
  22. new Thanks_For_Reading_Plugin();
<?php
/*
 * Plugin Name: Thanks for Reading
 */
class Thanks_For_Reading_Plugin {
  private static $_this;
  function __construct() {
    if ( isset( self::$_this ) )
      wp_die( sprintf( __( &#39;%s is a singleton class and your cannot create a second instance.&#39;,
        &#39;thanks-for-reading&#39; ), get_class( $this ) ) );

    self::$_this = $this;
    add_filter( &#39;the_content&#39;, array( $this, &#39;the_content&#39; ) );
  }
  function this() {
    return self::$_this;
  }
  function the_content( $content ) {
    return $content . &#39;<p>Thanks for Reading!</p>&#39;;
  }
}
new Thanks_For_Reading_Plugin();

Summary

When using classes as code wrappers for WordPress plugins as we've been recommending you are effectively using a Singleton without enforcing the singleton constraint. To disallow multiple instantiation use the isset( self::$_this ) test. If you don't then site builders, theme coders and other plugin developers might misuse your class by instantiating it a second time and overwrite your singleton instance. And nobody wants that. :)

Update

Be sure to read our follow up to this post where we talk about ensuring that classes uses for Singletons actually are limited to a single instance.

Related Links

Recently Eric Mann has had a field day writing about Singletons for WordPress, three (3) posts in little over a week (or should that be a "field week?") You'll note Eric recommends a slight different structure for singletons than we do. We'll address that in our next post:

About a year ago RJ Zaworski wrote a post offering his take on a:

RJ has some interesting techniques that were very clearly influences by Model-view-controller frameworks, approaches that are not common in the WordPress world. Nonetheless, his coding techniques are interesting.

Footnotes

[1]
When we refer to a "page load" we mean the entire lifecycle generated by an HTTP request where the PHP starting with /index.php is executed on the server and the resultant HTML is returned to the HTTP client which is typically a site visitor's browser.
[2]
To test our example simply save as a file you can name thanks-for-reading.php in the WordPress plugins directory on your web server, typically /wp-content/plugins/ from the root of your website and then activate it like you would any other plugin.

4 thoughts on “Using Singleton Classes for WordPress Plugins

    • Hi @Chris,

      Thanks for commenting. Can you elaborate on what you mean by “multiple unique instances of your plugin on a page?” Are you referring to widgets, or something else?

      Reply

Leave a reply

required

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code lang=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" extra="">