API de Configuración de WordPress: Implementación de Pestañas en Menú Personalizado
He estado siguiendo la serie de tutoriales sobre la API de Configuración de WordPress de este chico:
Hasta ahora, he tenido éxito en hacer lo básico. Ahora, al implementar pestañas, estoy teniendo problemas.
Problema 1: Las pestañas no funcionan. Todos los campos se muestran en ambas pestañas. La Sección 1 debería mostrarse en la Pestaña Uno y la Sección 2 en la Pestaña Dos.
Problema 2: La Opción 2 no se guarda. Funcionaba bien antes de implementar las pestañas.
Código:
/* ----------------------------------------------------------------------------- */
/* Agregar Página de Menú */
/* ----------------------------------------------------------------------------- */
function add_my_menu() {
add_menu_page (
'Título de Página', // título de página
'Título de Menú', // título de menú
'manage_options', // capacidad
'my-menu-slug', // slug del menú
'my_menu_page', // función que renderizará su salida
get_template_directory_uri() . '/assets/ico/theme-option-menu-icon.png' // enlace al ícono que se mostrará en la barra lateral
//$position, // posición de la opción de menú
);
}
add_action('admin_menu', 'add_my_menu');
function my_menu_page() {
?>
<?php
if( isset( $_GET[ 'tab' ] ) ) {
$active_tab = $_GET[ 'tab' ];
} else {
$active_tab = 'tab_one';
}
?>
<div class="wrap">
<h2>Título de la Página de Menú</h2>
<div class="description">Esta es la descripción de la página.</div>
<?php settings_errors(); ?>
<h2 class="nav-tab-wrapper">
<a href="?page=my-menu-slug&tab=tab_one" class="nav-tab <?php echo $active_tab == 'tab_one' ? 'nav-tab-active' : ''; ?>">Pestaña Uno</a>
<a href="?page=my-menu-slug&tab=tab_two" class="nav-tab <?php echo $active_tab == 'tab_two' ? 'nav-tab-active' : ''; ?>">Pestaña Dos</a>
</h2>
<form method="post" action="options.php">
<?php
if( $active_tab == 'tab_one' ) {
settings_fields( 'setting-group-1' );
do_settings_sections( 'my-menu-slug' );
} elseif( $active_tab == 'tab_two' ) {
settings_fields( 'setting-group-2' );
do_settings_sections( 'my-menu-slug' );
}
?>
<?php submit_button(); ?>
</form>
</div>
<?php
}
/* ----------------------------------------------------------------------------- */
/* Secciones y Campos de Configuración */
/* ----------------------------------------------------------------------------- */
function sandbox_initialize_theme_options() {
add_settings_section(
'page_1_section', // ID usado para identificar esta sección y con el cual registrar opciones
'Sección 1', // Título a mostrar en la página de administración
'page_1_section_callback', // Función callback para renderizar la descripción de la sección
'my-menu-slug' // Página donde agregar esta sección de opciones
);
add_settings_section(
'page_2_section', // ID usado para identificar esta sección y con el cual registrar opciones
'Sección 2', // Título a mostrar en la página de administración
'page_2_section_callback', // Función callback para renderizar la descripción de la sección
'my-menu-slug' // Página donde agregar esta sección de opciones
);
/* ----------------------------------------------------------------------------- */
/* Opción 1 */
/* ----------------------------------------------------------------------------- */
add_settings_field (
'option_1', // ID usado para identificar el campo
'Opción 1', // Etiqueta a la izquierda del elemento de opción
'option_1_callback', // Nombre de la función responsable de renderizar la interfaz de opción
'my-menu-slug', // Página donde se mostrará esta opción
'page_1_section', // Nombre de la sección a la que pertenece este campo
array( // Array de argumentos para pasar al callback. En este caso, solo una descripción.
'Esta es la descripción de la opción 1',
)
);
register_setting(
//~ 'my-menu-slug',
'setting-group-1',
'option_1'
);
/* ----------------------------------------------------------------------------- */
/* Opción 2 */
/* ----------------------------------------------------------------------------- */
add_settings_field (
'option_2', // ID -- ID usado para identificar el campo
'Opción 2', // ETIQUETA -- La etiqueta a la izquierda del elemento de opción
'option_2_callback', // FUNCIÓN CALLBACK -- Nombre de la función responsable de renderizar la interfaz de opción
'my-menu-slug', // SLUG DE PÁGINA DE MENÚ -- Página donde se mostrará esta opción
'page_2_section', // ID DE SECCIÓN -- Nombre de la sección a la que pertenece este campo
array( // Array de argumentos para pasar al callback. En este caso, solo una descripción.
'Esta es la descripción de la opción 2', // DESCRIPCIÓN -- Descripción del campo.
)
);
register_setting(
'setting-group-2',
'option_2'
);
} // function sandbox_initialize_theme_options
add_action('admin_init', 'sandbox_initialize_theme_options');
function page_1_section_callback() {
echo '<p>Descripción de la sección aquí</p>';
} // function page_1_section_callback
function page_2_section_callback() {
echo '<p>Descripción de la sección aquí</p>';
} // function page_1_section_callback
/* ----------------------------------------------------------------------------- */
/* Funciones Callback para Campos */
/* ----------------------------------------------------------------------------- */
function option_1_callback($args) {
?>
<input type="text" id="option_1" class="option_1" name="option_1" value="<?php echo get_option('option_1') ?>">
<p class="description option_1"> <?php echo $args[0] ?> </p>
<?php
} // end option_1_callback
function option_2_callback($args) {
?>
<textarea id="option_2" class="option_2" name="option_2" rows="5" cols="50"><?php echo get_option('option_2') ?></textarea>
<p class="description option_2"> <?php echo $args[0] ?> </p>
<?php
} // end option_2_callback

