get_terms no muestra product_cat ni otras taxonomías personalizadas cuando se especifican
Me pregunto si podrían tener algunas ideas sobre este problema. He estado buscando en Google durante días pero no puedo resolverlo.
Aquí es donde estoy:
Tengo una meta box para el tipo de post 'products' de Woocommerce. Dentro de la meta box hay un 'type' => 'select'
que quiero poblar con una lista de todos los 'taxonomy' => 'product_cat'
disponibles.
Puedo hacer que el select box se llene y funcione con las categorías estándar de posts, 'taxonomy' => 'category'
usando el siguiente código:
function product_cats() {
$options = array();
$categories = get_terms( array( 'taxonomy' => 'category' ) );
foreach( $categories as $category ) {
$options[$category->term_id] = array(
'label' => $category->name,
'value' => $category->slug
);
}
// return array('options'=>$options);
return $options;
}
Sin embargo, todo falla cuando intento usar 'taxonomy' => 'product_cat'
o cualquier otra taxonomía personalizada que tenga.
Pensé que el problema era que estaba intentando acceder a la taxonomía personalizada antes de que se registrara, así que intercambié algunas declaraciones/llamadas en mi archivo function.php (las que llaman al CPT, meta boxes y woocommerce) para potencialmente cambiar el orden en que se ejecutan las cosas, pero sin éxito.
PERO, basado en la pregunta y respuesta de abajo, ahora puedo confirmar que la función puede 'ver' y mostrar todos los términos, a través de las taxonomías. Si excluyo el 'taxonomy =>
de los argumentos, devuelve términos de todos los tipos de posts personalizados y taxonomías.
Idealmente la función básica sería:
function product_cats() {
$options = array();
$categories = get_terms( array( 'taxonomy' => 'product_cat' ) );
foreach( $categories as $category ) {
$options[$category->term_id] = array(
'label' => $category->name,
'value' => $category->slug
);
}
// return array('options'=>$options);
return $options;
}
¿Me pregunto si tienen alguna idea general? Sé que es difícil sin ver toda la base de código, pero pensé que valdría la pena preguntar.
Versión de Wordpress 4.7.2
Versión de Woocommerce 2.6.14
ACTUALIZACIÓN:
Poco a poco estoy tratando de identificar mi problema.
Parece que 'product_cat'
puede ser accedido después de todo (bueno) pero está devolviendo un array que no se muestra correctamente.
Esto me confunde ya que si simplemente uso get_terms()
sin ningún parámetro, o especificando 'taxonomy' => 'category'
el código anterior funciona perfectamente
Las otras piezas de código que necesito que funcionen con esto son:
El array donde me gustaría que se coloque la lista de opciones
array(
'label'=> 'Collections',
'desc' => 'Select the collection you would like to display',
'id' => $prefix.'collection',
'type' => 'select',
'options' => product_cats()
),
el código que genera la lista select (usado para otros campos meta)
// select
case 'select':
echo '<select name="'.$field['id'].'" id="'.$field['id'].'">';
foreach ($field['options'] as $option) {
echo '<option', $meta == $option['value'] ? ' selected="selected"' : '', ' value="'.$option['value'].'">'.$option['label'].'</option>';
}
echo '</select><br /><span class="description">'.$field['desc'].'</span>';
break;
No tengo ningún problema con otros campos meta que funcionan o se muestran, incluyendo las listas select.
Preferiría no reescribir toda la meta box con todos sus campos, así que estoy tratando de trabajar con lo que tengo en este momento.

Probablemente estás ejecutando una versión antigua de WordPress (anterior a la 4.5).
Antes de WordPress 4.5.0, el primer parámetro de get_terms() era una taxonomía o lista de taxonomías y desde la versión 4.5.0, las taxonomías deben pasarse mediante el argumento 'taxonomy' en el array $args (que es lo que estás haciendo, debería funcionar así).
Encontrarás todos los detalles sobre estos cambios en la página de referencia de get_terms().
ACTUALIZACIÓN: Lo siento, verifiqué mi código y uso get_categories() no get_terms, y es correcto que get_terms() no funciona.
Aquí tienes un ejemplo funcional para listar todas mis categorías de producto (product_cat):
$product_categories = get_categories( array(
'taxonomy' => 'product_cat', // Taxonomía a consultar
'orderby' => 'name', // Ordenar por nombre
'pad_counts' => false, // No incluir recuentos de hijos
'hierarchical' => 1, // Mostrar jerarquía
'hide_empty' => false // Mostrar categorías vacías
) );
¡Espero que te ayude!

