Wrapper class: How to get rid of call_user_func_array() warning?

I have several installations of wordpress and now im trying to create my own small framework so I can create and maintain my themes more efficiently. What I would like to do is to have a wrapper for the hooks that wordpress offer.

I would like to call hooks like this in my application

Read More
$_addThumb = function(){
add_theme_support('post-thumbnails');
};

 $core->registerAction(array('tag' => 'after_theme_setup', 
                             'callback' => $_redirect
                             ));

In my class I handle the logic like this (this is a snippet, the whole code is below)

    if (!empty($this -> _actions)) {
        foreach ($this->_actions as $action) {
            add_action($action[0], array($this, call_user_func($action[1])));
        }
    }

The problem is that if I add the $this keyword to the add_action call like this …

add_action($tag, array($this, $callback))  

… I get this warning:

Warning: call_user_func_array() expects parameter 1 to be a valid callback, second array member is not a valid method in Z:Websitewp-includesplugin.php

And if I don’t add it like this …

add_action($tag, $callback)

Then I get this notice:

Undefined offset: 0 in Z:Websitewp-includesplugin.php

On both scenarios everything works though. I just would like to understand why is this happening and at least get rid of the warning.

Here is my complete code:

class Core {

/**
 * theme features
 */
protected $_features = array();
private $_actions = array();


/**
 * register extra functions so you can add actions to the theme
 *@param array mixed
 */
public function registerAction($args) {

    if (!is_array($args)) {
        $args = func_get_args();
    }
    if (count($args) < 2) {
        throw new InvalidArgumentException(sprintf('Not enough arguments(registerCallback needs at least two arguments): %s.', print_r($args, true)));
    }
    $arg_list = array_values($args);

    /**
     * sets the default priority
     */
    if (!isset($arg_list[2])) {
        $arg_list[2] = 10;
    }
    /**
     * sets default args
     */
    if (!isset($arg_list[3])) {
        $arg_list[3] = 0;
    }

    if (!is_callable($arg_list[1])) {
        throw new Exception("callback not callable : Core:13");
    }

    $this -> _actions[] = $arg_list;

}

/**
 * TODO: development only
 */
public function get_actions() {
    echo "<pre>";
    print_r($this -> _actions);
    echo "</pre>";
}

/**
 * set theme features
 * 'post-formats'
 * 'post-thumbnails'
 * 'custom-background'
 * 'custom-header'
 * 'automatic-feed-links'
 * 'menus'
 * @param string (required) name of the feature to be added
 * @param array (optional) optional arguments
 */
public function set_feature($feature, $options = array()) {

    if (is_array($options) && !empty($options)) {
        $this -> _features[]['args'] = array($feature, $options);
    } else {
        $this -> _features[]['name'] = $feature;
    }
}

public function get_features() {
    return $this->_features;
}

function __construct() {

}

public function init($tag = '', $function = '') {
    add_action('after_setup_theme', array($this, 'initial_setup'));

    if (!empty($this -> _actions)) {
        foreach ($this->_actions as $action) {
            add_action($action[0], array($this, call_user_func($action[1])), $action[2], $action[3]);
        }
    }
}

public function initial_setup() {

    // check if we have ay features so we can add them to our theme
    if (!empty($this -> _features)) {
        foreach ($this->_features as $feature) {
            if (isset($feature['args'])) {
                add_theme_support($feature['args'][0], $feature['args'][1]);
            } else {
                add_theme_support($feature['name']);
            }
        }
    }
}

}

my functions.php

$core = new Core();

$core->set_feature('automatic-feed-links');

$core->set_feature('post-formats', array('aside',
                                         'image',
                                         'link',
                                         'quote',
                                         'status',
                                         'gallery',
                                         'video' ));
$_addThumb = function(){
    add_theme_support('post-thumbnails');
};

$_sidebars = function() {
    register_sidebar( array(
        'name'          => __( 'Main Widget Area', 'twentythirteen' ),
        'id'            => 'sidebar-1',
        'description'   => __( 'Appears in the footer section of the site.', 'twentythirteen' ),
        'before_widget' => '<aside id="%1$s" class="widget %2$s">',
        'after_widget'  => '</aside>',
        'before_title'  => '<h3 class="widget-title">',
        'after_title'   => '</h3>',
    ) );

    register_sidebar( array(
        'name'          => __( 'Secondary Widget Area', 'twentythirteen' ),
        'id'            => 'sidebar-2',
        'description'   => __( 'Appears on posts and pages in the sidebar.', 'twentythirteen' ),
        'before_widget' => '<aside id="%1$s" class="widget %2$s">',
        'after_widget'  => '</aside>',
        'before_title'  => '<h3 class="widget-title">',
        'after_title'   => '</h3>',
    ) );
};

$_adminHead = function(){

echo '<style>[for="wp_welcome_panel-hide"] {display: none !important; } #normal-sortables{display:none !important;}</style>';

};

/** i don't get a notiche with this **/
$core->registerAction(array('tag' => 'after_theme_setup', 'callback' => $_addThumb));

/** it works but i get this warning 
 * arning: call_user_func_array() expects parameter 1 to be a valid callback, second array member is not a valid method in Z:Armen Websitewp-includesplugin.php on line
 */
$core->registerAction(array('tag' =>'admin_head', 'callback' => $_adminHead));
$core->registerAction(array('tag' => 'widgets_init', 'callback' => $_sidebars));
$core->init();

Related posts

2 comments

  1. As you have noticed already, $this will not work as you expected prior to PHP 5.4. You can read this in the PHP wiki. The reason:

    For PHP 5.3 $this support for Closures was removed because no consensus could be reached how to implement it in a sane fashion. This RFC describes the possible roads that can be taken to implement it in the next PHP version.

    An easy workaround is to simple copy $this up front, then use the new reference/ variable:

    $subject = clone $this;
    
  2. I figure it out. the problem is that add_action is expecting an object with a method. add_action($action[0], array($this, call_user_func($action[1]))); im passing the object with the $this keyword but the method is not recognized because is a closure so it’s outside of the scope of the class the best solution would be to bind the closure to the object however im using php 5.3 and closure binding is available on version 5.4 only. So what i ended it up doing was to create a registy for all the closures and attach and alias to it so that each closure will look like a method of the class. what gave me this idea was this answer https://stackoverflow.com/a/420030/1287608 and this is how i end it up doing it. notice how im adding a new method to the registry with an alias “loadAction” in this case. $this->register($closure, "loadAction{$i}")

    public function init($tag = '', $function = '') {
    
        add_action('after_setup_theme', array($this, 'initial_setup'));
    
        if (!empty($this -> _actions)) {
            $i = 0;
            foreach ($this->_actions as $action) {
                $this->register($action[1], "loadAction{$i}");
                $success = add_action($action[0], array($this, "loadAction{$i}"), $action[2], $action[3]);
            $i++;
            }
        }
    }
    

Comments are closed.