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.

Is it possible to reference a class instead of a function in 'add_action'? Can't seem to figure it out. Here is just a basic example of the function in question.

add_action( 'admin_init', 'MyClass' );
class MyClass {
     function __construct() {
          .. This is where stuff gets done ..
     }
}

So yeah, that doesn't work. I've also tried:

$var = new MyClass();
add_action( 'admin_init', array( &$var ) );

And:

$var = new MyClass();
add_action( 'admin_init', array( &$var, '__construct' ) );

And also:

add_action( 'admin_init', 'MyClass::__construct' );

Is there anyway I can do this without having to create a separate function that loads the class? I'd like to be able to just run the classes constructor through the add_action. That's all that needs to be loaded to get the ball rolling.

share|improve this question

5 Answers 5

up vote 13 down vote accepted

No, you cannot 'initialise' or instantiate the class through a hook, not directly. Some additional code is always required ( and it is not a desirable thing to be able to do that, as you're opening a can of worms for yourself.

Here is a better way of doing it:

class MyClass {
     function __construct() {
          add_action( 'admin_init',array( $this, 'getStuffDone' ) );
     }
     function getStuffDone() {
          // .. This is where stuff gets done ..
     }
}
$var = new MyClass();

Of course one could create an interface class to simplify it for the general case even further:

class IGetStuffDone {
    function IGetStuffDone(){
        add_action( 'admin_init',array( $this, 'getStuffDone' ) );
    }
    public abstract function getStuffDone();
}

Which would let you say:

class CDoingThings extends IGetStuffDone {
    function getStuffDone(){
        // doing things
    }
}
$var = new CDoingThings();

Which would then automatically add all the hooks, you just need to define what exactly is being done in a subclass and then create it!

On Constructors

I wouldn't add a constructor as a hook function, it's bad practice, and can lead ot a lot of unusual events. Also in most languages a constructor returns the object that is being instantiated, so if your hook needs to return something like in a filter, it will not return the filtered variable as you want, but instead it will return the class object.

Calling a constructor or a destructor is very, very, very bad programming practice, no matter which language you're in, and should never be done.

Constructors should also construct objects, to initialise them ready for use, not for actual work. Work to be done by the object should be in a separate function.

Static class methods, and not needing to instantiate/initialise at all

If your class method is a static class method, you can pass the name of the class in quotes rather than &$this as shown below:

class MyClass {
     public static function getStuffDone() {
          // .. This is where stuff gets done ..
     }
}
add_action('admin_init',array('MyClass','getStuffDone'));

Closures & PHP 5.3

Sadly you cannot avoid the line creating the new class. The only other solution to skipping it would involve boiler plate code that still has that line, and would require PHP 5.3+ e.g.:

add_action('admin_init',function(){
    $var = new MyClass();
    $var->getStuffDone();
});

At which point you may as well skip the class, and just use a function:

add_action('admin_init',function(){
    // do stuff
});
share|improve this answer
    
Ok. Thank you from all of that; really learnt quite a bit. I'm really only getting comfortable in class based PHP now. This is what I have done, and it works, but could you tell me if it is bad practice/incorrect in any way? I've initiated the class inside a static function, within the class itself. Then referenced the static function in the add_action. See this link: pastebin.com/0idyPwwY –  Matthew Ruddy Apr 5 '12 at 14:35
    
yes you could do it that way, though I could avoid using $class as your variable name, those words tend to be reserved. I think you're going way out of your way to avoid saying something similar to $x = new Y(); in the global scope, and you're adding complexity where none is necessary. Your attempt to reduce the amount of code written has involved writing more code! –  Tom J Nowell Apr 5 '12 at 14:45
    
I'd point out in all of the above cases, you would be better off using a function rather than a class, as that class will be discarded anyway and serves the same purpose. It's a waste of resources. Remember, there is a cost to creating and destroying an object, you want few objects, and you want them to be long lived –  Tom J Nowell Apr 5 '12 at 14:47
    
Good point. Changed the way I've been looking at it. I think I'll call it in the global scope instead, avoiding the extra code. –  Matthew Ruddy Apr 5 '12 at 15:09

Example class

Notes:

  • Init the class only once
    • Call on priority 0, so you can use the same hook with the default priority later
    • Wrap it up in a ! class_exists to avoid calling it twice and place the init caller inside
  • Make the init function and the class var static
  • Call the constructor from inside your init, when you call the class new self.

Here's an example

if ( ! class_exists( 'WPSESampleClass' ) )
{
    // Init the class on priority 0 to avoid adding priority inside the class as default = 10
    add_action( 'init', array ( 'WPSESampleClass', 'init' ), 0 );

class WPSESampleClass
{
    /**
     * The Class Object
     */
    static private $class = null;

    public static function init()
    {
        if ( null === self::$class ) 
            self :: $class = new self;

        return self :: $class;
    }

    public function __construct()
    {
        // do stuff like add action calls:
        add_action( 'init', array( $this, 'cb_fn_name' ) );
    }

    public function cb_fn_name()
    {
        // do stuff 
    }
} // END Class WPSESampleClass

} // endif;

Php 5+

Please, leave the & out. We're already beyond php4. :)

share|improve this answer

Generally speaking, you wouldn't add an entire class to a hook. The add_action()/add_filter() hooks expect callback functions, which can be referenced from within a class.

Let's say that you have an init() function inside your class, that you want to hook into the WordPress init hook.

Put your add_action() call inside your class, and then identify the callback like so:

add_action( 'init', array( &$this, 'init' ) );

(Note: I'm assuming your class is properly namespaced; otherwise, be sure to namespace your callback functions.)

share|improve this answer
    
What about if the current class hasn't already been initiated? I was trying to use add_action to actually initiate, so I don't have to add $var = new MyClass(); beforehand elsewhere. –  Matthew Ruddy Apr 5 '12 at 14:08
    
Can you not just write a callback to instantiate your class at init (or wherever you need it)? –  Chip Bennett Apr 5 '12 at 15:55

You should be able to do it by passing the class name instead of the instantiated object:

add_action( 'init', array( 'MyClass', '__construct' ) );

(In theory, your other solution should work too

$var = new MyClass();
add_action( 'admin_init', array( &$var, '__construct' ) );

Not sure off the head why it doesn't. Maybe if you don't call by reference?)

share|improve this answer
    
First one doesn't work. Just makes the page go blank. The second works, but only because the class has been initiated in the first line. It sort of defeats the purpose of adding the action, because the class has already been initiated. But it doesn't do what I'm trying to do, which is initiate the class through the action. In the actual code I'm working on, the action isn't 'admin_init' but a custom action within another class. I don't want the function 'MyClass' to be initiated if the action in the other class isn't there. Sorry if I'm missing something; learning as I go –  Matthew Ruddy Apr 5 '12 at 14:15
    
Yeah, I was wrong. That only works if you're calling a static init method. See wordpress.stackexchange.com/a/48093/14052 –  Boone Gorges Apr 5 '12 at 15:17

Note the anonymous function technique (a.k.a. lambda) has one drawback: it can't be removed with remove_action(). Otherwise it is ideal for simple actions.

share|improve this answer

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.