Versión de Wordpress es: Versión 4.7.2 (Voy a agregar más a los problemas iniciales)

sin suerte, si quieres agregar un meta_box en la pantalla de edición de producto, ¿estás usando la acción add_meta_boxes u otra para activar el add_meta_box()?

usando add_meta_boxes
. No creo que sea un problema con el meta box sino más bien con acceder a los términos de product_cat

Como Dave Romsey te mencionó en el comentario, debería funcionar, también funciona para mí.

Por la vida mía, realmente quiero que esto funcione de la manera correcta. Por la vida mía, no logro entender la integración.
Anteriormente había considerado wp_dropdown_categories()
y pensé que era una solución mejor (y más fácil). Terminé trabajando en el problema anterior porque no pude averiguar cómo hacerlo funcionar con la sintaxis existente de las meta cajas.
Por ahora, he decidido implementar la solución temporal que se encuentra a continuación. No es ideal y ciertamente no es la mejor manera, pero me permite avanzar al llamar los valores en las plantillas que utilizarán este campo.
// Envolver todas las categorías en una función
function product_cats() {
$output = array();
$categories = get_terms( array(
'orderby' => 'name',
'pad_counts' => false,
'hierarchical' => 1,
'hide_empty' => true,
) );
foreach( $categories as $category ) {
if ($category->taxonomy == 'product_cat' ) {
$output[$category->slug] = array(
'label' => $category->name,
'value' => $category->slug
);
}
}
//return array('options'=>$output);
return $output;
}
Actualizaré más a medida que avance.

Probablemente esto no lo solucione, pero quería compartirlo: Me encontré con el mismo problema hoy y fue causado por no tener ningún producto en mis categorías. Si este también es tu caso, asegúrate de añadir 'hide_empty' => false
.
Dicho esto. Cuando ejecutas get_terms()
sin ningún argumento. ¿Cuál es el resultado?

