Update a Plugin while maintaining back compatibility: general

Class names are case insensitive in PHP (with one exception), so that should not be a problem.

Accessing your main plugin instance for a class is possible with a static method get_instance() (example). You don’t have to build a Singleton for that. And it should not break backwards-compatibility.

If you had public methods in your old code and these methods have been used by third party code, you have to keep the exact signature. So either keep the method and pass the call through to the instance of the new class, or – if there are many such methods – use __call() to catch all these methods in one.

(Update) Given your example of remove_action() … this is tricky. If you add this callback from another class now, there is no safe way to stay backwards compatible, because you cannot “watch” remove_action() calls.
You could register the old callback and implement an Observer to be noticed if it has been removed.

One idea I have been playing with for future projects: separate the public API from the inner logic.

Example: Create a class Plugin_API and pass all objects from your working code into that class when they are set up. When a method from that API is called, pass that call to the responsible object internally, without exposing your plugin structure to the public.

Sample code

add_action( 'wp_loaded', array ( Plugin_Controller::get_instance(), 'plugin_setup' ) );

class Plugin_Controller
{
    protected static $instance = NULL;

    public static function get_instance()
    {
        NULL === self::$instance and self::$instance = new self;

        return self::$instance;
    }

    public function plugin_setup()
    {
        $api = Plugin_API::get_instance();
        $api->add_object( 'post_type',    new Plugin_Custom_Post_Type );
        $api->add_object( 'taxonomy',     new Plugin_Custom_Taxonomy );
        $api->add_object( 'options_page', new Plugin_Options_Page );

        add_action( 'wp_head', array ( $api, 'wp_head' ) );
    }
}

class Plugin_Custom_Post_Type {}
class Plugin_Custom_Taxonomy {}
class Plugin_Options_Page {}

class Plugin_API
{
    protected static $instance = NULL;

    protected $objects;

    public static function get_instance()
    {
        NULL === self::$instance and self::$instance = new self;

        return self::$instance;
    }

    public function add_object( $name, $object )
    {
        $this->objects[ $name ] = $object;
    }

    public function wp_head()
    {
        $this->objects['post_type']->wp_head_callback();
        $this->objects['taxonomy']->wp_head_callback();
    }
}

Now another plugin can remove that action with …

remove_action( 'wp_head', array ( Plugin_API::get_instance(), 'wp_head' ) );

… and you are still free to change your plugin structure whenever you want.

This is just an idea, I haven’t used it. But it could be worth a try for a complex plugin with lots of classes. Not sure how it will work with filters, but these are easier to move anyway.

Updating an unknown number of post meta fields can be expensive. I would not touch that.

Leave a Comment