Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

How can I make updates a public plugin of mine without breaking the plugin for all existing users.

Firstly, I'd like to change the main plugin's class/namespace, because I'd like it to be similar to other classes in the plugin that it extends.

So I'd like to change

class some_class(){}

to

class Some_Class(){}

Secondly, the whole class is instantiated and saved in a global variable.

global $some_class;
$some_class = new some_class();

Somewhere on here I saw a good example of how to instantiate a class without a global (can't find it now of course, #doh). The global can be used by users to add/remove a couple of templates. Is there a way to get rid of the global without completely breaking the themes of people who might be using it to manipulate the templates?

Thirdly, related to above, my main plugin file has gotten really big and I'd like to split it up into pieces for my own sanity. However, if the some_templates() method is in the some_class() is it possible to move it to the front_end_class() without breaking things for users?

For example

To unhook an action in my plugin

function remove_method(){
  global $some_class;
  remove_action('wp_head', array($someclass, 'some_templates'));
}
add_action('init','remove_method');

Can the class structure and global variable setup be adjusted without breaking this. How can I alert people that this has changed? _doing_it_wrong() ?

Finally, I've been saving some post meta as "yes" versus "no" in lieu of a boolean. Does it make sense to change this?

share|improve this question
    
Since you mentioned a post about instantiating without a global here's such a post about with links to several other related posts: hardcorewp.com/2013/… –  MikeSchinkel Apr 11 '13 at 5:46

1 Answer 1

up vote 3 down vote accepted

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.

share|improve this answer
    
Was hoping you might respond to this! Thanks! Could I trouble you to take a look at the example third-party code I've added? Could I still implement your demo class structure, and/or move some_templates() to a separate class without breaking that? –  helgatheviking Mar 3 '13 at 13:35
    
@helgatheviking See my update. –  toscho Mar 3 '13 at 14:14
    
Thanks so much! I don't know if I'll be able to implement it with this particular plugin because of all the back-compatibility, but this will be super handy for the next one! –  helgatheviking Mar 3 '13 at 16:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.