Agregar 'hide_empty' => false
no ayuda en absoluto.
En cuanto a ejecutar get_terms()
sin ningún argumento, ni siquiera especificando la taxonomía, obtengo una lista masiva de TODOS los términos, a través de todas las taxonomías que aparecen (incluyendo product_cat
que es lo que estoy intentando acceder.
Lo que me lleva a preguntarme cuál es el problema, ya que parece estar 'viendo' las categorías de productos después de todo.
Necesitaré hacer algunas pruebas para ver si realmente están apareciendo.

Aquí hay un ejemplo completamente funcional de una meta caja que muestra un cuadro de selección de categorías de productos. La meta caja aparecerá en el tipo de entrada "product".
add_action( 'add_meta_boxes', 'wpse256897_add_meta_box' );
add_action( 'save_post', 'wpse256897_save' );
/**
* Añade el contenedor de la meta caja.
*/
function wpse256897_add_meta_box( $post_type ) {
// Limitar meta caja a ciertos tipos de entrada.
$post_types = array( 'product' );
if ( in_array( $post_type, $post_types ) ) {
add_meta_box(
'product_cat_selection',
__( 'Selección de Categoría de Producto', 'textdomain' ),
'wpse256897_render_meta_box_content',
$post_type,
'advanced',
'high'
);
}
}
/**
* Guarda los metadatos cuando se guarda la entrada.
*
* @param int $post_id El ID de la entrada que se está guardando.
*/
function wpse256897_save( $post_id ) {
/*
* Necesitamos verificar que esto venga de nuestra pantalla y con la autorización adecuada,
* porque save_post puede activarse en otros momentos.
*/
// Verificar si nuestro nonce está configurado.
if ( ! isset( $_POST['myplugin_inner_custom_box_nonce'] ) ) {
return $post_id;
}
$nonce = $_POST['myplugin_inner_custom_box_nonce'];
// Verificar que el nonce es válido.
if ( ! wp_verify_nonce( $nonce, 'myplugin_inner_custom_box' ) ) {
return $post_id;
}
/*
* Si esto es un autoguardado, nuestro formulario no ha sido enviado,
* así que no queremos hacer nada.
*/
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
// Verificar los permisos del usuario.
if ( 'page' == $_POST['post_type'] ) {
if ( ! current_user_can( 'edit_page', $post_id ) ) {
return $post_id;
}
} else {
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return $post_id;
}
}
/* OK, ahora es seguro guardar los datos. */
// Sanitizar la entrada del usuario.
$mydata = sanitize_text_field( $_POST['product_cat_selection'] );
// Actualizar el campo meta.
update_post_meta( $post_id, '_product_cat_selection', $mydata );
}
/**
* Renderiza el contenido de la Meta Caja.
*
* @param WP_Post $post El objeto de entrada.
*/
function wpse256897_render_meta_box_content( $post ) {
// Añadir un campo nonce para verificar más tarde.
wp_nonce_field( 'myplugin_inner_custom_box', 'myplugin_inner_custom_box_nonce' );
// Usar get_post_meta para recuperar un valor existente de la base de datos.
$current_product_cat = get_post_meta( $post->ID, '_product_cat_selection', true );
// Mostrar el formulario, usando el valor actual.
$product_cats = wpse256897_product_cats();
if ( !empty ( $product_cats ) ) {
echo '<select name="product_cat_selection" id="product_cat_selection">';
foreach ( $product_cats as $product_cat_id => $product_cat ) { ?>
<option value="<?php echo esc_attr( $product_cat['value'] ); ?>" <?php if ( isset ( $current_product_cat ) ) selected( $current_product_cat, $product_cat['value'] ); ?>><?php echo esc_html( $product_cat['label'] ); ?></option><?php
}
echo '</select>';
}
}
function wpse256897_product_cats() {
$options = array();
$categories = get_terms( array( 'taxonomy' => 'product_cat' ) );
foreach( $categories as $category ) {
$options[$category->term_id] = array(
'label' => $category->name,
'value' => $category->slug
);
}
return $options;
}
Este no es el ejemplo más elegante (las convenciones de nombres podrían ser mejores). Fue adaptado rápidamente de las notas contribuidas en la página de referencia de Add Meta Box, pero demuestra que wpse256897_product_cats()
obtiene las categorías de productos y que pueden guardarse y mostrarse en un cuadro de selección en la página de producto dentro de una meta caja.
También me gustaría añadir que podría valer la pena revisar la función wp_dropdown_categories()
. Que, a pesar de su nombre, también funciona con taxonomías personalizadas. Esto te ahorraría crear tu propio marcado de desplegable de categorías.
Actualización:
Parece que la estructura del array devuelto por la función product_cats()
no coincide con tu implementación de la meta caja. Fíjate que en mi ejemplo anterior, usé esta línea para recorrer las categorías al generar las opciones para el elemento select:
foreach ( $product_cats as $product_cat_id => $product_cat ) { ?>
Esto es porque $product_cats
es un array asociativo de IDs de categorías que cada uno contiene otro array con la label
(etiqueta) y el slug
para cada ID de categoría.
Parece que podrías usar esta versión alternativa de product_cats()
que formatea el valor de retorno $options de una manera compatible con tu código de metabox:
function product_cats_alternate() {
$options = array();
$categories = get_terms( array( 'taxonomy' => 'product_cat' ) );
foreach( $categories as $category ) {
$options[] = array(
'label' => $category->name,
'value' => $category->slug
);
}
return $options;
}

Gracias Dave. Esto me ayudó a entender mejor cuál es mi problema real (actualicé la publicación original). Preferiría no tener que actualizar todo mi meta box (aunque si es necesario, lo haré) sino intentar trabajar con lo que tengo en este momento. Gracias por ayudarme a entender.
Nota: Intenté usar wp_dropdown_categories pero tuve aún más dificultades para que poblara una lista de selección.
