get_terms не отображает product_cat или другие пользовательские таксономии при указании
Интересно, есть ли у вас идеи по этой проблеме. Я искал решение несколько дней, но не могу разобраться.
Вот моя ситуация:
У меня есть мета-бокс для типа записи Woocommerce 'products'. Внутри мета-бокса есть 'type' => 'select'
, который я хочу заполнить списком всех доступных 'taxonomy' => 'product_cat'
.
Я могу заполнить выпадающий список и работать со стандартными категориями записей, 'taxonomy' => 'category'
используя следующий код:
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;
}
Однако всё ломается, когда я пытаюсь использовать 'taxonomy' => 'product_cat'
или любую другую пользовательскую таксономию.
Я думал, что проблема в том, что я пытаюсь получить доступ к пользовательской таксономии до её регистрации, поэтому я поменял местами некоторые объявления/вызовы в моем файле function.php (те, которые вызывают CPT, мета-боксы и woocommece), чтобы потенциально изменить порядок выполнения, но безуспешно.
НО, основываясь на вопросе и ответе ниже, я теперь могу подтвердить, что функция может 'видеть' и отображать все термины во всех таксономиях. Если я исключу 'taxonomy =>'
из аргументов, она возвращает термины из всех пользовательских типов записей и таксономий.
В идеале базовая функция должна выглядеть так:
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;
}
Может у вас есть какие-то общие мысли? Я понимаю, что сложно без доступа ко всей кодовой базе, но решил спросить.
Версия Wordpress 4.7.2
Версия Woocommerce 2.6.14
ОБНОВЛЕНИЕ:
Постепенно я пытаюсь локализовать мою проблему.
Оказывается, что 'product_cat'
всё-таки доступен (хорошо), но он выводит массив, который не отображается правильно.
Это сбивает меня с толку, так как если я просто использую get_terms()
без параметров или указываю 'taxonomy' => 'category'
, код выше работает безупречно
Другие части кода, которые должны работать с этим:
Массив, в который я хотел бы поместить список опций
array(
'label'=> 'Collections',
'desc' => 'Select the collection you would like to display',
'id' => $prefix.'collection',
'type' => 'select',
'options' => product_cats()
),
код, который генерирует список выбора (используется для других мета-полей)
// 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;
У меня нет никаких проблем с работой или отображением других мета-полей, включая списки выбора.
Я бы предпочел не переписывать весь мета-бокс со всеми его полями, поэтому пытаюсь работать с тем, что есть на данный момент.

Возможно, вы используете старую версию WordPress (до 4.5).
До версии WordPress 4.5.0 первым параметром get_terms() была таксономия или список таксономий, а начиная с 4.5.0 таксономии должны передаваться через аргумент 'taxonomy' в массиве $args (именно так вы и делаете, это должно работать).
Все подробности об этих изменениях вы найдёте на странице справки get_terms().
ОБНОВЛЕНИЕ: Извините, я проверил свой код и использовал get_categories(), а не get_terms, и действительно get_terms() не работает!
Вот рабочий пример для вывода всех категорий товаров product_cat:
$product_categories = get_categories( array(
'taxonomy' => 'product_cat',
'orderby' => 'name',
'pad_counts' => false,
'hierarchical' => 1,
'hide_empty' => false
) );
Надеюсь, это поможет!

Версия WordPress: 4.7.2 (Я собираюсь добавить больше информации к первоначальным проблемам)

Безрезультатно, если вы хотите добавить meta_box на экран редактирования товара, используете ли вы действие add_meta_boxes или другое для вызова add_meta_box()?

Использую add_meta_boxes
. Я не думаю, что проблема в meta box, скорее в доступе к терминам product_cat

Как сказал вам Дейв Ромси в комментарии, это должно работать, у меня тоже работает.

Я просто не могу заставить это работать правильным способом. Как ни стараюсь, не могу разобраться с интеграцией.
Ранее я рассматривал wp_dropdown_categories()
и думал, что это лучшее (и более простое) решение. Я начал работать над текущей проблемой, потому что не смог понять, как заставить это работать с существующим синтаксисом метабоксов.
Пока я решил использовать временное решение, приведенное ниже. Оно не идеально и точно не лучший способ, но позволяет мне двигаться дальше с вызовом значений в шаблонах, которые будут использовать это поле.
// Обернуть все категории в функцию
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;
}
Буду обновлять по мере продвижения.

Вероятно, это не решит проблему, но хочу поделиться: сегодня я столкнулся с такой же проблемой, и она была вызвана отсутствием товаров в моих категориях. Если у вас аналогичная ситуация, убедитесь, что добавили параметр 'hide_empty' => false
.
Тем не менее. Когда вы вызываете get_terms()
без аргументов, какой результат получаете?

