Pasando argumentos a un callback de página de menú en el admin de WordPress

5 may 2011, 12:47:47
Vistas: 19K
Votos: 17

Situación: Estoy trabajando en un plugin y lo estoy desarrollando como una clase. Todo funcionaba bien hasta que me encontré con esta situación. Quería hacer las cosas un poco más limpias e intenté esto...

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

    // No quiero escribir una función para cada página de opciones que cree
    // prefiero cargar el contenido desde un archivo externo.        
    function load_view($filename) {
        $view = require(dirname(__FILE__).'/views/'.$filename.'.php');
        return $view;
    }

    // Aquí es donde surge el problema
    function myplugin_create_menus() {
        add_menu_page( 'Nombre del plugin',
                       'Nombre del plugin',
                       'manage_options',
                       'my-plugin-settings',
                       array(&$this, 'load_view') // ¿Dónde especifico el valor de $filename??
                     );
    }

}#fin de la clase

He probado varias opciones diferentes pero nada funciona, quizás lo tengo delante pero no lo veo.

Por supuesto esto es una recreación, he añadido prefijos a todas mis funciones y no son exactamente como las escribí aquí, pero espero que entiendan la idea de lo que pregunto.

Gracias de antemano.

P.D.: Si quieren ver el código fuente original estaré encantado de pegarlo y darles el enlace.

0
Todas las respuestas a la pregunta 5
2
10

No puedes pasar un argumento a la función de callback. add_menu_page() lo añade como un manejador de acción, y admin.php dispara la acción, sin ningún argumento.

Veo dos soluciones simples para este problema. Una es almacenar todos los nombres de archivo en un array en tu clase, indexados por el nombre del hook. Luego puedes usar esto para buscar qué archivo necesitas cargar (también puedes almacenar datos adicionales en este array).

class WPSE16415_Plugin
{
    protected $views = array();

