in

3 enfoques para agregar campos configurables a su complemento de WordPress

Cualquiera que haya creado un complemento de WordPress comprende la necesidad de crear campos configurables para modificar el funcionamiento del complemento. Hay innumerables usos para las opciones configurables en un complemento, y casi tantas formas de implementar dichas opciones. Verás, WordPress permite a los autores de complementos crear su propio marcado dentro de sus páginas de configuración. Como efecto secundario, las páginas de configuración pueden variar mucho entre complementos. En este artículo, repasaremos tres formas comunes en las que puedes configurar tu complemento. Comenzaremos creando una página de configuración y crearemos nuestros campos utilizando la API de configuración de WordPress predeterminada. Luego, te guiaré a través de cómo configurar tus campos con un controlador personalizado. Finalmente, te mostraré cómo integrar un excelente complemento de campos configurables Advanced Custom Fields (ACF) en tu propio complemento.

Cualquiera que haya creado un complemento de WordPress comprende la necesidad de crear campos configurables para modificar el funcionamiento del complemento. Hay innumerables usos para las opciones configurables en un complemento, y casi tantas formas de implementar dichas opciones. Verás, WordPress permite a los autores de complementos crear su propio marcado dentro de sus páginas de configuración. Como efecto secundario, las páginas de configuración pueden variar mucho entre complementos. En este artículo, repasaremos tres formas comunes en las que puedes configurar tu complemento. Comenzaremos creando una página de configuración y crearemos nuestros campos utilizando la API de configuración de WordPress predeterminada. Luego, te guiaré a través de cómo configurar tus campos con un controlador personalizado. Finalmente, te mostraré cómo integrar un excelente complemento de campos configurables Advanced Custom Fields (ACF) en tu propio complemento. Dado que ésta es una publicación larga, aquí hay una tabla de contenido con enlaces a cada una de las secciones principales:

Para obtener ejemplos de código, consulta el repositorio en el que me he basado para acompañar a esta publicación.

Creación de nuestro complemento y página de configuración  #

Lo primero que debemos hacer es configurar nuestro complemento y crear una página de configuración. Los tres enfoques descritos en este artículo comienzan con la estructura del complemento a continuación. Esta estructura de complemento está orientada a objetos, por lo que puede haber algunas diferencias en tu propio código si tu complemento está escrito de forma procedimental. Presta especial atención al formato de la función de devolución de llamada en las acciones y filtros.


/*
    Plugin Name: Smashing Fields Plugin
    description: >-
  Setting up configurable fields for our plugin.
    Author: Matthew Ray
    Version: 1.0.0
*/
class Smashing_Fields_Plugin {
    // Our code will go here
}
new Smashing_Fields_Plugin();

Dentro de nuestra clase vamos a agregar un gancho de acción para agregar la página de configuración:

public function __construct() {
    // Hook into the admin menu
    add_action( 'admin_menu', array( $this, 'create_plugin_settings_page' ) );
}

Puedes ver que la devolución de llamada de nuestra acción es create_plugin_settings_page, así que creamos ese método. Nota: he configurado los argumentos como variables con nombre separadas para dar contexto a nuestro código, pero simplemente puedes colocar los valores directamente en la función para ahorrar memoria.

public function create_plugin_settings_page() {
    // Add the menu item and page
    $page_title = 'My Awesome Settings Page';
    $menu_title = 'Awesome Plugin';
    $capability = 'manage_options';
    $slug = 'smashing_fields';
    $callback = array( $this, 'plugin_settings_page_content' );
    $icon = 'dashicons-admin-plugins';
    $position = 100;

    add_menu_page( $page_title, $menu_title, $capability, $slug, $callback, $icon, $position );
}

Echa un vistazo al codex de WP para obtener más información de add_menu_page. Esta función creará nuestra página, así como el elemento del menú. Las partes importantes aquí son los argumentos slug, capacidad y devolución de llamada. El slug lo usaremos más adelante para registrar nuestros campos, así que escríbelo en alguna parte. Puedes cambiar la capacidad para permitir que diferentes niveles de usuario accedan a tu página de configuración. En cuanto a la devolución de llamada, crearemos ese método en breve. Ten en cuenta que también puedes poner una clase de icono de guión directamente en la función para cambiar el icono del menú. El último argumento es la posición del elemento de menú dentro del menú; juega con este número para encontrar el lugar en el menú en el que te gustaría que cayera su configuración. Nota: puedes utilizar valores decimales para evitar conflictos con otros elementos del menú. Nuestro siguiente paso es crear el método de devolución de llamada plugin_settings_page_content para nuestra página de configuración.

public function plugin_settings_page_content() {
    echo 'Hello World!';
}

Si guardas el complemento y actualizas el panel de administración de WordPress, deberías ver lo siguiente:

El estado inicial de la página de configuración. (Ver versión grande)

Puedes ver que tu página de configuración es un elemento de menú de nivel superior. Es posible que prefieras dejarlo de esta manera en función de las necesidades de la página de configuración. Sin embargo, es posible que también desees tener la configuración de tu complemento en otro elemento del menú. En este caso, simplemente cambia la última línea del método create_plugin_settings_page a lo siguiente:

add_submenu_page( 'options-general.php', $page_title, $menu_title, $capability, $slug, $callback );

Aquí estamos cambiando la función add_menu_page de add_submenu_page y anteponiendo un nuevo argumento. Ese argumento es el elemento del menú principal en el que estará la nueva página de configuración. En la documentación de add_submenu_page puedes ver una lista bastante buena de los elementos del menú principal y sus slugs. También puedes ver que ya no tenemos los dos últimos argumentos $icon y $position. Dado que ahora estamos en la sección del submenú, ya no tenemos control sobre la posición del elemento. Además, los submenús no tienen iconos disponibles para ellos, por lo que no es necesario ese argumento. Si guardas este nuevo código, verás que nuestra página de configuración se mostrará en el elemento del menú Configuración:

La página de configuración ahora se ha colocado en el menú Configuración. (Ver versión grande)

En muchos casos, el lugar más apropiado para agregar una página de configuración de complementos es en el elemento Configuración. En el codex de WordPress, explica que la sección Configuración se usa para «Mostrar opciones de complementos que solo los administradores deben ver». Sin embargo, esto es solo una guía, no una regla. Ahora que tenemos nuestra página de configuración configurada y sabemos cómo mover los elementos, podemos comenzar a trabajar en los campos. El trabajo que hemos realizado hasta ahora se reutilizará para los diversos métodos a continuación.

Enfoque 1: Uso de la funcionalidad incorporada de WordPress  #

Antes de profundizar demasiado en el código, repasemos algunos de los pros y los contras de usar este enfoque.

Pros  #

  • Fácil de integrar en las páginas de configuración existentes
  • Es poco probable que se rompa ya que el código es administrado por WordPress
  • Se puede usar tanto para temas como para complementos
  • Flexible, seguro y extensible

Contras  #

  • La validación de datos personalizados es manual
  • Los tipos de campo avanzados (repetidores, mapas, cargas, etc.) son más difíciles de implementar

¿Cuándo deberías utilizar este enfoque? #

Este enfoque es lo suficientemente flexible como para personalizarlo para páginas de configuración muy simples o muy avanzadas. Puedes utilizar este método en la mayoría de situaciones si no te importa hacer algunas cosas manualmente.

Empezando  #

Con este enfoque, tendremos que seguir el mismo marcado que usan las páginas de opciones de WordPress. Deberíamos modificar nuestro método plugin_settings_page_content a lo siguiente:

public function plugin_settings_page_content() { ?>
    <div class="wrap">
        <h2>My Awesome Settings Page</h2>
        <form method="post" action="options.php">
            <?php
                settings_fields( 'smashing_fields' );
                do_settings_sections( 'smashing_fields' );
                submit_button();
            ?>
        </form>
    </div> <?php
}

El marcado anterior es directamente del codex de WordPress sobre la creación de páginas de opciones. El nombre del método debe coincidir con el nombre de devolución de llamada que pusimos en la función add_menu_page anterior. El contenedor div es en realidad el mismo que un formulario de WordPress predeterminado y extraerá los estilos de esas secciones. La etiqueta form apunta al controlador de formulario de opciones predeterminado para WordPress. Las tres líneas de PHP hacen varias cosas:

  • La función settings_fields es básicamente una referencia para el resto de nuestros campos. El argumento de cadena que ingresa en esa función debe coincidir con la variable $slug que configuramos anteriormente; estará en todos los campos que registremos más adelante en el complemento. Esta función también genera algunas entradas ocultas para el nonce, la acción del formulario y algunos otros campos para la página de opciones.
  • La siguiente función, do_settings_sections es un marcador de posición para las secciones y campos que registraremos en otro lugar de nuestro complemento.
  • La última función, submit_button generará la entrada de envío, pero también agregará algunas clases según el estado de la página. Puede haber otros argumentos que desee pasar a la función submit_button; se describen en el codex.

Si actualizamos nuestra página de configuración, deberíamos obtener algo parecido a esto:

Nuestra página de configuración antes de registrar secciones y campos.

¡Se ve un poco escaso! Comencemos a configurar los campos ahora.

Secciones y campos  #

WordPress separa sus páginas de opciones en secciones. Cada sección puede tener una lista de campos asociados. Necesitamos registrar una sección en nuestro complemento antes de que podamos comenzar a agregar nuestros campos. Agrega el siguiente código a tu función constructora:

add_action( 'admin_init', array( $this, 'setup_sections' ) );

Este gancho configurará las secciones de nuestra página. Aquí está el código para la devolución de llamada:

public function setup_sections() {
    add_settings_section( 'our_first_section', 'My First Section Title', false, 'smashing_fields' );
}

El primer argumento es un identificador único para la sección y lo usaremos para los campos que deseamos asignar a la sección. Estos identificadores deben ser únicos para todas las secciones nuevas de esta página. El siguiente argumento es el título que se genera encima de la sección; puedes hacerlo como quieras. El tercer argumento es la devolución de llamada. Ahora mismo lo tengo configurado false, pero lo revisaremos en breve. El cuarto argumento es la página de opciones a la que se agregarán las opciones (la $slug variable de antes). Entonces, ¿por qué hay una devolución de llamada false? Bueno, algo que no está muy claro al configurar las opciones de WordPress usando su documentación es que múltiples secciones pueden compartir una devolución de llamada. A menudo, cuando configuras una devolución de llamada, existe una relación de 1 por 1 entre el gancho y la devolución de llamada. Entonces, solo por ejemplo, intentemos crear tres secciones con la misma devolución de llamada:

public function setup_sections() {
    add_settings_section( 'our_first_section', 'My First Section Title', array( $this, 'section_callback' ), 'smashing_fields' );
    add_settings_section( 'our_second_section', 'My Second Section Title', array( $this, 'section_callback' ), 'smashing_fields' );
    add_settings_section( 'our_third_section', 'My Third Section Title', array( $this, 'section_callback' ), 'smashing_fields' );
}

Las tres secciones tienen la devolución de llamada section_callback configurada en ese tercer espacio de argumento. Si luego creamos un método que coincida con esa devolución de llamada y colocamos un «Hola mundo» allí:

public function section_callback( $arguments ) {
    echo '

Hola Mundo ‘; } obtenemos algo que se parece a esto:

Tres secciones que comparten la misma devolución de llamada.

Sé lo que estás pensando, «¿Por qué diablos querría tener el mismo texto en todas mis secciones?» La respuesta es que probablemente no lo harás así. Aquí es donde podemos complicarnos un poco con la función add_settings_section. Si observas la documentación de esa función, verás que en la parte de Notas de la página a la función de devolución de llamada se le asignará una matriz de argumentos que se correlacionan directamente con los argumentos de nuestro gancho. Si introduces var_dump($arguments), verás que todos los argumentos se pasan a nuestra función. Luego podemos escribir un simple interruptor en nuestra devolución de llamada para cambiar el texto en función de la ID que se le pasa:

public function section_callback( $arguments ) {
    switch( $arguments['id'] ){
        case 'our_first_section':
            echo 'This is the first description here!';
            break;
        case 'our_second_section':
            echo 'This one is number two';
            break;
        case 'our_third_section':
            echo 'Third time is the charm!';
            break;
    }
}

¡Ahora tenemos texto personalizado para cada sección que podemos cambiar en una función!

Texto personalizado debajo de cada sección.

Por supuesto, también puedes especificar devoluciones de llamada únicas para estas secciones, pero este enfoque te permite consolidar tu código en una sola función. Esta idea funciona igual para la configuración de campos. Podemos hacer que todos nuestros campos compartan una devolución de llamada y que genere el tipo de campo correcto en función de los argumentos que pasamos. Agreguemos los campos a nuestro método constructor. Coloca este código justo después de nuestras secciones enganchadas en el constructor:

add_action( 'admin_init', array( $this, 'setup_fields' ) );

Como ya conoces el ejercicio, solo devolveré la llamada para nuestra acción:

public function setup_fields() {
    add_settings_field( 'our_first_field', 'Field Name', array( $this, 'field_callback' ), 'smashing_fields', 'our_first_section' );
}

Los argumentos de esta función son similares a los de la función de secciones. El primer argumento es el identificador único del campo. La segunda es la etiqueta que aparece junto al campo. En el tercer argumento puedes ver que estoy llamando al método field_callback; crearemos esa devolución de llamada en solo un segundo. La cuarta es la página de opciones que queremos usar (la nuestra $slug de antes). El quinto argumento es el identificador único de la sección a la que queremos asignar este campo. Aquí está el código para la devolución de llamada en nuestro tercer argumento:

public function field_callback( $arguments ) {
    echo '<input name="our_first_field" id="our_first_field" type="text" value="' . get_option( 'our_first_field' ) . '" />';
}

Aquí simplemente estoy copiando el identificador único del campo en el nombre, ID y nuestra función get_option. Veamos cómo se ve nuestra página con nuestro nuevo campo adjunto:

La página de configuración con nuestro primer campo adjunto.

¡Impresionante, tenemos nuestro campo en la página! Intenta agregar algo de contenido y presiona guardar cambios, esperaré aquí… ¿Lo has hecho? Si has hecho todo correctamente hasta este punto, deberías haber recibido un error al decir algo como ERROR: options page not found, o similar. La razón por la que esto sucede es en realidad una característica de seguridad en WordPress. Verás, sin esta función, un usuario podría ingresar al HTML y cambiar el nombre de un campo a lo que quisiera, presionar guardar, e ingresaría esa opción en la base de datos con el nombre que se le dio (asumiendo que era un valor válido nombre de la opción). Esto podría permitir a cualquier usuario cambiar opciones en otras páginas (incluso aquellas a las que normalmente no podrían acceder) simplemente ingresando el nombre correcto en el campo y presionando guardar, no es genial. Este problema se resuelve agregando una función llamada register_setting. A menos que le diga específicamente a WordPress, «Oye, este campo puede guardarse en esta página», WordPress no actualizará un campo en la base de datos. Entonces, debajo de nuestro marcado de campo, agregaremos esta nueva función. Así es como se ve la devolución de llamada después de agregar el código:

public function field_callback( $arguments ) {
    echo '<input name="our_first_field" id="our_first_field" type="text" value="' . get_option( 'our_first_field' ) . '" />';
    register_setting( 'smashing_fields', 'our_first_field' );
}

El primer argumento de la nueva función es la página de opciones en la que queremos guardar el campo (el $slug de antes) y el segundo argumento es el campo que queremos guardar. Ahora intenta actualizar el campo: ¡funcionó! ¡Felicidades! Acabas de guardar tu primer campo usando la API de configuración de WordPress. Ahora, ¿qué pasa si queremos tener algunos tipos de campos diferentes en lugar de solo texto? Revisemos nuestra devolución de llamada de campo y hablemos de esa variable $arguments que se pasa a nuestra función.

Argumentos de campo  #

Si entramos en nuestro campo de devolución de llamada var_dump($arguments), obtendremos una matriz vacía. ¿Por qué? En nuestra devolución de llamada de la sección, obtuvimos un montón de cosas sobre la sección. Bueno, aquí está sucediendo algo diferente. Si se echa un vistazo a la documentación de add_settings_field que hay un quinto argumento de que se puede pasar a la función. Esa variable se correlaciona directamente con la variable $arguments en nuestra devolución de llamada. Así que vamos a querer poner nuestro material nuevo ahí. Si miramos uno de los campos predeterminados en una página de configuración de WordPress, podemos ver que hay varias áreas que podemos agregar a nuestro campo para obtener un formato predeterminado. Aquí hay una captura de pantalla del campo de zona horaria en la página de configuración general:

El campo de zona horaria de WordPress. (Ver versión grande)

