Передача аргументов в callback-функцию страницы меню админки WordPress

5 мая 2011 г., 12:47:47
Просмотры: 19K
Голосов: 17

Ситуация: Я работаю над плагином и разрабатываю его как класс, всё работало хорошо, пока я не столкнулся с этой ситуацией. Я хотел сделать код чище и попробовал это...

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

    // Не хочу писать отдельную функцию для каждой страницы настроек
    // предпочитаю загружать содержимое из внешнего файла.        
    function load_view($filename) {
        $view = require(dirname(__FILE__).'/views/'.$filename.'.php');
        return $view;
    }

    // Здесь возникает проблема
    function myplugin_create_menus() {
        add_menu_page( 'Название плагина',
                       'Название плагина',
                       'manage_options',
                       'my-plugin-settings',
                       array(&$this, 'load_view') // Где указать значение $filename??
                     );
    }

}#конец класса

Я пробовал разные варианты, но ничего не работает, может я смотрю прямо на решение, но не вижу его.

Конечно, это упрощённый пример, все мои функции имеют префиксы и выглядят не совсем так, как здесь, но надеюсь, вы поняли суть моего вопроса.

Заранее спасибо.

P.S.: Если хотите увидеть оригинальный исходный код, я с радостью вставлю его и дам ссылку.

0
Все ответы на вопрос 5
2
10

Вы не можете передать аргумент в callback-функцию. add_menu_page() добавляет её как обработчик действия, а admin.php запускает действие, без каких-либо аргументов.

Я вижу два простых решения этой проблемы. Первое — хранить все имена файлов в массиве внутри вашего класса, индексируя их по имени хука. Затем вы можете использовать это для поиска нужного файла для загрузки (вы также можете хранить дополнительные данные в этом массиве).

class WPSE16415_Plugin
{
    protected $views = array();

    function load_view() {
        // current_filter() также возвращает текущее действие
        $current_views = $this->views[current_filter()];
        include(dirname(__FILE__).'/views/'.$current_views.'.php');
    }

    function myplugin_create_menus() {
        $view_hook_name = add_menu_page( 'Название плагина',
            'Название плагина',
            'manage_options',
            'my-plugin-settings',
            array(&$this, 'load_view'),
        );
        $this->views[$view_hook_name] = 'options';
    }
}

Второй вариант — пропустить аргумент callback, чтобы WordPress сам включал файл, указанный в имени слага, как предлагает Брэди в своём ответе.

5 мая 2011 г. 16:05:49
Комментарии

