Filtrar un segundo menú desplegable al elegir un valor en el primero
Tengo una tabla con dos menús desplegables. El primero es para las marcas, que es un custom post type de WordPress. El segundo es para los sabores, que también es un custom post type. La marca es el padre de los sabores. Cuando selecciono una marca necesito actualizar el segundo menú desplegable con los sabores de esa marca (los hijos).
Creé shortcodes para mis listas y se llenan correctamente. Pero no sé cómo filtrar el segundo menú desplegable cuando cambia el primero.
Aquí está mi tabla:
<table id="fla_inf" width="100%">
<tbody>
<tr>
<th class="tab_header" colspan="6">Sabores y Aditivos</th>
</tr>
<tr>
<th class="tab_header_nam">Marca del Sabor</th>
<th class="tab_header_nam">Nombre del Sabor</th>
<th class="tab_header_nam">Tipo de gotero</th>
<th class="tab_header_nam">Unidad de Cantidad</th>
<th class="tab_header_nam">Cantidad</th>
<th class="tab_header_nam">Añadir/Eliminar fila</th>
</tr>
<tr class="flavors">
<td>[brand_list]</td>
<td>[flavor_list]</td>
<td><select id="dropper0" class="dropper">
<option selected="selected" value="type1">tipo 1</option>
<option value="type2">tipo 2-3</option>
</select></td>
<td><select id="qtyunit0" class="qtyunit">
<option value="ml">ml</option>
<option value="drops">gotas</option>
<option selected="selected" value="perc">%</option>
</select></td>
<td><input id="quantity0" class="quantity" type="number" /></td>
<td><input class="addline" src="http://spitilab.com/wp-content/uploads/2015/01/add.png" type="image" alt="Añadir fila" title="Añadir nueva fila" /><input class="remline" src="http://spitilab.com/wp-content/uploads/2015/01/delete.png" type="image" alt="Eliminar fila" title="Eliminar esta fila" /></td>
</tr>
</tbody>
</table>
aquí están mis shortcodes:
function GetBrandList() {
// Obtener lista desplegable de marcas
$brands = wp_dropdown_pages(array('id'=>'marque0','post_type' => 'marque-type','echo'=>0));
return $brands;
}
function GetFlavorList() {
// Obtener lista desplegable de sabores
$flavors = wp_dropdown_pages(array('id'=>'arome0','post_type'=>'aromes-type','echo'=>0));
return $flavors;
}
add_shortcode('brand_list', 'GetBrandList');
add_shortcode('flavor_list', 'GetFlavorList');
Aquí está mi actualización:
Añadí lo siguiente a mi functions.php
add_action( 'wp_ajax_brand_children', 'GetBrandChildren');
add_action( 'wp_ajax_nopriv_brand_children', 'GetBrandChildren');
function GetBrandChildren($parent_id,$id) {
// Obtener hijos de la marca seleccionada
$children = wp_dropdown_pages(array('id'=>'arome$id','post_type'=>'aromes-type','child_of'=>$parent_id,'echo'=>0));
return $children;
}
y aquí está mi jquery:
// Al seleccionar marca, actualizar lista de sabores
$(document).on('change', "select[id^='marque']", function() {
var $brandid = $(this).val();
var $brand_dd_id = $(this).attr('id');
var $flav_dd_id = $brand_dd_id.substr($brand_dd_id.length-1);
$("#arome"+$flav_dd_id).empty();
// Hacer petición AJAX con el valor seleccionado
$.ajax({data: '{"parent_id":"' + $brandid + '","id":"'+ $flav_dd_id +'","action":"brand_children"}',
success: function(output) {
alert(output);
$("#arome"+$flav_dd_id).html(output);
}
});
});
Sin embargo, mi menú desplegable de sabores permanece vacío. En la salida mostrada en la alerta, parece que se devuelve la página HTML completa.
ACTUALIZACIÓN:
add_action( 'wp_ajax_brand_children', 'GetBrandChildren');
add_action( 'wp_ajax_nopriv_brand_children', 'GetBrandChildren');
function GetBrandChildren() {
$parent_id = $_POST['brandid'];
$id = $_POST['flav_dd_id'];
echo wp_dropdown_pages(array("id"=>"arome$id",'post_type'=>'aromes-type','child_of'=>$parent_id,'echo'=>0));
//ob_clean();
//echo "working";
wp_die();
}
// necesarias para localizar admin-ajax.php en jQuery
wp_enqueue_script( 'my-ajax-request', get_template_directory_uri() . '/js/ajax.js', array( 'jquery' ) );
wp_localize_script( 'my-ajax-request', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
el JQuery:
// Al seleccionar marca, actualizar lista de sabores
$(document).on('change', "select[id^='marque']", function() {
var $brandid = $(this).val();
var $brand_dd_id = $(this).attr('id');
var $flav_dd_id = $brand_dd_id.substr($brand_dd_id.length-1);
$("#arome"+$flav_dd_id).empty();
// Hacer petición AJAX
$.ajax({
url: MyAjax.ajaxurl,
data: {
'parent_id': $brandid,
'id': $flav_dd_id,
'action': 'brand_children'
},
success: function(output) {
console.log(output);
$("#arome"+$flav_dd_id).html(output);
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status + " "+ thrownError);
}});
});
ahora mi segundo menú desplegable se actualiza correctamente.