    function load_view() {
        // current_filter() también devuelve la acción actual
        $current_views = $this->views[current_filter()];
        include(dirname(__FILE__).'/views/'.$current_views.'.php');
    }

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

La otra es omitir el argumento del callback, para que WordPress incluya el archivo indicado por el nombre del slug mismo, como Brady sugiere en su respuesta.

5 may 2011 16:05:49
Comentarios

¡Ah-ha! ¿Por qué no se me ocurrió hacerlo de esa manera? :(

Scott Scott
5 may 2011 19:00:29

¡¡SÍ!! Salvaste docenas de gatitos hoy... aunque nunca había escuchado de esa función 'current_filter'. Solución muy inteligente. Muchas gracias por tu ayuda @Brady @Jan Fabry

Luis Luis
5 may 2011 19:39:17
5

Siempre puedes utilizar una función anónima (o clausura). Algo como:

add_menu_page( $page, $menu, $capability, $slug, function() { print_my_admin_page($with_args); }, $icon, $position);
25 jul 2013 03:24:02
Comentarios

Esto no funciona para mí. Estoy usando WordPress 4.1 (y al día de hoy 4.1.1)

Jeff Vdovjak Jeff Vdovjak
19 feb 2015 22:35:27

¡Ingenioso! Y sí funciona. Aquí hay un ejemplo más completo: http://hastebin.com/segibugice que generaría una URL como http://example.com/wp-admin/admin.php?page=my-slug

Quinn Comendant Quinn Comendant
15 may 2015 07:35:33

Debería haber mencionado que cuando pasas variables al alcance de una función anónima, debes usar la palabra clave "use". function() use ($my_var) { // ahora puedes usar $my_var }

user35752 user35752
27 may 2015 05:34:36

Puedo confirmar que esto funciona perfectamente en WordPress v5.5

factorypolaris factorypolaris
16 oct 2020 12:19:19

No funciona para mí en WP 6.3.2

rank rank
19 oct 2023 13:53:26
3

Resolví este problema simplemente añadiendo el ID (o cualquier dato que necesites) al slug del menú.

Por ejemplo:

 add_menu_page( 'Nombre del plugin',
                       'Nombre del plugin',
                       'manage_options',
                       'mi-plugin-config-' . $identificador,
                       'funcion-callback-config'
                     );

Esto creará una URL con 'mi-plugin-config-archivo' (como ejemplo), y puedo analizar esa parte de la URL (con $_GET o filter_input).

19 feb 2015 06:43:15
Comentarios

También podrías usar un parámetro de URL, pero tienes que crear un ítem de menú (y luego puedes ocultarlo si lo deseas).

Jeff Vdovjak Jeff Vdovjak
19 feb 2015 22:33:50

Gracias por poner mi código en un bloque de código toscho. Cuando hago una pregunta hay un botón para eso, pero no estoy familiarizado con el marcado para hacerlo en una respuesta.

Jeff Vdovjak Jeff Vdovjak
19 feb 2015 22:36:19

Esta es una gran idea para resolver el problema.

rank rank
19 oct 2023 13:52:57
6

¿La función load_view debería ser así?:

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

y en tu archivo include debería imprimir cualquier contenido para la página que se está mostrando.

EDITADO:

Esto es lo que dice el Codex al respecto:

$menu_slug (string) (requerido) El nombre del slug para referirse a este menú (debe ser único para este menú). Antes de la Versión 3.0 esto se llamaba parámetro file (o handle). Si se omite el parámetro function, menu_slug debe ser el archivo PHP que maneja la visualización del contenido de la página del menú. Por defecto: Ninguno

$function La función que muestra el contenido de la página para la página del menú. Técnicamente, el parámetro function es opcional, pero si no se proporciona, WordPress asumirá básicamente que incluir el archivo PHP generará la pantalla de administración, sin llamar a una función. La mayoría de los autores de plugins eligen poner el código generador de página en una función dentro de su archivo principal del plugin.:En caso de que se especifique el parámetro function, es posible usar cualquier cadena para el parámetro file. Esto permite el uso de páginas como ?page=my_super_plugin_page en lugar de ?page=my-super-plugin/admin-options.php.

Entonces, lo que puedo deducir de esto es que si dejas function vacío intenta incluir un archivo php basado en lo que hayas establecido en menu_slug.

EDITADO 2

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

function myplugin_create_menus() {
    $this->filename = "something";
    add_menu_page( 'Nombre del plugin',
                   'Nombre del plugin',
                   'manage_options',
                   'my-plugin-settings',
                   array(&$this, 'load_view')
                 );
    $this->filename = "somethingelse";
    add_menu_page( 'Nombre del plugin',
                   'Nombre del plugin',
                   'manage_options',
                   'my-plugin-settings',
                   array(&$this, 'load_view')
                 );
}
5 may 2011 13:47:59
Comentarios

@Brady Lo sé, y la función "load_view" está funcionando bien y mostrando el contenido correctamente cuando se usa un valor estático. Por ejemplo: incl..../views/my-panel.php');

Luis Luis
5 may 2011 13:57:38

@Luis - Entonces ¿cuál es el problema?

Scott Scott
5 may 2011 13:59:49

@Brady array(&$this, 'load_view') // ¿Dónde especifico el valor de $filename??. No puedo hacer algo como array(&$this, 'load_view("my-value")') Quiero encontrar una manera de pasar parámetros a la función que estoy llamando

Luis Luis
5 may 2011 14:31:04

Ah, ya entiendo. Quieres pasar una función de clase pero con un parámetro. Bueno, he buscado y buscado y no encuentro cómo hacerlo. Pero ya que estás pasando la clase, ¿no podrías hacer lo que he puesto en EDIT 2?

Scott Scott
5 may 2011 15:06:37

@Brady: Tu segunda edición no ayudará mucho, solo sobrescribes la variable filename por lo que siempre será "somethingelse". Tu primera edición podría ser la clave aquí: si load_view no hace nada excepto incluir el archivo, realmente no deberías pasar una función callback y WordPress intentará cargar la página que pasaste como slug.

Jan Fabry Jan Fabry
5 may 2011 15:48:59

@Brady primero que nada gracias por tus esfuerzos :). También probé eso (edición 2) pero como dijo @Jan Fabry obtengo el último valor establecido para todos.

Luis Luis
5 may 2011 18:35:41
Mostrar los 1 comentarios restantes
0

Basado en la respuesta de user35752, incluso puedes usar un método de objeto con parámetros como 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 ene 2020 15:21:25