Ах, вот оно что! Почему я не подумал сделать так :(

Scott Scott
5 мая 2011 г. 19:00:29

ДА!! Ты сегодня спас десятки котят... Никогда не слышал о функции 'current_filter'. Очень умное решение. Большое спасибо за помощь @Brady @Jan Fabry

Luis Luis
5 мая 2011 г. 19:39:17
5

Вы всегда можете использовать анонимную функцию (или замыкание). Например, что-то вроде:

add_menu_page( $page, $menu, $capability, $slug, function() { print_my_admin_page($with_args); }, $icon, $position);
25 июл. 2013 г. 03:24:02
Комментарии

У меня это не работает. Я использую WordPress 4.1 (и на сегодняшний день 4.1.1)

Jeff Vdovjak Jeff Vdovjak
19 февр. 2015 г. 22:35:27

Умно! И это действительно работает. Вот более полный пример: http://hastebin.com/segibugice который генерирует URL вида http://example.com/wp-admin/admin.php?page=my-slug

Quinn Comendant Quinn Comendant
15 мая 2015 г. 07:35:33

Я должен был упомянуть, что при передаче переменных в область видимости анонимной функции необходимо использовать ключевое слово "use". function() use ($my_var) { // теперь вы можете использовать $my_var }

user35752 user35752
27 мая 2015 г. 05:34:36

Могу подтвердить, что это отлично работает в WordPress v5.5

factorypolaris factorypolaris
16 окт. 2020 г. 12:19:19

У меня не работает в WP 6.3.2

rank rank
19 окт. 2023 г. 13:53:26
3

Я решил эту проблему, просто добавляя ID (или любые другие нужные данные) к слагу меню.

Например:

 add_menu_page( 'Название плагина',
                       'Название плагина',
                       'manage_options',
                       'my-plugin-settings-' . $identifier,
                       'setting-function-callback'
                     );

Это создаст URL вида 'my-plugin-settings-filename' (например), и я могу просто разобрать эту часть URL (с помощью $_GET или filter_input).

19 февр. 2015 г. 06:43:15
Комментарии

Вы также можете использовать параметр URL, но вам нужно создать пункт меню (который потом можно скрыть, если нужно).

Jeff Vdovjak Jeff Vdovjak
19 февр. 2015 г. 22:33:50

Спасибо, что оформил мой код в виде блока кода, toscho. Когда я задаю вопрос, там есть кнопка для этого, но я не знаком с разметкой, чтобы сделать это в ответе.

Jeff Vdovjak Jeff Vdovjak
19 февр. 2015 г. 22:36:19

Это отличная идея для решения проблемы.

rank rank
19 окт. 2023 г. 13:52:57
6

Функция load_view должна выглядеть так?:

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

И в вашем включаемом файле она должна выводить контент для отображаемой страницы.

РЕДАКТИРОВАНО:

Вот что говорит кодекс по этому поводу:

$menu_slug (string) (обязательный) Уникальный идентификатор для этого меню (должен быть уникальным для данного меню). До версии 3.0 этот параметр назывался file (или handle). Если параметр функции опущен, menu_slug должен быть PHP-файлом, который обрабатывает отображение содержимого страницы меню. По умолчанию: Нет

$function Функция, которая отображает содержимое страницы для пункта меню. Технически, параметр функции не является обязательным, но если он не указан, WordPress будет считать, что включаемый PHP-файл генерирует административный экран без вызова функции. Большинство авторов плагинов предпочитают размещать код генерации страницы в функции внутри основного файла плагина.:В случае, если параметр функции указан, можно использовать любую строку для параметра file. Это позволяет использовать страницы вида ?page=my_super_plugin_page вместо ?page=my-super-plugin/admin-options.php.

Из этого я могу сделать вывод, что если оставить функцию пустой, WordPress попытается включить PHP-файл на основе того, что вы установили в menu_slug.

РЕДАКТИРОВАНО 2

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

function myplugin_create_menus() {
    $this->filename = "something";
    add_menu_page( 'Название плагина',
                   'Название плагина',
                   'manage_options',
                   'my-plugin-settings',
                   array(&$this, 'load_view')
                 );
    $this->filename = "somethingelse";
    add_menu_page( 'Название плагина',
                   'Название плагина',
                   'manage_options',
                   'my-plugin-settings',
                   array(&$this, 'load_view')
                 );
}
5 мая 2011 г. 13:47:59
Комментарии

@Brady Я знаю это, и функция "load_view" работает корректно и выводит содержимое правильно при использовании статического значения. Например: incl..../views/my-panel.php');

Luis Luis
5 мая 2011 г. 13:57:38

@Luis - Тогда в чем проблема?

Scott Scott
5 мая 2011 г. 13:59:49

@Brady array(&$this, 'load_view') // Где я могу указать значение $filename??. Я не могу сделать что-то вроде array(&$this, 'load_view("my-value")'). Я хочу найти способ передавать параметры в вызываемую функцию

Luis Luis
5 мая 2011 г. 14:31:04

А, теперь я понял. Вы хотите передать метод класса, но с параметром. Я искал и искал, но не могу найти, как это сделать. Но раз вы передаете класс, то разве нельзя сделать так, как я указал в EDIT 2?

Scott Scott
5 мая 2011 г. 15:06:37

@Brady: Ваша вторая правка мало чем поможет, вы просто переопределяете переменную filename, так что она всегда будет "somethingelse". Ваша первая правка может сработать: если load_view ничего не делает, кроме включения файла, то действительно не стоит передавать callback-функцию, и WordPress попытается загрузить страницу, которую вы передали как slug.

Jan Fabry Jan Fabry
5 мая 2011 г. 15:48:59

@Brady, прежде всего, спасибо за ваши усилия :). Я тоже пробовал это (edit 2), но, как сказал @Jan Fabry, у меня получается последнее установленное значение для всех.

Luis Luis
5 мая 2011 г. 18:35:41
Показать остальные 1 комментариев
0

На основе ответа user35752, вы даже можете использовать метод объекта с параметрами в качестве 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)
15 янв. 2020 г. 15:21:25