15

Situation: I'm working on a plugin and I'm developing it as a class, everything worked fine until I run into this situation. I wanted to make things a bit cleaner and tried this..

class MyPlugin {
    function __construct() {
        add_action('admin_menu', array(&$this, 'myplugin_create_menus');
    }        

    //I don't want to write a function for every options page I create
    //so I prefer to just load the content from an external file.        
    function load_view($filename) {
        $view = require(dirname(__FILE__).'/views/'.$filename.'.php');
        return $view;
    }

    //Here is where the problem comes
    function myplugin_create_menus() {
        add_menu_page( 'Plugin name',
                       'Plugin name',
                       'manage_options',
                       'my-plugin-settings',
                       array(&$this, 'load_view') // Where do I specify the value of $filename??
                     );
    }

}#end of class

I've tried a bunch of different options but nothing works, maybe I'm in front of it but I can't see it.

Of course this is a re-creation, I've prefixed all my functions and they are not exactly as I wrote here but I hope you got the idea of I'm asking for.

Thanks in advance.

P.D.: If you want to see the original source code I'll be glad to paste it and give you the link.

5 Answers 5

9

You can't pass an argument to the callback function. add_menu_page() adds it as an action handler, and admin.php fires the action, without any arguments.

I see two simple solutions to this problem. One is to store all filename in an array in your class, indexed by hook name. Then you can use this to look up what file you need to load (you can also store additional data in this array).

class WPSE16415_Plugin
{
    protected $views = array();

    function load_view() {
        // current_filter() also returns the current action
        $current_views = $this->views[current_filter()];
        include(dirname(__FILE__).'/views/'.$current_views.'.php');
    }

    function myplugin_create_menus() {
        $view_hook_name = add_menu_page( 'Plugin name',
            'Plugin name',
            'manage_options',
            'my-plugin-settings',
            array(&$this, 'load_view'),
        );
        $this->views[$view_hook_name] = 'options';
    }
}

The other is to skip the callback argument, so WordPress will include the file indicated by the slug name itself, as Brady suggests in his answer.

2
  • ah-ha why didn't I think of doing it that way :(
    – Scott
    May 5, 2011 at 16:00
  • YEAH!! you saved dozens of kittens today.. never heard of that function though 'current_filter'. Very clever solution. Thanks a lot for your help @Brady @Jan Fabry
    – Luis
    May 5, 2011 at 16:39
4

You could always just use an anonymous function (or closure). Something to the affect of:

add_menu_page( $page, $menu, $capability, $slug, function() { print_my_admin_page($with_args); }, $icon, $position);
4
  • 1
    This doesn't work for me. I'm using WordPress 4.1 (and as of today 4.1.1) Feb 19, 2015 at 20:35
  • Clever! And it does work. Here's a more complete example: hastebin.com/segibugice which would generate a URL like example.com/wp-admin/admin.php?page=my-slug May 15, 2015 at 4:35
  • I should have mentioned when passing variables into the scope of an anonymous function, you have to use the "use" keyword. function() use ($my_var) { // now you can use $my_var }
    – user35752
    May 27, 2015 at 2:34
  • I can confirm this works great in WordPress v5.5 Oct 16, 2020 at 9:19
0

the function load_view should be like this?:

function load_view($filename) {
    include(dirname(__FILE__).'/views/'.$filename.'.php');
}

and in your include file it should echo any content for the page being displayed.

EDIT:

Here is what the codex says on the matter:

$menu_slug (string) (required) The slug name to refer to this menu by (should be unique for this menu). Prior to Version 3.0 this was called the file (or handle) parameter. If the function parameter is omitted, the menu_slug should be the PHP file that handles the display of the menu page content. Default: None

$function The function that displays the page content for the menu page. Technically, the function parameter is optional, but if it is not supplied, then WordPress will basically assume that including the PHP file will generate the administration screen, without calling a function. Most plugin authors choose to put the page-generating code in a function within their main plugin file.:In the event that the function parameter is specified, it is possible to use any string for the file parameter. This allows usage of pages such as ?page=my_super_plugin_page instead of ?page=my-super-plugin/admin-options.php.

So what I can gather from this is that if you leave function empty it tries to include a php file based on what you have set the menu_slug to.

EDIT 2

function load_view() {
    include(dirname(__FILE__).'/views/'.$this->filename.'.php');
}

function myplugin_create_menus() {
    $this->filename = "something";
    add_menu_page( 'Plugin name',
                   'Plugin name',
                   'manage_options',
                   'my-plugin-settings',
                   array(&$this, 'load_view')
                 );
    $this->filename = "somethingelse";
    add_menu_page( 'Plugin name',
                   'Plugin name',
                   'manage_options',
                   'my-plugin-settings',
                   array(&$this, 'load_view')
                 );
}
6
  • @Brady I know that, and the function "load_view" is working well and outputting the content correctly when using a static value. For example: incl..../views/my-panel.php');
    – Luis
    May 5, 2011 at 10:57
  • @Luis - Then whats the issue?
    – Scott
    May 5, 2011 at 10:59
  • @Brady array(&$this, 'load_view') // Where do I specify the value of $filename??. I can't do something like array(&$this, 'load_view("my-value")') I want to find a way to pass parameters to the function I'm calling
    – Luis
    May 5, 2011 at 11:31
  • Oh i get it now. You want to pass a class function but with a parameter. Well Ive looked and looked and cannot find how you do it. But since you are passing the class then cannot you do what I have put in EDIT 2?
    – Scott
    May 5, 2011 at 12:06
  • @Brady: Your second edit will not help much, you just override the filename variable so it will always be "somethingelse". Your first edit could be the trick here: if load_view does nothing except for including the file, you should indeed not pass a callback function and WordPress will try to load the page you passed as the slug.
    – Jan Fabry
    May 5, 2011 at 12:48
0

I solved this problem by just appending the ID (or whatever data you need to) to the menu slug.

For example:

 add_menu_page( 'Plugin name',
                       'Plugin name',
                       'manage_options',
                       'my-plugin-settings-' . $identifier,
                       'setting-function-callback'
                     );

This will then create a URL with 'my-plugin-settings-filename' (as an example), and I can just parse that part of the URL (with the $_GET or filter_input).

2
  • You could also use a URL parameter, but you have to create a menu item (and then you can hide it if you want). Feb 19, 2015 at 20:33
  • Thanks for putting my code into a code block toscho. When I ask a question there's a button for it, but I'm not familiar with the markup to do it in an answer. Feb 19, 2015 at 20:36
0

Based on user35752 answer, you can even use an object method with params as callback.

$args = [ [new Foo(), 'bar'], [$param1, $param2, ...] ];

$callback = function () use ($args){
                call_user_func_array($args[0], $args[1]);
            };
add_menu_page( $page, $menu, $capability, $slug, $callback , $icon, $position)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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