Aquí está cómo lo hago, cuidado, el post es extenso.
/* Añadir Menús
-----------------------------------------------------------------*/
add_action('admin_menu', 'ch_essentials_admin');
function ch_essentials_admin() {
/* Menú Base */
add_menu_page(
'Essentials Theme',
'Essentials Theme',
'manage_options',
'ch-essentials-options',
'ch_essentials_index');
}
Ahora para mis campos de configuración, campos extras removidos, solo como ejemplo.
Esto es para 'Configuraciones de Página Principal' y 'Pestaña de Página Principal'
add_action('admin_init', 'ch_essentials_options');
function ch_essentials_options() {
/* Sección de Opciones de Página Principal */
add_settings_section(
'ch_essentials_front_page',
'Opciones de Página Principal Essentials',
'ch_essentials_front_page_callback',
'ch_essentials_front_page_option'
);
add_settings_field(
'featured_post',
'Post Destacado',
'ch_essentials_featured_post_callback',
'ch_essentials_front_page_option',
'ch_essentials_front_page'
);
Esto es para mis opciones de encabezado, que es la pestaña 'opciones de encabezado'
/* Sección de Opciones de Encabezado */
add_settings_section(
'ch_essentials_header',
'Opciones de Encabezado Essentials',
'ch_essentials_header_callback',
'ch_essentials_header_option'
);
add_settings_field(
'header_type',
'Tipo de Encabezado',
'ch_essentials_textbox_callback',
'ch_essentials_header_option',
'ch_essentials_header',
array(
'header_type'
)
);
Registrar Configuraciones
register_setting('ch_essentials_front_page_option', 'ch_essentials_front_page_option');
register_setting('ch_essentials_header_option', 'ch_essentials_header_option');
Todos estos están envueltos en una función, luego ejecutados con un admin_init
/* Opciones
-----------------------------------------------------------------*/
add_action('admin_init', 'ch_essentials_options');
function ch_essentials_options() {
/* Código mostrado arriba */
}
Funciones de Retorno:
/* Funciones de Retorno
-----------------------------------------------------------------*/
function ch_essentials_front_page_callback() {
echo '<p>Opciones de Visualización de Página Principal:</p>';
}
function ch_essentials_header_callback() {
echo '<p>Opciones de Visualización de Encabezado:</p>';
}
function ch_essentials_textbox_callback($args) {
$options = get_option('ch_essentials_header_option');
echo '<input type="text" id="' . $args[0] . '" name="ch_essentials_header_option[' . $args[0] . ']" value="' . $options['' . $args[0] . ''] . '"></input>';
}
function ch_essentials_featured_post_callback($args) {
$options = get_option('ch_essentials_front_page_option');
query_posts( $args );
echo '<select id="featured_post" name="ch_essentials_front_page_option[featured_post]">';
while ( have_posts() ) : the_post();
$selected = selected($options['featured_post'], get_the_id(), false);
printf('<option value="%s" %s>%s</option>', get_the_id(), $selected, get_the_title());
endwhile;
echo '</select>';
}
Ahora esta es la parte de visualización, con las pestañas..
Si tienes tus secciones y campos de configuración hechos exactamente así, entonces podrás hacer las pestañas sin problemas.
/* Página de Visualización
-----------------------------------------------------------------*/
function ch_essentials_index() {
?>
<div class="wrap">
<div id="icon-themes" class="icon32"></div>
<h2>Opciones del Tema Essentials</h2>
<?php settings_errors(); ?>
<?php
$active_tab = isset( $_GET[ 'tab' ] ) ? $_GET[ 'tab' ] : 'front_page_options';
?>
<h2 class="nav-tab-wrapper">
<a href="?page=ch-essentials-options&tab=front_page_options" class="nav-tab <?php echo $active_tab == 'front_page_options' ? 'nav-tab-active' : ''; ?>">Opciones de Página Principal</a>
<a href="?page=ch-essentials-options&tab=header_options" class="nav-tab <?php echo $active_tab == 'header_options' ? 'nav-tab-active' : ''; ?>">Opciones de Encabezado</a>
</h2>
<form method="post" action="options.php">
<?php
if( $active_tab == 'front_page_options' ) {
settings_fields( 'ch_essentials_front_page_option' );
do_settings_sections( 'ch_essentials_front_page_option' );
} else if( $active_tab == 'header_options' ) {
settings_fields( 'ch_essentials_header_option' );
do_settings_sections( 'ch_essentials_header_option' );
}
?>
<?php submit_button(); ?>
</form>
</div>
<?php
}
-----EDITADO-----
y noté en tu post que tienes 'elseif' y no 'else if' en tu página de visualización real en la sección de pestañas

Esto fue bastante útil para mí. Tenía problemas para convertir una página individual en una página de pestañas. Las únicas cosas que añadí fueron una verificación empty() en el array $option para cada campo de entrada. De lo contrario, me aparecía un error cuando el valor no estaba establecido. También añadí un tercer argumento a register_settings(). Este acepta un array opcional para configurar cosas como la sanitización. En general, este fue un post muy bueno con código de calidad.

Codificar así funcionó para mí:
<?php
/* ----------------------------------------------------------------------------- */
/* Añadir Página de Menú */
/* ----------------------------------------------------------------------------- */
function add_my_menu() {
add_menu_page (
'Título de la Página', // título de la página
'Título del Menú', // título del menú
'manage_options', // capacidad
'my-menu-slug', // slug del menú
'my_menu_page', // función que renderizará su salida
get_template_directory_uri() . '/assets/ico/theme-option-menu-icon.png' // enlace al icono que se mostrará en la barra lateral
//$position, // posición de la opción del menú
);
}
add_action('admin_menu', 'add_my_menu');
function my_menu_page() {
?>
<?php
if( isset( $_GET[ 'tab' ] ) ) {
$active_tab = $_GET[ 'tab' ];
} else {
$active_tab = 'tab_one';
}
?>
<div class="wrap">
<h2>Título de la Página del Menú</h2>
<div class="description">Esta es la descripción de la página.</div>
<?php settings_errors(); ?>
<h2 class="nav-tab-wrapper">
<a href="?page=my-menu-slug&tab=tab_one" class="nav-tab <?php echo $active_tab == 'tab_one' ? 'nav-tab-active' : ''; ?>">Pestaña Uno</a>
<a href="?page=my-menu-slug&tab=tab_two" class="nav-tab <?php echo $active_tab == 'tab_two' ? 'nav-tab-active' : ''; ?>">Pestaña Dos</a>
</h2>
<form method="post" action="options.php">
<?php
if( $active_tab == 'tab_one' ) {
settings_fields( 'setting-group-1' );
do_settings_sections( 'my-menu-slug-1' );
} else if( $active_tab == 'tab_two' ) {
settings_fields( 'setting-group-2' );
do_settings_sections( 'my-menu-slug-2' );
}
?>
<?php submit_button(); ?>
</form>
</div>
<?php
}
/* ----------------------------------------------------------------------------- */
/* Secciones y Campos de Configuración */
/* ----------------------------------------------------------------------------- */
function sandbox_initialize_theme_options() {
add_settings_section(
'page_1_section', // ID usado para identificar esta sección y con el cual registrar opciones
'Sección 1', // Título a mostrar en la página de administración
'page_1_section_callback', // Función de callback para renderizar la descripción de la sección
'my-menu-slug-1' // Página donde añadir esta sección de opciones
);
add_settings_section(
'page_2_section', // ID usado para identificar esta sección y con el cual registrar opciones
'Sección 2', // Título a mostrar en la página de administración
'page_2_section_callback', // Función de callback para renderizar la descripción de la sección
'my-menu-slug-2' // Página donde añadir esta sección de opciones
);
/* ----------------------------------------------------------------------------- */
/* Opción 1 */
/* ----------------------------------------------------------------------------- */
add_settings_field (
'option_1', // ID usado para identificar el campo en todo el tema
'Opción 1', // La etiqueta a la izquierda del elemento de opción
'option_1_callback', // El nombre de la función responsable de renderizar la interfaz de opción
'my-menu-slug-1', // La página donde se mostrará esta opción
'page_1_section', // El nombre de la sección a la que pertenece este campo
array( // El array de argumentos para pasar al callback. En este caso, solo una descripción.
'Esta es la descripción de la opción 1',
)
);
register_setting(
//~ 'my-menu-slug',
'setting-group-1',
'option_1'
);
/* ----------------------------------------------------------------------------- */
/* Opción 2 */
/* ----------------------------------------------------------------------------- */
add_settings_field (
'option_2', // ID -- ID usado para identificar el campo en todo el tema
'Opción 2', // ETIQUETA -- La etiqueta a la izquierda del elemento de opción
'option_2_callback', // FUNCIÓN CALLBACK -- El nombre de la función responsable de renderizar la interfaz de opción
'my-menu-slug-2', // SLUG DE PÁGINA DE MENÚ -- La página donde se mostrará esta opción
'page_2_section', // ID DE SECCIÓN -- El nombre de la sección a la que pertenece este campo
array( // El array de argumentos para pasar al callback. En este caso, solo una descripción.
'Esta es la descripción de la opción 2', // DESCRIPCIÓN -- La descripción del campo.
)
);
register_setting(
'setting-group-2',
'option_2'
);
} // function sandbox_initialize_theme_options
add_action('admin_init', 'sandbox_initialize_theme_options');
function page_1_section_callback() {
echo '<p>Descripción de la sección aquí</p>';
} // function page_1_section_callback
function page_2_section_callback() {
echo '<p>Descripción de la sección aquí</p>';
} // function page_1_section_callback
/* ----------------------------------------------------------------------------- */
/* Funciones Callback de Campos */
/* ----------------------------------------------------------------------------- */
function option_1_callback($args) {
?>
<input type="text" id="option_1" class="option_1" name="option_1" value="<?php echo get_option('option_1') ?>">
<p class="description option_1"> <?php echo $args[0] ?> </p>
<?php
} // end sandbox_toggle_header_callback
function option_2_callback($args) {
?>
<textarea id="option_2" class="option_2" name="option_2" rows="5" cols="50"><?php echo get_option('option_2') ?></textarea>
<p class="description option_2"> <?php echo $args[0] ?> </p>
<?php
} // end sandbox_toggle_header_callback
?>

<form method="post" action="options.php">
<?php
if( $active_tab == 'tab_one' ) {
settings_fields( 'setting-group-1' );
do_settings_sections( 'my-menu-slug-1' );
} elseif( $active_tab == 'tab_two' ) {
settings_fields( 'setting-group-2' );
do_settings_sections( 'my-menu-slug-1' );
}
?>
Cambia el my-menu-slug
por my-menu-slug-1
y my-menu-slug-2
