get_terms не отображает product_cat или другие пользовательские таксономии при указании

17 февр. 2017 г., 21:17:50
Просмотры: 22.3K
Голосов: 4

Интересно, есть ли у вас идеи по этой проблеме. Я искал решение несколько дней, но не могу разобраться.

Вот моя ситуация:

У меня есть мета-бокс для типа записи 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;

У меня нет никаких проблем с работой или отображением других мета-полей, включая списки выбора.

Я бы предпочел не переписывать весь мета-бокс со всеми его полями, поэтому пытаюсь работать с тем, что есть на данный момент.

5
Комментарии

Протестировал код под заголовком В идеале базовая функция должна выглядеть так:, и он работает для меня. Категории товаров отображаются в метабоксе на странице редактирования товара. WP 4.7.2, WC 2.6.9.

Dave Romsey Dave Romsey
17 февр. 2017 г. 22:44:14

Не поделитесь кодом? Хотя ваш ответ полезен, говоря, что это должно работать, он не предоставляет никакой полезной информации.

Kevin Van Lierop Kevin Van Lierop
17 февр. 2017 г. 22:46:35

Конечно, а вы сможете сделать то же самое?

Dave Romsey Dave Romsey
17 февр. 2017 г. 22:47:37

Не демонстрируя код всего сайта, больше особо нечем поделиться. Функция работает до определенного момента, поэтому что-то ломается или отсутствует внутри неё. Если бы был дополнительный код функции, я бы обязательно им поделился.

Kevin Van Lierop Kevin Van Lierop
17 февр. 2017 г. 22:49:38

Посмотрю, что ещё смогу найти.

Kevin Van Lierop Kevin Van Lierop
17 февр. 2017 г. 22:51:27
Все ответы на вопрос 4
5

Возможно, вы используете старую версию 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
) );

Надеюсь, это поможет!

17 февр. 2017 г. 22:37:03
Комментарии

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

Kevin Van Lierop Kevin Van Lierop
17 февр. 2017 г. 22:42:02

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

Benoti Benoti
17 февр. 2017 г. 22:46:40

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

Kevin Van Lierop Kevin Van Lierop
17 февр. 2017 г. 22:47:50

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

Benoti Benoti
17 февр. 2017 г. 22:49:57

Я обновил свой ответ.

Benoti Benoti
17 февр. 2017 г. 23:08:33
0

Я просто не могу заставить это работать правильным способом. Как ни стараюсь, не могу разобраться с интеграцией.

Ранее я рассматривал 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;
}

Буду обновлять по мере продвижения.

18 февр. 2017 г. 15:26:42
2

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

Тем не менее. Когда вы вызываете get_terms() без аргументов, какой результат получаете?

17 февр. 2017 г. 21:54:13
Комментарии

Добавление 'hide_empty' => false вообще не помогает.

Что касается запуска get_terms() вообще без аргументов, даже без указания таксономии, то я получаю огромный список ВСЕХ терминов из всех таксономий, включая product_cat, к которому я пытаюсь получить доступ.

Это заставляет меня задуматься о сути проблемы, так как, похоже, он все-таки "видит" категории товаров.

Мне нужно будет провести несколько тестов, чтобы убедиться, что они действительно появляются.

Kevin Van Lierop Kevin Van Lierop
17 февр. 2017 г. 21:57:23

Подтверждаю, если я исключаю 'taxonomy' => из аргументов, возвращаются термины из всех типов записей и таксономий.

Это шаг в правильном направлении.

Kevin Van Lierop Kevin Van Lierop
17 февр. 2017 г. 22:06:58
2

Вот полностью рабочий пример метабокса, который отображает выпадающий список категорий товаров. Метабокс будет отображаться для типа записи "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;
}
17 февр. 2017 г. 23:16:51
Комментарии

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

Примечание: я пробовал wp_dropdown_categories, но столкнулся с еще большими трудностями при попытке заполнить выпадающий список.

Kevin Van Lierop Kevin Van Lierop
18 февр. 2017 г. 04:06:56

Понял! Я добавил небольшое обновление к своему первоначальному ответу.

Dave Romsey Dave Romsey
18 февр. 2017 г. 04:34:48