3 enfoques para agregar campos configurables a su complemento de WordPress
Publicado: 2022-03-10Cualquiera 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á, 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 puede hacer que su complemento sea configurable. Comenzaremos creando una página de configuración y crearemos nuestros campos utilizando la API de configuración predeterminada de WordPress.
Lectura adicional en SmashingMag:
- Extienda WordPress con campos personalizados
- Hacks de campos personalizados para WordPress
- Ampliación de campos personalizados avanzados con sus propios controles
- La guía completa de tipos de publicaciones personalizadas
Luego lo guiaré a través de cómo configurar sus campos con un controlador personalizado. Finalmente, le mostraré cómo integrar un excelente complemento de campos configurables Campos personalizados avanzados (ACF) en su propio complemento.
Dado que esta es una publicación larga, aquí hay una tabla de contenido con enlaces a cada una de las secciones principales:
- Crear nuestra página de complementos y configuraciones
- Enfoque 1: Uso de la funcionalidad incorporada de WordPress
- Enfoque 2: Configuración de un formulario y un controlador personalizados
- Enfoque 3: Integración de ACF (Campos personalizados avanzados) en su complemento
Para ver ejemplos de código, consulte el repositorio que he configurado para acompañar esta publicación.
Creando nuestra página de complementos y configuraciones
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. La estructura de este complemento está orientada a objetos, por lo que puede haber algunas diferencias en su propio código si su complemento está escrito de manera procesal. Preste 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 enlace 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' ) ); }
Puede ver que la devolución de llamada de nuestra acción es create_plugin_settings_page
, así que vamos a crear ese método. Nota: he configurado los argumentos como variables separadas con nombre para dar algo de contexto a nuestro código, pero simplemente puede 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 ); }
Eche un vistazo al códice de WP para add_menu_page
para obtener más información.
Esta función creará nuestra página, así como el elemento del menú. Las partes importantes aquí son los argumentos de slug, capacidad y devolución de llamada. El slug que usaremos más tarde para registrar nuestros campos, así que anótelo en alguna parte. Puede cambiar la capacidad para permitir que diferentes niveles de usuario accedan a su página de configuración. En cuanto a la devolución de llamada, crearemos ese método en breve. Tenga en cuenta que también puede poner una clase dashicon directamente en la función para cambiar el icono del menú. El último argumento es la posición del elemento del menú dentro del menú; juegue con este número para encontrar el lugar en el menú en el que desea que caigan sus configuraciones. Nota: puede usar 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 guarda su complemento y actualiza el panel de administración de WordPress, debería ver lo siguiente:

Puede ver que su página de configuración es un elemento de menú de nivel superior. Es posible que prefiera dejarlo así según las necesidades de su página de configuración. Sin embargo, es posible que también desee tener la configuración de su complemento en otro elemento del menú. En este caso, simplemente cambiará 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
a add_submenu_page
y agregando 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
puede ver una lista bastante buena de los elementos del menú principal y sus slugs. También puede ver que ya no tenemos los dos últimos argumentos, $icon
y $position
. Como 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, por lo que no es necesario ese argumento.
Si guarda este nuevo código, verá que nuestra página de configuración se mostrará en el elemento del menú Configuración:

En muchos casos, el lugar más apropiado para agregar una página de configuración del complemento es debajo del elemento Configuración. En el códice de WordPress se explica que la sección Configuración se usa para "Mostrar opciones de complementos que solo los administradores deberían ver". Sin embargo, esto es solo una guía, no una regla.
Ahora que tenemos configurada nuestra página de configuración y sabemos cómo mover los elementos, podemos comenzar a trabajar en los campos. El trabajo que hemos hecho 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.
ventajas
- Fácil de integrar en las páginas de configuración existentes
- La sanitización está hecha para ti
- 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 campos avanzados (repetidores, mapas, cargas, etc.) son más difíciles de implementar
¿Cuándo debería usar este enfoque?
Este enfoque es lo suficientemente flexible como para que se pueda personalizar para páginas de configuración muy simples o muy avanzadas. Puede usar este método en la mayoría de las situaciones si no le importa hacer algunas cosas manualmente.
Empezando
Con este enfoque, necesitaremos seguir el mismo marcado que usan las propias 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 códice de WordPress en 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 div
contenedor es en realidad lo mismo que un formulario predeterminado de WordPress y extraerá los estilos de esas secciones. La etiqueta del 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 puso 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 de 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ónsubmit_button
; se describen en el códice.
Si actualizamos nuestra página de configuración, deberíamos obtener algo parecido a esto:

¡Se ve un poco escaso! Empecemos 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 a ella. 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; puede convertirlo en lo que desee. El tercer argumento es la devolución de llamada. En este momento lo tengo configurado en false
, pero lo revisaremos en breve. El cuarto argumento es la página de opciones a la que se agregarán las opciones (la variable $slug
de antes).
Entonces, ¿por qué hay un false
en nuestra devolución de llamada? Bueno, algo que no está muy claro al configurar las opciones de WordPress usando su documentación es que varias secciones pueden compartir una devolución de llamada. A menudo, cuando configura una devolución de llamada, existe una relación de 1 por 1 entre el gancho y la devolución de llamada. Entonces, solo como 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
establecida 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:

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ías. Aquí es donde podemos complicarnos un poco con la función add_settings_section
. Si observa la documentación de esa función, verá que en la parte de Notas de la página, a la función de devolución de llamada se le asignará una serie de argumentos que se correlacionan directamente con los argumentos en nuestro enlace. Si ingresa y var_dump( $arguments )
, verá que todos los argumentos pasan a nuestra función.
Luego, podemos escribir un cambio simple 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 sola función!

Por supuesto, también puede especificar devoluciones de llamada únicas para estas secciones, pero este enfoque le permite consolidar su código en una sola función. Esta idea funciona igual para configurar campos. Podemos hacer que todos nuestros campos compartan una devolución de llamada y hacer que emita el tipo de campo correcto en función de los argumentos que le pasamos. Agreguemos los campos a nuestro método constructor. Coloque este código justo después de que nuestras secciones se enganchen en el constructor:
add_action( 'admin_init', array( $this, 'setup_fields' ) );
Como ya conoce el simulacro, solo le 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 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 (nuestra $slug
anterior). 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" 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:

Impresionante, tenemos nuestro campo en la página! Intente agregarle algo de contenido y presione Guardar cambios, esperaré aquí ...
¿Lo has hecho? Si ha hecho todo bien hasta este punto, debería haber recibido un error que dice algo como ERROR: options page not found
, o similar. La razón por la que esto sucede es en realidad una función de seguridad en WordPress.
Verá, 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 cualquier nombre que se le haya dado (suponiendo que fuera un campo válido). nombre de la opción). Esto podría permitir a cualquier usuario cambiar las opciones en otras páginas (incluso aquellas a las que normalmente no pueden 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" type="text" value="' . get_option( 'our_first_field' ) . '" />'; register_setting( 'smashing_fields', 'our_first_field' ); }
El primer argumento en 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 intente actualizar el campo: ¡funcionó!
¡Felicidades! Acaba de guardar su primer campo usando la API de configuración de WordPress. Ahora, ¿qué sucede si queremos tener algunos tipos de campos diferentes en lugar de solo texto? Revisemos nuestra devolución de llamada de campo y hablemos sobre la variable $arguments
que se pasa a nuestra función.
Argumentos de campo
Si entramos en nuestra devolución de llamada de campo y var_dump( $arguments )
, obtendremos una matriz vacía. ¿Lo que da? En nuestra devolución de llamada de sección, obtuvimos un montón de cosas sobre la sección. Bueno, hay algo diferente pasando aquí. Si consulta la documentación de add_settings_field
, hay un quinto argumento 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 nuestras cosas nuevas allí.
Si observamos 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:

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 qué sección debe ir
- El tipo de campo (texto, área de texto, selección, etc.)
- En el caso de que haya múltiples opciones, querremos esas
- 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)
- Tal vez 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 de 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, 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" 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. Estamos configurando los valores predeterminados para los campos si están vacíos y agregando el ayudante y el texto complementario. Sin embargo, la parte más importante de nuestro código es la sentencia switch. En esta declaración, vamos a describir cómo se manejarán nuestros argumentos en función del tipo de campo que queremos.
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. Como ya tenemos tipos de texto configurados, ejecutemos este código y veamos qué obtenemos.

Cuando cargue la página de configuración de su complemento, debería ver el campo superior en esta imagen. La parte inferior es lo que verá si elimina el contenido del campo (es decir, el marcador de posición). Si tuviera que eliminar el helper
o los argumentos supplimental
de nuestra matriz de campos, deberían desaparecer en la página de configuración. También podemos cambiar el argumento de la section
y movernos por la ubicación del campo en las secciones.