Vas a querer usar Ajax para hacer esto y que el segundo menú desplegable se cargue después de haber seleccionado el primero. No estoy seguro de un par de cosas que tienes ahí arriba, así que simplemente voy a codificarlo por ti, puede que tengas que cambiar algo aquí o allá, lo completaré lo mejor posible. Lo primero que hay que hacer es configurar una acción ajax. Esto debería configurarse idealmente dentro de un plugin. Se usa is_admin() porque cuando la solicitud Ajax se envía desde la página con tu lista desplegable, se ejecutará bajo admin. Si parece que estamos trabajando al revés, es solo un asunto de qué fue primero, el huevo o la gallina. ¿Qué fue primero, la solicitud o el manejador... el manejador, por supuesto, por eso empiezo aquí.
<?php
if ( is_admin() ) {
// Añadimos 2 acciones, la primera para usuarios logueados, la segunda para invitados.
add_action( 'wp_ajax_dynamic_dropdown', 'dynamic_dropdown_func' );
add_action( 'wp_ajax_nopriv_dynamic_dropdown', 'dynamic_dropdown_func' );
}
// Esta es la función que manejará tu Solicitud/Respuesta Ajax
function dynamic_dropdown_func () {
global $wpdb;
if (isset($_POST['value'])) {
$selected_option = $_POST['value'];
// Este será tu segundo menú desplegable, se devolverá en una solicitud Ajax
$args = array(
'show_option_none' => __( 'Elige otro' ),
'class' => 'dropper',
'id' => 'dropper0',
'orderby' => 'ID',
'order' => 'ASC',
'hide_empty' => 0,
'hierarchical' => 1,
'depth' => 1,
// Esto es lo que nos dará los hijos de la primera opción seleccionada
'child_of' => (int)$selected_option,
'echo' => 0,
// Asegúrate de cambiar esta constante por tu taxonomía
'taxonomy' => MY_CUSTOM_TAX,
);
$my_second_dropdown = wp_dropdown_categories( $args );
// Si quieres hacer algún preg_replace o str_replace, hazlo aquí antes del ob_clean()
}
// ob_clean es para evitar errores, echos, cualquier cosa que se haya enviado a la salida hasta este punto en la instancia Ajax de WP que podría arruinar tu retorno.
ob_clean();
return $my_second_dropdown;
wp_die();
}
Bien, ahora vamos a hacer la parte del frontend del código. Esta es la parte que verá el usuario. Cuando activen la Solicitud Ajax, al recibir la respuesta, el segundo menú debería cargarse. Normalmente, localizarías un archivo JavaScript con la variable para ajax_url y cualquier otro valor PHP que necesitemos usar en nuestro JS para enviar solicitudes Ajax a WP. Vamos a hacer un poco de trampa y simplemente imprimiremos nuestro script en la página y obtendremos el mismo resultado. Solo asegúrate de imprimir este script al final del body idealmente, o de lo contrario tendrás que añadir una función document ready, de todos modos no haría daño.
function my_frontend_javascript () {
$ajax_url = admin_url( 'admin-ajax.php' );
$javascript = "
<script>
var ajaxUrl = {$ajax_url},
// Ahora vamos a capturar nuestros menús desplegables
dropdownArome = jQuery('#arome0'),
dropdownDropper = jQuery('#dropper0');
if (dropdownArome.length && dropdownDropper.length) {
// Bien, nuestros elementos existen
dropdownArome.on('change', function (e) {
var value = e.target.selectedOptions[0].value,
success,
data;
if (!!value) {
// Muy bien, enviemos ese valor a nuestro Script Ajax, nota que la acción es la misma que el hook de acción Ajax que usamos antes
data = {
'my_value' : value,
'action' : 'dynamic_dropdown'
};
success = function ( response ) {
// Esta respuesta contendrá nuestras etiquetas <option>
dropdownDropper.html( response );
};
jQuery.post( ajaxUrl, data, success );
}
});
}
</script>";
return $javascript;
}
/** Aquí es donde construimos nuestro sitio/formulario/menús desplegables */
$args = array(
'show_option_none' => __( 'Elige uno' ),
'class' => 'arome',
'id' => 'arome0"',
'orderby' => 'ID',
'order' => 'ASC',
'hide_empty' => 0,
'hierarchical' => 1,
'depth' => 1,
'echo' => 0,
// Asegúrate de cambiar esta constante
'taxonomy' => MY_CUSTOM_TAX,
);
$my_first_dropdown = wp_dropdown_categories( $args );
// Bien, ahora imprimimos los 2 menús desplegables, luego el JavaScript de la función que escribimos arriba
echo $my_first_dropdown;
echo '<br /><div id="dropper0-container"></div><br />';
echo my_frontend_javascript();
/** ¡Eso debería ser todo! Como dije, tendrás que ajustar algunas opciones para que se adapten a tu sitio y tu implementación. */
Así es como harías lo que intentas hacer de lo que supongo podría ser una de las formas más simples. Digo simple porque realmente no hicimos validación, nonce, básicamente asumimos que todo salió bien. Sugeriría leer más sobre Ajax en WP, incluso si ya sabes algo, nunca está de más saber más. Espero que este código funcione bien para ti con algunos ajustes.
http://codex.wordpress.org/AJAX_in_Plugins
http://www.smashingmagazine.com/2011/10/18/how-to-use-ajax-in-wordpress/

