Registrar opciones
1. Visión general (flujo)
Cuando creas una página de ajustes en el Admin de WP normalmente sigues este flujo:
register_setting()
— registras la opción (nombre enwp_options
) y la función que la limpiará/validará.add_settings_section()
— defines una sección —un bloque con título/descripcion— dentro de la página de ajustes.add_settings_field()
— registras cada campo (input) que irá dentro de una sección. Le das un callback que pinta el HTML del campo.- En tu página de ajustes llamas a
settings_fields( $option_group )
,do_settings_sections( $page )
ysubmit_button()
para que WP construya el formulario y gestione el guardado.
Resumen rápido:
register_setting()
= guardar + sanitizar,add_settings_section()
= organizar,add_settings_field()
= dibujar inputs.
2. register_setting()
— explicación detallada
Propósito: registrar una opción (o grupo de opciones) en WP, declarar su tipo por defecto y definir la función que la limpiará/validará antes de guardarla en la base de datos.
register_setting( string $option_group, string $option_name, array|string $args = array() );
- $option_group
- Nombre del grupo de ajustes. También es el valor que PASAS luego a
settings_fields()
. - No confundir con la página; es el grupo al que pertenecen las opciones.
- Nombre del grupo de ajustes. También es el valor que PASAS luego a
- $option_name
- Nombre de la opción que se almacenará en
wp_options
. Puede ser un string simple (opción individual) o el nombre de un array (p. ej.mi_plugin_options
) que contendrá varias claves.
- Nombre de la opción que se almacenará en
- $args (array o string — preferir array) puede contener:
'type'
—'string'|'integer'|'boolean'|'array'|'number'
(ayuda a documentación/validación).'description'
— texto descriptivo.'sanitize_callback'
— función que recibe el valor enviado y debe devolver el valor limpio (oWP_Error
/ usaradd_settings_error()
para errores).'default'
— valor por defecto si la opción no existe.'show_in_rest'
— boolean o array para exponer la opción en la REST API.
Ejemplo mínimo (opción simple):
register_setting( 'mi_plugin_group', 'mi_plugin_items_per_page', array(
'type' => 'integer',
'sanitize_callback' => 'absint',
'default' => 5,
) );
Ejemplo (opción tipo array con función de sanitizado):
register_setting( 'mi_plugin_group', 'mi_plugin_options', array(
'type' => 'array',
'sanitize_callback' => 'mi_plugin_sanitize_options',
'default' => array( 'items_per_page' => 5, 'show_title' => 1 ),
) );
function mi_plugin_sanitize_options( $input ) {
$output = array();
// items_per_page => integer entre 1 y 50
$output['items_per_page'] = isset( $input['items_per_page'] ) ? absint( $input['items_per_page'] ) : 5;
if ( $output['items_per_page'] < 1 ) {
$output['items_per_page'] = 1;
add_settings_error( 'mi_plugin_options', 'items_per_page_error', 'El número mínimo es 1', 'error' );
}
if ( $output['items_per_page'] > 50 ) {
$output['items_per_page'] = 50;
add_settings_error( 'mi_plugin_options', 'items_per_page_max', 'El número máximo es 50', 'warning' );
}
// checkbox: puede venir vacío si está desmarcado
$output['show_title'] = ! empty( $input['show_title'] ) ? 1 : 0;
return $output;
}
Notas importantes:
- La sanitización siempre debe hacerse. Nunca confíes en los datos del usuario.
- La función puede usar
add_settings_error()
para notificar errores y devolver un valor por defecto o corregido. - Si devuelves un
WP_Error
la opción no se actualizará (y el error se podrá mostrar). Es más común usaradd_settings_error()
y devolver un valor seguro.
3. add_settings_section()
— explicación detallada
Propósito: agrupar campos dentro de la página de ajustes, con un ID, título y (opcionalmente) una descripción o callback que muestre ayuda.
add_settings_section( string $id, string $title, callable $callback, string $page );
- $id — identificador único de la sección (ej.
'mi_section'
). - $title — título visible de la sección.
- $callback — función que imprime texto/descripción para la sección (puede ser
__return_false
si no quieres descripción). - $page — slug de la página de ajustes donde deberá imprimirse esta sección. (Este
$page
es el mismo valor que luego pasas ado_settings_sections( $page )
cuando construyes la página).
Ejemplo:
add_settings_section(
'mi_section',
'Ajustes Generales',
function() { echo '<p>Configura las opciones principales del plugin.</p>'; },
'mi_plugin_page'
);
4. add_settings_field()
— explicación detallada
Propósito: registrar un campo que aparecerá dentro de una sección específica. Le indicas un callback que dibuje el HTML del input.
add_settings_field( string $id, string $title, callable $callback, string $page, string $section = 'default', array $args = array() );
- $id — id único del campo (ej.
'items_per_page'
). - $title — etiqueta visible para el campo.
- $callback — función que pinta el input. Recibe
$args
(el último parámetro). - $page — debe coincidir con el
page
usado enadd_settings_section()
y endo_settings_sections()
. - $section — el id de la sección donde irá el campo.
- $args — array opcional con cualquier dato que quieras pasar al callback (por ejemplo
label_for
,class
,nombre_opcion
, etc.).label_for
es útil para vincular<label for="...">
con elid
del input.
Ejemplo (uso de label_for):
add_settings_field(
'items_per_page',
'Items por página',
'mi_field_items_render',
'mi_plugin_page',
'mi_section',
array(
'label_for' => 'mi_items_per_page',
'class' => 'mi_row_class'
)
);
function mi_field_items_render( $args ) {
$options = get_option( 'mi_plugin_options', array() );
$value = isset($options['items_per_page']) ? $options['items_per_page'] : 5;
printf(
'<input id="%1$s" name="mi_plugin_options[items_per_page]" type="number" min="1" max="50" value="%2$s" />',
esc_attr( $args['label_for'] ),
esc_attr( $value )
);
}
Notas:
- Cuando el
option_name
es un array (mi_plugin_options
), en elname
del input usasmi_plugin_options[campo]
para que WP guarde todo como un array. - Si registraste la opción como opción individual (
mi_plugin_items_per_page
), elname
debe ser simplementemi_plugin_items_per_page
.
5. Cómo construir la página de ajustes (markup habitual)
En el callback que pinta la página (p. ej. render_settings
), normalmente incluyes:
function mi_plugin_render_page() {
if ( ! current_user_can( 'manage_options' ) ) return;
?>
<div class="wrap">
<h1>Mi Plugin — Ajustes</h1>
<?php
// Muestra errores/avisos registrados con add_settings_error()
settings_errors( 'mi_plugin_options' ); // opcional: filtrar por setting
?>
<form action="options.php" method="post">
<?php
// prints hidden fields (nonce, option_page, etc.) — el primer parámetro coincide con register_setting's option_group
settings_fields( 'mi_plugin_group' );
// imprime las secciones y campos registrados para la "page" (mi_plugin_page)
do_settings_sections( 'mi_plugin_page' );
// botón Guardar
submit_button();
?>
</form>
</div>
<?php
}
Puntos clave:
settings_fields( 'mi_plugin_group' )
debe recibir exactamente el mismo option_group que usaste enregister_setting()
.do_settings_sections( 'mi_plugin_page' )
mostrará todas las secciones y campos añadidos para esa página.submit_button()
genera el botón y WP se encargará de procesar el guardado con las llamadas a la función de sanitización registrada.
6. Ejemplo completo y real (lista para copiar)
Plugin pequeño que registra un array de opciones, añade sección y dos campos:
<?php
/**
* Plugin Name: Ejemplo Settings API Completo
* Description: Ejemplo didáctico de register_setting, add_settings_section y add_settings_field.
* Version: 1.0
* Author: Tu Nombre
*/
if ( ! defined( 'ABSPATH' ) ) exit;
// Hook: registrar settings y campos
add_action( 'admin_init', 'ejemplo_settings_init' );
function ejemplo_settings_init() {
// 1) Registrar la opción (array)
register_setting( 'ejemplo_group', 'ejemplo_options', array(
'type' => 'array',
'sanitize_callback' => 'ejemplo_sanitize_options',
'default' => array(
'items_per_page' => 5,
'show_title' => 1
)
) );
// 2) Añadir sección
add_settings_section(
'ejemplo_section',
'Ajustes principales',
function() { echo '<p>Configura las opciones principales del plugin.</p>'; },
'ejemplo_page'
);
// 3) Añadir campo: items_per_page
add_settings_field(
'items_per_page',
'Items por página',
'ejemplo_field_items_render',
'ejemplo_page',
'ejemplo_section',
array(
'label_for' => 'ejemplo_items_per_page'
)
);
// 4) Añadir campo: show_title (checkbox)
add_settings_field(
'show_title',
'Mostrar título',
'ejemplo_field_showtitle_render',
'ejemplo_page',
'ejemplo_section',
array(
'label_for' => 'ejemplo_show_title'
)
);
}
// Render del campo items_per_page
function ejemplo_field_items_render( $args ) {
$options = get_option( 'ejemplo_options' );
$val = isset( $options['items_per_page'] ) ? $options['items_per_page'] : 5;
printf(
'<input id="%1$s" name="ejemplo_options[items_per_page]" type="number" min="1" max="50" value="%2$s" />',
esc_attr( $args['label_for'] ),
esc_attr( $val )
);
echo '<p class="description">Número de items a mostrar por página (1–50).</p>';
}
// Render del checkbox show_title
function ejemplo_field_showtitle_render( $args ) {
$options = get_option( 'ejemplo_options' );
$checked = ! empty( $options['show_title'] );
printf(
'<input id="%1$s" name="ejemplo_options[show_title]" type="checkbox" value="1" %2$s />',
esc_attr( $args['label_for'] ),
checked( 1, $checked, false )
);
echo '<label for="' . esc_attr( $args['label_for'] ) . '"> Mostrar el título en la lista</label>';
}
// Sanitización
function ejemplo_sanitize_options( $input ) {
$output = array();
$output['items_per_page'] = isset( $input['items_per_page'] ) ? absint( $input['items_per_page'] ) : 5;
if ( $output['items_per_page'] < 1 ) {
$output['items_per_page'] = 1;
add_settings_error( 'ejemplo_options', 'items_min', 'El valor mínimo es 1', 'error' );
}
if ( $output['items_per_page'] > 50 ) {
$output['items_per_page'] = 50;
add_settings_error( 'ejemplo_options', 'items_max', 'El valor máximo es 50', 'error' );
}
$output['show_title'] = ! empty( $input['show_title'] ) ? 1 : 0;
return $output;
}
// PÁGINA DE ADMIN (ej. desde add_menu_page llamas a esta función)
function ejemplo_render_page() {
if ( ! current_user_can( 'manage_options' ) ) return;
?>
<div class="wrap">
<h1>Ejemplo Settings API</h1>
<?php settings_errors( 'ejemplo_options' ); ?>
<form method="post" action="options.php">
<?php
settings_fields( 'ejemplo_group' ); // option_group de register_setting
do_settings_sections( 'ejemplo_page' ); // page usada en add_settings_section / add_settings_field
submit_button();
?>
</form>
</div>
<?php
}
(Para que la página sea accesible, añade un add_menu_page()
que llame a ejemplo_render_page()
.)
7. Buenas prácticas y consejos útiles
- Sanitiza siempre (
sanitize_callback
) y escapa al mostrar (esc_attr
,esc_html
…) — nunca confíes en el input del usuario. - Usa prefijos en nombres de opción para evitar colisiones (ej.
mi_plugin_
). - Array vs opciones separadas:
- Guardar un array (
mi_plugin_options
) es práctico (menos entradas enwp_options
) y ordenado. - Guardar opciones separadas (
mi_plugin_items_per_page
) puede ser más simple si son independientes.
- Guardar un array (
- Checkboxes: recuerda que si están desmarcadas no se envían; tu sanitizador debe poner
0
ofalse
si la clave no existe. - Mostrar errores: usa
add_settings_error()
dentro del sanitizador para notificar errores; en la página usasettings_errors()
para mostrarlos. - Nonces & permisos:
settings_fields()
genera el nonce para la opción; además, compruebacurrent_user_can()
en tu callback de renderizado. - Cargar assets solo donde toca: usa
$hook_suffix
devuelto poradd_menu_page()
para encolar scripts/estilos solo para tu página. - Depuración: si los campos no aparecen, revisa que los parámetros
page
yoption_group
coincidan exactamente entreadd_settings_section()
,add_settings_field()
,register_setting()
y tus llamadas ado_settings_sections()
/settings_fields()
.
8. Errores comunes
- Usar nombres distintos para
option_group
enregister_setting()
ysettings_fields()
→ las opciones no se guardan correctamente. - Olvidar
name="mi_plugin_options[campo]"
cuando registraste la opción como array → WP no guarda el subcampo. - No retornar el valor saneado en el
sanitize_callback
→ la opción puede guardarse mal o no guardarse. - No llamar a
settings_errors()
→ no verás los mensajes agregados conadd_settings_error()
.