Добавление 'hide_empty' => false
вообще не помогает.
Что касается запуска get_terms()
вообще без аргументов, даже без указания таксономии, то я получаю огромный список ВСЕХ терминов из всех таксономий, включая product_cat
, к которому я пытаюсь получить доступ.
Это заставляет меня задуматься о сути проблемы, так как, похоже, он все-таки "видит" категории товаров.
Мне нужно будет провести несколько тестов, чтобы убедиться, что они действительно появляются.

Вот полностью рабочий пример метабокса, который отображает выпадающий список категорий товаров. Метабокс будет отображаться для типа записи "product" (товар).
add_action( 'add_meta_boxes', 'wpse256897_add_meta_box' );
add_action( 'save_post', 'wpse256897_save' );
/**
* Добавляет контейнер метабокса.
*/
function wpse256897_add_meta_box( $post_type ) {
// Ограничиваем метабокс определенными типами записей.
$post_types = array( 'product' );
if ( in_array( $post_type, $post_types ) ) {
add_meta_box(
'product_cat_selection',
__( 'Выбор категории товара', 'textdomain' ),
'wpse256897_render_meta_box_content',
$post_type,
'advanced',
'high'
);
}
}
/**
* Сохраняет метаданные при сохранении записи.
*
* @param int $post_id ID сохраняемой записи.
*/
function wpse256897_save( $post_id ) {
/*
* Нам нужно убедиться, что запрос пришел с нашего экрана и с правильными правами,
* так как save_post может срабатывать в других случаях.
*/
// Проверяем установлен ли nonce.
if ( ! isset( $_POST['myplugin_inner_custom_box_nonce'] ) {
return $post_id;
}
$nonce = $_POST['myplugin_inner_custom_box_nonce'];
// Проверяем валидность nonce.
if ( ! wp_verify_nonce( $nonce, 'myplugin_inner_custom_box' ) ) {
return $post_id;
}
/*
* Если это автосохранение, наша форма не была отправлена,
* поэтому ничего не делаем.
*/
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
// Проверяем права пользователя.
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, теперь безопасно сохранять данные. */
// Очищаем пользовательский ввод.
$mydata = sanitize_text_field( $_POST['product_cat_selection'] );
// Обновляем метаполе.
update_post_meta( $post_id, '_product_cat_selection', $mydata );
}
/**
* Отображает содержимое метабокса.
*
* @param WP_Post $post Объект записи.
*/
function wpse256897_render_meta_box_content( $post ) {
// Добавляем nonce поле для последующей проверки.
wp_nonce_field( 'myplugin_inner_custom_box', 'myplugin_inner_custom_box_nonce' );
// Используем get_post_meta для получения существующего значения из базы данных.
$current_product_cat = get_post_meta( $post->ID, '_product_cat_selection', true );
// Отображаем форму с текущим значением.
$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;
}
Это не самый элегантный пример (можно улучшить соглашения по именованию). Он был быстро адаптирован из примечаний на странице справки Add Meta Box, но демонстрирует, что функция wpse256897_product_cats()
действительно получает категории товаров, которые можно сохранить и отобразить в выпадающем списке на странице товара в метабоксе.
Также хочу добавить, что стоит обратить внимание на функцию wp_dropdown_categories()
. Несмотря на название, она работает и с пользовательскими таксономиями. Это избавит вас от необходимости создавать собственную разметку для выпадающего списка категорий.
Обновление:
Похоже, структура массива, возвращаемого функцией product_cats()
, не совсем соответствует вашей реализации метабокса. Обратите внимание, что в моем примере выше я использовал эту строку для перебора категорий при генерации элементов select:
foreach ( $product_cats as $product_cat_id => $product_cat ) { ?>
Это потому, что $product_cats
- это ассоциативный массив ID категорий, каждый из которых содержит другой массив с label
(названием) и slug
(ярлыком) для каждого ID категории.
Вы можете использовать эту альтернативную версию функции product_cats()
, которая форматирует возвращаемое значение $options в формате, совместимом с вашим кодом метабокса:
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;
}

Спасибо, Дэйв. Это помогло мне лучше понять, в чем моя реальная проблема (обновил исходный пост). Я бы хотел не переписывать весь метабокс (хотя если придется, значит придется), а попробовать работать с тем, что есть сейчас. Спасибо за помощь в понимании.
Примечание: я пробовал wp_dropdown_categories, но столкнулся с еще большими трудностями при попытке заполнить выпадающий список.