Usando este campo como punto de partida, repasemos los datos que queremos pasar a nuestra devolución de llamada de campo.

  • El identificador único
  • La etiqueta del campo (zona horaria en el ejemplo)
  • En que sección debería entrar
  • El tipo de campo (texto, área de texto, seleccionar, etc.)
  • En el caso de que haya varias opciones, las queremos
  • Tal vez un marcador de posición si el tipo de campo admite uno
  • Texto auxiliar (a la derecha del campo en el ejemplo)
  • Texto complementario (debajo del campo en el ejemplo)
  • Quizás una selección predeterminada si hay una

Desde esta lista podemos configurar una matriz asociativa de campos y valores que podemos pasar a nuestra devolución de llamada:

public function setup_fields() {
    $fields = array(
        array(
            'uid' => 'our_first_field',
            'label' => 'Awesome Date',
            'section' => 'our_first_section',
            'type' => 'text',
            'options' => false,
            'placeholder' => 'DD/MM/YYYY',
            'helper' => 'Does this help?',
            'supplemental' => 'I am underneath!',
            'default' => '01/01/2015'
        )
    );
    foreach( $fields as $field ){
        add_settings_field( $field['uid'], $field['label'], array( $this, 'field_callback' ), 'smashing_fields', $field['section'], $field );
        register_setting( 'smashing_fields', $field['uid'] );
    }
}

Entonces, lo primero que tenemos aquí es una variable llamada $fields que contendrá todos los campos que queremos crear. Dentro de esa matriz tenemos otra matriz que contiene los datos específicos para cada campo. He configurado los datos para que coincidan exactamente con nuestra lista anterior. Luego, recorro cada campo (agregaremos más en breve) en la matriz y agrego el campo y lo registro. Al final de la función add_settings_field, también estoy agregando toda la matriz de datos para ese campo específico para que podamos hacer algunas cosas en la función de devolución de llamada. Echemos un vistazo a esa función de devolución de llamada aquí:

public function field_callback( $arguments ) {
    $value = get_option( $arguments['uid'] ); // Get the current value, if there is one
    if( ! $value ) { // If no value exists
        $value = $arguments['default']; // Set to our default
    }

    // Check which type of field we want
    switch( $arguments['type'] ){
        case 'text': // If it is a text field
            printf( '<input name="%1$s" id="%1$s" type="%2$s" placeholder="%3$s" value="%4$s" />', $arguments['uid'], $arguments['type'], $arguments['placeholder'], $value );
            break;
    }

    // If there is help text
    if( $helper = $arguments['helper'] ){
        printf( '<span class="helper"> %s</span>', $helper ); // Show it
    }

    // If there is supplemental text
    if( $supplimental = $arguments['supplemental'] ){
        printf( '<p class="description">%s</p>', $supplimental ); // Show it
    }
}

En el ejemplo anterior, estamos haciendo varias cosas. Establecemos los valores predeterminados para los campos si están vacíos y agregamos el texto auxiliar y complementario. Sin embargo, la parte más importante de nuestro código es la declaración de cambio. En esta declaración vamos a delinear cómo se manejarán nuestros argumentos en función del tipo de campo que queramos. Por ejemplo, si tenemos un campo de texto, no necesitamos tener múltiples opciones. Sin embargo, un menú desplegable <select> debe tener opciones para funcionar correctamente. Dado que ya tenemos los tipos de texto configurados, ejecutemos este código y veamos qué obtenemos.

Nuestro campo se completó con texto de marcador de posición. (Ver versión grande)

Cuando cargues la página de configuración de tu complemento, deberías ver el campo superior en esta imagen. La parte inferior es lo que verás si elimina el contenido del campo (es decir, el marcador de posición). Si eliminaras los argumentos helper o supplimental de nuestra matriz de campos, deberían desaparecer en la página de configuración. También podemos cambiar el argumento section y movernos por la ubicación del campo en las secciones. OK, entonces tenemos campos de texto; ¿Qué tal algunos tipos de campos más complejos? Echemos otro vistazo a nuestra declaración de cambio y agreguemos la opción para áreas de texto y selecciones simples:

switch( $arguments['type'] ){
    case 'text': // If it is a text field
        printf( '<input name="%1$s" id="%1$s" type="%2$s" placeholder="%3$s" value="%4$s" />', $arguments['uid'], $arguments['type'], $arguments['placeholder'], $value );
        break;
    case 'textarea': // If it is a textarea
        printf( '<textarea name="%1$s" id="%1$s" placeholder="%2$s" rows="5" cols="50">%3$s</textarea>', $arguments['uid'], $arguments['placeholder'], $value );
        break;
    case 'select': // If it is a select dropdown
        if( ! empty ( $arguments['options'] ) && is_array( $arguments['options'] ) ){
            $options_markup = ’;
            foreach( $arguments['options'] as $key => $label ){
                $options_markup .= sprintf( '<option value="%s" %s>%s</option>', $key, selected( $value, $key, false ), $label );
            }
            printf( '<select name="%1$s" id="%1$s">%2$s</select>', $arguments['uid'], $options_markup );
        }
        break;
}

En el código anterior, notarás varias diferencias entre cada uno de los tipos de campo. Aunque las áreas de texto son funcionalmente similares a los campos de texto normales, requieren un marcado diferente. Los menús desplegables seleccionados son un animal completamente diferente debido a las opciones. Necesitamos recorrer las opciones y establecer valores, estados seleccionados y etiquetas. Entonces, nuestro marcado es drásticamente diferente. Ahora que hemos actualizado nuestra función de devolución de llamada, veamos cómo han cambiado los datos del campo:

$fields = array(
    array(
        'uid' => 'our_first_field',
        'label' => 'Awesome Date',
        'section' => 'our_first_section',
        'type' => 'text',
        'options' => false,
        'placeholder' => 'DD/MM/YYYY',
        'helper' => 'Does this help?',
        'supplemental' => 'I am underneath!',
        'default' => '01/01/2015'
    ),
    array(
        'uid' => 'our_second_field',
        'label' => 'Awesome Date',
        'section' => 'our_first_section',
        'type' => 'textarea',
        'options' => false,
        'placeholder' => 'DD/MM/YYYY',
        'helper' => 'Does this help?',
        'supplemental' => 'I am underneath!',
        'default' => '01/01/2015'
    ),
    array(
        'uid' => 'our_third_field',
        'label' => 'Awesome Select',
        'section' => 'our_first_section',
        'type' => 'select',
        'options' => array(
            'yes' => 'Yeppers',
            'no' => 'No way dude!',
            'maybe' => 'Meh, whatever.'
        ),
        'placeholder' => 'Text goes here',
        'helper' => 'Does this help?',
        'supplemental' => 'I am underneath!',
        'default' => 'maybe'
    )
);

Aquí hay tres campos, cada uno con un tipo de campo diferente en nuestro complemento. El primero que ya hemos repasado. El segundo es nuestro nuevo campo textarea. Podemos pasar los mismos parámetros con la matriz (con la excepción del UID), pero un simple cambio a nuestro tipo y obtendremos un textarea. El último campo de esta matriz es el menú desplegable de selección. La actualización principal aquí es la adición de la matriz de opciones. Agregamos una matriz asociativa simple con la clave de la matriz como el valor de la opción HTML y la etiqueta. Usando esta matriz, así es como se ven nuestros campos:

Nuestra página de configuración con campos. (Ver versión grande)

¡Casi termino! #

Ahora tenemos una página de configuración de complementos en funcionamiento. Hemos configurado las secciones de la página, las opciones, todas las devoluciones de llamada y los campos registrados. Lo único que queda es obtener nuestros valores de configuración en otra parte. Lo creas o no, ya lo hemos hecho. En la parte superior de nuestro campo de devolución de llamada, puedes ver que estamos verificando el valor de la base de datos:

$value = get_option( $arguments['uid'] );

Podemos usar el mismo código en nuestro complemento (o tema) y simplemente pasarlo a la función uid. Entonces, si quisieras obtener el valor de our_first_field, simplemente debes escribir:

get_option('our_first_field')

¡Listo! ¡Tenemos nuestro increíble complemento y nuestra increíble configuración! Obviamente, solo hemos configurado algunos tipos de campos, pero he revisado y agregado más en el repositorio de código para este enfoque (específicamente campos de texto, contraseñas, números, áreas de texto, menús desplegables de selección, selecciones múltiples, botones de radio y casillas de verificación).

Enfoque 2: Configuración de un formulario personalizado y un número de controlador 

En el pasado, este enfoque era la única forma de agregar páginas de configuración. Antes de WordPress 2.7, los autores de complementos tenían que crear sus propios formularios y controladores personalizados. Obviamente, esto condujo a muchos errores e inconsistencias entre los complementos. Si bien este enfoque está algo desaprobado, sigue siendo una opción viable en algunos casos.

Pros  #

  • Puedes enviar el formulario a controladores personalizados y remotos
  • Puedes omitir algunas de las restricciones integradas de la API de configuración

Contras  #

  • La compatibilidad debe ser mantenida por el desarrollador.
  • Debes desinfectar y validar manualmente

¿Cuándo deberías utilizar este enfoque? #

Utiliza este enfoque cuando sea absolutamente necesario tener un controlador personalizado o una interfaz muy personalizada. Probablemente puedas salirte con la tuya con el Método 1 en la mayoría de los casos, pero tienes más flexibilidad con la validación y el manejo con este método.

Empezando  #

Antes de entrar en detalles, debemos idear un escenario en el que usemos un controlador personalizado. En aras de la simplicidad, vamos a crear un formulario que verificará un nombre de usuario y una dirección de correo electrónico. Podríamos tirar de los datos de una base de datos o incluso un servidor remoto. En este caso, configuraré una matriz con nombres de usuario y direcciones de correo electrónico válidos para que podamos verificarlos. Luego almacenaremos los valores de campo que ingrese el usuario y los almacenaremos en la base de datos.

Creando el Formulario  #

Como mencioné antes, seguiremos los mismos pasos que hicimos en “Creación de nuestra página de complementos y configuraciones”. Para este enfoque, configuraremos nuestros campos usando marcado HTML estático. Agregaremos este código a la devolución de llamada desde la función plugin_settings_page_content de esta manera:

public function plugin_settings_page_content() {
    ?>
    <div class="wrap">
        <h2>My Awesome Settings Page</h2>
        <form method="POST">
            <table class="form-table">
                <tbody>
                    <tr>
                        <th><label for="username">Username</label></th>
                        <td><input name="username" id="username" type="text" value="" class="regular-text" /></td>
                    </tr>
                    <tr>
                        <th><label for="email">Email Address</label></th>
                        <td><input name="email" id="email" type="text" value="" class="regular-text" /></td>
                    </tr>
                </tbody>
            </table>
            <p class="submit">
                <input type="submit" name="submit" id="submit" class="button button-primary" value="Check My Info!">
            </p>
        </form>
    </div> <?php
}