Bien, 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 individuales:
switch( $arguments['type'] ){ case 'text': // If it is a text field printf( '<input name="%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" 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">%2$s</select>', $arguments['uid'], $options_markup ); } break; }
En el código anterior, notará 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. Así que 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 ya lo 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 en nuestro tipo y obtendremos un área de textarea
en su lugar. 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:

¡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 registrado los campos. Lo único que queda es obtener nuestros valores de configuración en otro lugar. Lo creas o no, ya lo hemos hecho. En la parte superior de nuestra devolución de llamada de campo, puede 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 pasar el uid
a la función. Entonces, si quisiera obtener el valor de our_first_field
, simplemente escribiría:
get_option('our_first_field')
¡Listo! ¡Tenemos nuestro increíble complemento y nuestra increíble configuración! Obviamente, solo hemos configurado algunos tipos de campo, 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: configurar un formulario y un controlador personalizados
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 generó muchos errores e inconsistencias entre los complementos. Si bien este enfoque está algo obsoleto, sigue siendo una opción viable en algunos casos.
ventajas
- Puede enviar el formulario a controladores personalizados y remotos
- Puede omitir algunas de las restricciones integradas de la API de configuración
Contras
- El desarrollador debe mantener la compatibilidad.
- Debe higienizarse y validarse manualmente
¿Cuándo debería usar este enfoque?
Utilice este enfoque cuando sea absolutamente necesario tener un controlador personalizado o una interfaz altamente personalizada. Probablemente pueda salirse con la suya con el Enfoque 1 en la mayoría de los casos, pero tiene más flexibilidad con la validación y el manejo utilizando este método.
Empezando
Antes de entrar en detalles, debemos idear un escenario en el que usaríamos un controlador personalizado. Para simplificar, hagamos un formulario que verifique un nombre de usuario y una dirección de correo electrónico. Podríamos extraer los datos de una base de datos o incluso de un servidor remoto. En este caso, configuraré una matriz con nombres de usuario y direcciones de correo electrónico válidos para que los verifiquemos. Luego almacenaremos los valores de campo que el usuario ingresó y los almacenaremos en la base de datos.
Crear 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" type="text" value="" class="regular-text" /></td> </tr> <tr> <th><label for="email">Email Address</label></th> <td><input name="email" type="text" value="" class="regular-text" /></td> </tr> </tbody> </table> <p class="submit"> <input type="submit" name="submit" class="button button-primary" value="Check My Info!"> </p> </form> </div> <?php }
Puede 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 predeterminado options.php .
Antes de escribir nuestro controlador personalizado, agreguemos 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 identidad del usuario 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. Volveremos 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 verificamos si el campo updated
oculto se ha enviado y, si es así, llamamos a un método en nuestro complemento llamado handle_form
. Aquí es donde podemos comenzar a escribir nuestro controlador personalizado.
Creando el controlador
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 el código para nuestro controlador de formulario ahora (este código reemplazará el comentario en el fragmento anterior):
$valid_usernames = array( 'admin', 'matthew' ); $valid_emails = array( '[email protected]', '[email protected]' ); $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. El primer par de 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 los formularios web. A continuación, verificamos si los valores proporcionados por los usuarios están en nuestra matriz de valores aceptables. Si es así, actualice las opciones del 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 informamos.
Lo último que debemos hacer es mostrar los campos almacenados en el formulario después de que se hayan ingresado. Lo haremos de la misma manera que recuperaríamos estos campos en cualquier otra parte del complemento: con la función get_option
. Aquí están los campos después de agregar el código correcto:
<tr> <th><label for="username">Username</label></th> <td><input name="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" type="text" value="<?php echo get_option('awesome_email'); ?>" class="regular-text" /></td> </tr>
Ahora estamos listos para probar nuestro formulario. Intente ingresar el nombre de usuario admin y la dirección de correo electrónico [email protected] . Debe obtener lo siguiente en su formulario:

Si intenta establecer cualquiera de los campos en un valor no válido, debería 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 ha configurado un formulario personalizado y un controlador para administrar los campos de su 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 su complemento
Si aún no has usado ACF de Elliot Condon, déjame presentarte. ACF es un administrador de campo maravilloso para WordPress. Una de las mejores cosas que tiene 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 sus propias páginas de opciones integradas). Puede pensar "No puedo integrar el complemento de otra persona en el mío, ¡eso es turbio!" pero el Sr. Condon comprende la difícil situación de sus compañeros desarrolladores y ha planeado esto en su complemento. Puede ver su documentación sobre este tema, pero repetiré parte de ella aquí. Repasemos las reglas.
- Primero, si está distribuyendo un complemento gratuito, debe usar la versión gratuita de ACF. Esto es para que las personas no puedan obtener la versión PRO de su complemento gratuito; eso no sería genial. Puede usar la versión PRO en complementos y temas premium sin problema, solo asegúrese de comprar la licencia de desarrollador.
- En segundo lugar, no modifique la información de derechos de autor de ACF. ¡Dale al hombre algo de crédito!
- Por último, no distribuya la clave de licencia con su complemento.
Ahora, los pros y los contras de este enfoque:
ventajas
- Muy fácil de integrar en temas y complementos.
- Puede aprovechar los campos avanzados que forman parte de ACF
- El equipo de ACF administra las actualizaciones de código y seguridad
- ACF tiene excelentes complementos y soporte si te quedas atascado
- Configurar sus campos es súper simple debido a la interfaz de usuario de configuración de campos
Contras
- Acceso limitado al marcado
- Crea una dependencia para su complemento o tema.
- Para mantener ACF actualizado, debe mantenerlo actualizado en sus archivos de complemento/tema (más información a continuación)
¿Cuándo debería usar este enfoque?
Cuando desea crear una interfaz de configuración avanzada muy rápidamente y no necesita personalizar la apariencia.
Empezando
For this approach I will show you how to set up the options page for the free version of ACF. To view a guide on setting up the PRO version check out the ACF documentation. To get started we will be adding ACF to our plugin directory. First, download the latest version of ACF and unzip its contents. In your plugin directory create a (Ver versión grande)
Again, we will follow the steps we did in “Creating Our Plugin And Settings Page”. Before we get into that, though, we should include ACF in our plugin.
Include ACF In Your Plugin
It's actually pretty easy to include ACF in your plugin – there are only three steps. First we have to include the main ACF file with PHP. Add the following code to the bottom of our constructor function:
include_once( plugin_dir_path( __FILE__ ) . 'vendor/advanced-custom-fields/acf.php' );
If you refresh the admin you should see a new menu item titled Custom Fields . Before we go into that page and start setting up our fields we need to update a couple of paths in ACF. We need to tell ACF to look for its front-end assets and file includes in our plugin directory instead of its normal place. Add these two hooks to your constructor:
add_filter( 'acf/settings/path', array( $this, 'update_acf_settings_path' ) ); add_filter( 'acf/settings/dir', array( $this, 'update_acf_settings_dir' ) );
And the callbacks for those hooks:
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; }
The first callback updates the include paths for the PHP files within the ACF plugin. The second updates the URIs for the ACF assets. Now we can set up our fields.
Configuring Your Fields
Now comes the fun part: the ACF field configuration UI. Add a title and any fields you'd like in your form. There is a great walkthrough of what everything on this page does in the ACF documentation. Here's how I have set up mine:

Once you are ready hit the Publish button on the right and your fields will be saved. Now we have to get the fields we set up into our plugin. Right now they only exist in the database. On the left-hand navigation, click the Tools item. On the new page, select the field group we just created and hit Generate Export Code . This will create a chunk of PHP code that we can now include in our plugin.
To add the options, we need to add a method call to our constructor. Add this line to the end of your constructor after our ACF include:
$this->setup_options();
Then we can create the method that will wrap our options:
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' => ', )); } }
Now that we have our fields ready to go, we can add them to the settings page.
Modifying The Settings Page Code
To add the fields we just created to the page we will need to update our plugin_settings_page_content
method.
Previously, we set up the form tag for our page. In this case we will let ACF do that part for us. Here is what our updated function should look like:
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 agregan los scripts y estilos que necesitaremos para los campos de configuración. Después de eso estamos configurando las opciones para nuestro formulario. Puede 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 de acf_form
. La última línea de nuestra función en realidad representará el formulario.
Si intenta cargar la página de configuración ahora, es posible que vea que la página está 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(); }
Puede intentar agregar algo de contenido y guardarlo, y debería funcionar igual que nuestros otros dos enfoques. Así debería verse nuestra página:

Solo hay un par de elementos de limpieza que necesitamos abordar:
Es posible que desee ocultar el hecho de que está utilizando ACF para su complemento. Si este es el caso, debe ocultar el elemento de menú Campos personalizados . Puede hacer esto agregando este fragmento a su 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 vaya a la sección de campos personalizados y presione el botón de la papelera. Este paso es opcional ya que solo afectará el entorno en el que creó el complemento, pero podría presentar problemas si está probando su complemento en el mismo entorno.
Uso de campos ACF dentro de su complemento
Para obtener los campos ACF que creó, simplemente necesita usar la función get_field
predeterminada de ACF. La primera opción debe ser la ID única del campo y el segundo argumento debe establecerse en 'option'
. Así es como obtendríamos el campo Awesome Date :
get_field( 'awesome_date', 'option' )
Y eso es. ¡Ya ha configurado un complemento con la configuración de ACF! Puede ver el código para este enfoque en el repositorio.
Conclusión
Así que ahí lo tiene: tres formas de hacer que sus complementos sean configurables. Me encantaría conocer los complementos que puede crear con estos métodos. Una vez más, configuré un repositorio que alberga el código para cada uno de estos enfoques. No dude en bifurcarlos y personalizarlos para que se ajusten a sus propias necesidades.
En cuanto a mis preferencias personales para estos enfoques, tiendo a inclinarme por el Enfoque 1. Prefiero mantener la menor cantidad posible de dependencias en mis complementos y puede personalizar el marcado para personalizar 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 vale la pena mencionar la propuesta de una API de campos 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 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 indica en los comentarios a continuación, y para brindarles a los desarrolladores otras opciones similares al enfoque ACF, puede consultar algunas alternativas que pueden ofrecer diferentes características. Si tiene más, envíelos 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)