Hola oneThingSimple,
No esperaba una respuesta tan completa como la tuya, muchísimas gracias por tomarte el tiempo de explicarme. Soy muy nuevo en ajax, esta es en realidad la primera vez que necesito usarlo. Intentaré adaptar tu respuesta a lo que necesito, realmente ayuda.
Gracias de nuevo.
Cyrille

@user3515709 De acuerdo, no hay problema. Ajax puede ser un poco complicado al principio. Sería bueno que te familiarizaras con cómo funciona el Objeto Ajax de jQuery. Ese es el objeto que usamos principalmente en WP para enviar solicitudes asíncronas. Como desarrollador, diría que jQuery vale su peso solo por el Objeto Ajax. Si necesitas ayuda, puedes contactarme, intentaré hacerlo menos doloroso para ti ya que será complejo hasta que entiendas todo el proceso, luego se volverá como cualquier otra cosa. Así que si te frustras, avísame.

Actualicé mi código, tengo un problema con la salida. Probablemente algo que entendí mal.

@user3515709 Terminaré con el trabajo en 4 horas. Luego, si quieres que revise el código, puedo hacerlo contigo. Intentaré ayudarte a que funcione. Ya sea en la sala de chat aquí en stackexchange o envíame un correo a mike@stayshine.com y podemos discutirlo fuera del foro. Buena suerte.

Aún no tengo suerte con esto. Creo que hay un problema con mi código, pero también con mi función wp_dropdown_pages porque creé un shortcode para mostrar los hijos de un padre específico y el menú desplegable muestra: "Main Page (no parent)"

Con tu función function GetBrandChildren($parent_id,$id) no estás obteniendo realmente los datos enviados en la solicitud Ajax como argumentos. Necesitas obtener esos valores del array $_POST. No es necesario intentar convertir manualmente tu propio objeto de datos en una cadena. Solo usa un objeto JavaScript regular. jQuery se encargará de serializar los argumentos. Además, recuerda usar echo para mostrar Children, no return. Luego de usar echo, utiliza wp_die() para que la página se complete y se envíe, y no se agregue contenido adicional.

gracias por tu aporte, cambié el código según tus recomendaciones. ¿Hay alguna forma de ver si el resultado devuelto es correcto? Cuando muestro el resultado en una alerta, parece que se devuelve toda la página

1 No tienes una URL en tu objeto ajax, por lo que no enviará los datos a ningún lugar. Primero, deberías intentar usar console.log(msg) en lugar de alert(msg), no solo para tu tranquilidad, sino también porque registrar en la consola te da mejor acceso a cualquier cosa que necesites inspeccionar, alert bloquea y es solo texto. Una forma fácil de asegurarte de que tus manejadores de acciones ajax se están llamando correctamente es simplemente escribir dentro de la función manejadora ob_clean();echo "¡FUNCIONO!";wp_die();
Eso limpiará cualquier salida de otras funciones y devolverá solo "¡FUNCIONO!" al éxito de $.ajax si toda la solicitud está configurada correctamente.

está funcionando, ahora el menú desplegable funciona, el problema restante es el wp_dropdown_pages que no se filtra con el ID del padre.

@user3515709 Deberías convertir el $parent_id a un entero. Así quedaría como 'child_of' => (int)$parent_id,
Prefiero mantener mis $args en una variable en lugar de directamente en la llamada a la función para que en momentos de depuración pueda hacer un var_dump(), print_r(), var_export(), ahora que tienes el ajax funcionando, esos resultados volverán en la respuesta para que puedas depurar. Me voy por esta noche. Si logras que funcione, por favor marca mi respuesta como útil. Si necesitas más ayuda, puedes enviarme un correo a la dirección que dejé en los comentarios o podemos continuar en un chat mañana. Buena suerte