Puedes ver arriba que solo estamos agregando algo de HTML estático para nuestros campos. Estamos duplicando el marcado de las páginas principales de configuración de WordPress. También estamos omitiendo la acción del formulario para que envíe el formulario a la página actual en lugar del controlador options.php predeterminado. Antes de escribir nuestro controlador personalizado, pongamos algunas funciones de seguridad rápidas. Lo primero que debemos hacer es poner un nonce en nuestro formulario. Nonces protegerá contra los intentos de falsificación de solicitudes entre sitios, que es similar a la suplantación de usuarios o los ataques de reproducción. Pongamos el nonce en nuestro HTML:

<form method="POST">
    <?php wp_nonce_field( 'awesome_update', 'awesome_form' ); ?>
    <table class="form-table">

El wp_nonce_field agregará un par de campos ocultos a nuestro formulario; el nonce y el referente. Regresaremos al nonce cuando revisemos el código del controlador. A continuación, debemos agregar un campo para detectar cuándo se ha actualizado el formulario. Podemos hacer esto simplemente agregando un campo oculto en la parte superior de nuestro formulario:

<form method="POST">
    <input type="hidden" name="updated" value="true" />
    <?php wp_nonce_field( 'awesome_update', 'awesome_form' ); ?>
    <table class="form-table">

Ahora podemos poner un fragmento de código en la parte superior de nuestra página para detectar cuándo se envía nuestro formulario y enviarnos a nuestro controlador personalizado:

public function plugin_settings_page_content() {
    if( $_POST['updated'] === 'true' ){
        $this->handle_form();
    } ?>
    <div class="wrap">
        <h2>My Awesome Settings Page</h2>

Aquí simplemente estamos verificando si el campo updated oculto se ha enviado y, si lo ha hecho, llamamos a un método en nuestro complemento llamado handle_form. Aquí es donde podemos comenzar a escribir nuestro controlador personalizado.

Creando el manejador  #

Hay un par de cosas que debemos verificar en el controlador antes de administrar los datos del formulario. Primero debemos verificar si nuestro nonce existe y es válido:

public function handle_form() {
    if(
        ! isset( $_POST['awesome_form'] ) ||
        ! wp_verify_nonce( $_POST['awesome_form'], 'awesome_update' )
    ){ ?>
        <div class="error">
           <p>Sorry, your nonce was not correct. Please try again.</p>
        </div> <?php
        exit;
    } else {
        // Handle our form data
    }
}

El código anterior verifica que el nonce sea correcto. Si no es válido, le damos al usuario un mensaje sobre por qué no se actualizó el formulario. Si el nonce existe y es correcto, podemos manejar nuestro formulario. Escribamos ahora el código para nuestro controlador de formularios (este código reemplazará el comentario en el fragmento de arriba):

$valid_usernames = array( 'admin', 'matthew' );
$valid_emails = array( 'email@domain.com', 'anotheremail@domain.com' );

$username = sanitize_text_field( $_POST['username'] );
$email = sanitize_email( $_POST['email'] );

if( in_array( $username, $valid_usernames ) && in_array( $email, $valid_emails ) ){
    update_option( 'awesome_username', $username );
    update_option( 'awesome_email', $email );?>
    <div class="updated">
        <p>Your fields were saved!</p>
    </div> <?php
} else { ?>
    <div class="error">
        <p>Your username or email were invalid.</p>
    </div> <?php
}

Repasemos el código en esta sección. Las primeras líneas son las matrices de nombres de usuario/correos electrónicos válidos con los que comprobaremos. Estos valores de matriz se pueden completar desde cualquier lugar. Las siguientes dos líneas son los valores que nuestro usuario ha ingresado en el formulario. Estamos utilizando las funciones de desinfección integradas que nos brinda WordPress. Este paso es importante para evitar varias vulnerabilidades con formularios web. A continuación, comprobamos si los valores proporcionados por los usuarios están en nuestra matriz de valores aceptables. Si es así, actualiza las opciones de formulario en la base de datos. Este paso también podría reemplazarse con un mecanismo de almacenamiento personalizado. También le estamos dando al usuario un mensaje de que sus campos fueron guardados. Si la entrada del usuario no es válida, se lo decimos. Lo último que debemos hacer es mostrar los campos almacenados en el formulario después de haberlos ingresado. Lo haremos de la misma manera que recuperaríamos estos campos en otra parte del complemento: con la función get_option. Estos son los campos después de agregar el código correcto:

<tr>
    <th><label for="username">Username</label></th>
    <td><input name="username" id="username" type="text" value="<?php echo get_option('awesome_username'); ?>" class="regular-text" /></td>
</tr>
<tr>
    <th><label for="email">Email Address</label></th>
    <td><input name="email" id="email" type="text" value="<?php echo get_option('awesome_email'); ?>" class="regular-text" /></td>
</tr>

Ahora estamos listos para probar nuestro formulario. Intenta ingresar el nombre de usuario admin y la dirección de correo electrónico email@domain.com. Deberías obtener lo siguiente en tu formulario:

Los campos guardados después de que ingresemos los valores correctos. (Ver versión grande)

Si intentas configurar cualquiera de los campos con un valor no válido, deberías recibir un mensaje de error y los campos no deberían actualizarse debido a nuestro controlador personalizado. ¡Eso es todo para nuestro segundo enfoque! Ahora has configurado un formulario y un controlador personalizados para administrar los campos de tu complemento. El código completo para este enfoque se puede encontrar en el repositorio de este artículo. Ahora, pasemos a nuestro enfoque final.

Enfoque 3: Integración de ACF (Campos personalizados avanzados) en el complemento  #

Si aún no has utilizado ACF de Elliot Condon, permíteme presentarlo. ACF es un administrador de campo maravilloso para WordPress. Una de las mejores cosas es la interfaz de configuración de campo. Hace que sea bastante fácil activar campos para varias páginas diferentes dentro de WordPress (como publicaciones, páginas, usuarios, taxonomías, incluso tus propias páginas de opciones integradas). Puedes pensar «No puedo integrar el complemento de otra persona en el mío, ¡eso es sospechoso!» pero el Sr. Condon comprende la difícil situación de sus compañeros desarrolladores y lo ha planeado en su complemento. Puede ver su documentación sobre este tema, pero volveré a exponer algo aquí. Repasemos las reglas.

  1. Primero, si distribuyes un complemento gratuito, debes utilizar la versión gratuita de ACF. Esto es para que la gente no pueda obtener la versión PRO de tu complemento gratuito, eso no sería lo ideal. Puedes usar la versión PRO en complementos y temas premium sin problema, solo asegúrate de comprar la licencia de desarrollador.
  2. En segundo lugar, no modifiques la información de derechos de autor de ACF. ¡Dale algo de crédito al hombre!
  3. Por último, no distribuyas la clave de licencia con tu complemento.

Ahora, los pros y los contras de este enfoque:

Pros  #

  • Muy fácil de integrar en temas y complementos
  • Puedes aprovechar los campos avanzados que forman parte de ACF
  • Las actualizaciones de código y seguridad son administradas por el equipo de ACF
  • ACF tiene excelentes complementos y soporte si te quedas atascado
  • Configurar sus campos es muy simple debido a la interfaz de usuario de configuración de campo

Contras  #

  • Acceso limitado al marcado
  • Crea una dependencia para su complemento o tema
  • Para mantener ACF actualizado, debes mantenerlo actualizado en sus archivos de plugin/tema (más información a continuación)

¿Cuándo deberías utilizar este enfoque? #

Cuando desees crear una interfaz de configuración avanzada muy rápidamente y no necesites personalizar la apariencia.

Empezando  #

Para este enfoque, te mostraré cómo configurar la página de opciones para la versión gratuita de ACF. Para ver una guía sobre cómo configurar la versión PRO, consulta la documentación de ACF. Para comenzar, agregaremos ACF a nuestro directorio de complementos. Primero, descarga la última versión de ACF y descomprime su contenido. En tu directorio de complementos, crea un directorio de proveedores y agréga ACF. Tus archivos deberían verse así:

ACF en el directorio de proveedores de complementos. (Ver versión grande)

Nuevamente, seguiremos los pasos que hicimos en “Creación de nuestra página de complementos y configuraciones”. Sin embargo, antes de entrar en eso, deberíamos incluir ACF en nuestro complemento.

Incluye ACF en el complemento  #

En realidad, es bastante fácil incluir ACF en el complemento: solo hay tres pasos. Primero tenemos que incluir el archivo ACF principal con PHP. Agrega el siguiente código al final de nuestra función constructora:

include_once( plugin_dir_path( __FILE__ ) . 'vendor/advanced-custom-fields/acf.php' );

Si actualizas el administrador, deberías ver un nuevo elemento de menú titulado Campos personalizados. Antes de entrar en esa página y comenzar a configurar nuestros campos, necesitamos actualizar un par de rutas en ACF. Necesitamos decirle a ACF que busque sus activos de front-end y archivos incluidos en nuestro directorio de complementos en lugar de su lugar normal. Agrega estos dos ganchos a su constructor:

add_filter( 'acf/settings/path', array( $this, 'update_acf_settings_path' ) );
add_filter( 'acf/settings/dir', array( $this, 'update_acf_settings_dir' ) );

Y las devoluciones de llamada para esos ganchos:

public function update_acf_settings_path( $path ) {
    $path = plugin_dir_path( __FILE__ ) . 'vendor/advanced-custom-fields/';
    return $path;
}

public function update_acf_settings_dir( $dir ) {
    $dir = plugin_dir_url( __FILE__ ) . 'vendor/advanced-custom-fields/';
    return $dir;
}

La primera devolución de llamada actualiza las rutas de inclusión para los archivos PHP dentro del complemento ACF. El segundo actualiza los URI de los activos de ACF. Ahora podemos configurar nuestros campos.

Configurando los campos  #

Ahora viene la parte divertida: la interfaz de usuario de configuración del campo ACF. Agrega un título y cualquier campo que desees en su formulario. Hay un gran tutorial de lo que hace todo en esta página en la documentación de ACF. Así es como configuré el mío:

Mis campos ACF en la interfaz de usuario de configuración. (Ver versión grande)

Una vez que estés listo, presiona el botón Publicar a la derecha y los campos se guardarán. Ahora tenemos que obtener los campos que configuramos en nuestro complemento. Ahora mismo solo existen en la base de datos. En la barra de navegación de la izquierda, haz clic en el elemento Herramientas. En la nueva página, selecciona el grupo de campos que acabamos de crear y presiona Generar código de exportación. Esto creará un fragmento de código PHP que ahora podemos incluir en nuestro complemento. Para agregar las opciones, necesitamos agregar una llamada al método a nuestro constructor. Agrega esta línea al final de tu constructor después de que nuestro ACF incluya:

$this->setup_options();

Luego podemos crear el método que envolverá nuestras opciones:

public function setup_options() {
    if( function_exists( 'register_field_group' ) ) {
        register_field_group(array (
            'id' => 'acf_awesome-options',
            'title' => 'Awesome Options',
            'fields' => array (
                array (
                    'key' => 'field_562dc35316a0f',
                    'label' => 'Awesome Name',
                    'name' => 'awesome_name',
                    'type' => 'text',
                    'default_value' => ’,
                    'placeholder' => ’,
                    'prepend' => ’,
                    'append' => ’,
                    'formatting' => 'html',
                    'maxlength' => ’,
                ),
                array (
                    'key' => 'field_562dc9affedd6',
                    'label' => 'Awesome Date',
                    'name' => 'awesome_date',
                    'type' => 'date_picker',
                    'date_format' => 'yymmdd',
                    'display_format' => 'dd/mm/yy',
                    'first_day' => 1,
                ),
                array (
                    'key' => 'field_562dc9bffedd7',
                    'label' => 'Awesome WYSIWYG',
                    'name' => 'awesome_wysiwyg',
                    'type' => 'wysiwyg',
                    'default_value' => ’,
                    'toolbar' => 'full',
                    'media_upload' => 'yes',
                ),
            ),
            'location' => array (
                array (
                    array (
                        'param' => 'options_page',
                        'operator' => '==',
                        'value' => 'smashing_fields',
                    ),
                ),
            ),
            'menu_order' => 0,
            'position' => 'normal',
            'style' => 'default',
            'label_placement' => 'top',
            'instruction_placement' => 'label',
            'hide_on_screen' => ’,
            'active' => 1,
            'description' => ’,
        ));
    }
}

Ahora que tenemos nuestros campos listos para usar, podemos agregarlos a la página de configuración.

Modificación del código de la página de configuración  #

Para agregar los campos que acabamos de crear a la página, necesitaremos actualizar nuestro método plugin_settings_page_content. Previamente, configuramos la etiqueta de formulario para nuestra página. En este caso, dejaremos que ACF haga esa parte por nosotros. Así es como debería verse nuestra función actualizada:

public function plugin_settings_page_content() {
    do_action('acf/input/admin_head'); // Add ACF admin head hooks
    do_action('acf/input/admin_enqueue_scripts'); // Add ACF scripts

    $options = array(
        'id' => 'acf-form',
        'post_id' => 'options',
        'new_post' => false,
        'field_groups' => array( 'acf_awesome-options' ),
        'return' => admin_url('admin.php?page=smashing_fields'),
        'submit_value' => 'Update',
    );
    acf_form( $options );
}

Las dos primeras líneas de nuestra función están agregando los scripts y estilos que necesitaremos para los campos de configuración. Después de eso, estamos configurando las opciones para nuestro formulario. Puedes notar que el valor en el argumento field_groups coincide con el ID de nuestra función register_field_group. Para ver los otros parámetros de configuración, consulte la documentación acf_form. La última línea de nuestra función va a representar el formulario. Si intentas cargar la página de configuración ahora, es posible que veas que la página está realmente rota. Esto se debe a que ACF necesita localizar algunas variables para JavaScript. Para hacer esto, necesitamos agregar otro gancho a nuestro constructor:

add_action( 'admin_init', array( $this, 'add_acf_variables' ) );

Ahora necesitamos configurar la devolución de llamada:

public function add_acf_variables() {
    acf_form_head();
}

Puedes intentar agregar algo de contenido y guardar, y debería funcionar como nuestros otros dos enfoques. Así es como debería verse nuestra página:

Nuestro formulario ACF completo. (Ver versión grande)

Solo hay un par de elementos de limpieza que necesitamos abordar:

  • Es posible que desees ocultar el hecho de que está utilizando ACF para tu complemento. Si éste es el caso, debes ocultar el elemento del menú Campos personalizados. Puedes hacer esto agregando este fragmento a tu función de constructor:
    add_filter('acf/settings/show_admin', '__return_false'); 
  • Deberíamos eliminar la versión de la base de datos de nuestro grupo de campo. Simplemente ve a la sección de campos personalizados y presiona el botón de la papelera. Este paso es opcional ya que solo afectará el entorno en el que creaste el complemento, pero podría presentar problemas si estás probando el complemento en el mismo entorno.

Uso de campos ACF dentro de tu complemento  #

Para obtener los campos ACF que creaste, simplemente necesitas usar la función get_field ACF predeterminada. La primera opción debe ser el ID único para el campo y el segundo argumento establecido en ‘option’. Así es como obtendríamos el campo Fecha impresionante:

get_field( 'awesome_date', 'option' )

Y eso es. ¡Ahora ha sconfigurado un complemento con la configuración de ACF! Puedes ver el código para este enfoque en el repositorio.

Conclusión  #

Así que ahí lo tienes: tres formas de hacer que tus complementos sean configurables. Me encantaría conocer los complementos que puedes crear con estos métodos. En cuanto a mis preferencias personales para estos enfoques, tiendo a inclinarme hacia el Método 1. Prefiero mantener la menor cantidad posible de dependencias en mis complementos y puedes personalizar el marcado para cambiar el tema de la página de configuración para proyectos personalizados. Para prototipos rápidos o proyectos en los que necesito configurar campos muy avanzados, usaré ACF, pero agrega un nivel de complejidad a la administración de actualizaciones de complementos. También cabe mencionar la propuesta de una API Fields de Scott Clark. Si bien actualmente todavía es un trabajo en progreso, la API esencialmente permitiría a los desarrolladores de complementos y temas la capacidad de usar la misma interfaz que la API del personalizador para crear campos de configuración en otras áreas del panel de administración.

Alternativas ACF  #

Como se señala en los comentarios a continuación, y para brindar a los desarrolladores otras opciones que sean similares al enfoque de ACF, puedes consultar algunas alternativas que pueden ofrecer diferentes características. Si tienes más, envíalos en los comentarios a continuación. Aquí están sin ningún orden en particular:

  • CMB2 por WebDevStudios
  • Meta Box de Tran Ngoc Tuan Anh (Rilwis)

¿Qué opinas?

Escrito por Wombat

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

Cómo reparar el error «429 Too Many Requests (demasiadas solicitudes)» en WordPress

Revisión de MemberMouse: ¿Es el mejor complemento de membresía de WordPress?