2

Wondering if you might have some ideas on this problem. I’m googled for days but can’t figure it out.

Here’s where I’m at:

I have a meta box for the Woocommerce post type ‘products’. Inside the meta box there’s a 'type' = > 'select' that I want to populate with a list of all of the available 'taxonomy' = > 'product_cat'.

I can get the select box to populate and work with the standard post categories, 'taxonomy' = > 'category' using the following code:

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;
}

It all falls apart though when I try to use ‘taxonomy' = > ‘product_cat’ or any other custom taxonomy I have.

I thought the issue was that I’m trying to access the custom taxonomy before it’s being registered, so I swapped around some declarations/calls in my function.php file (ones which call the CPT, meta boxes, and woocommece) to potentially change the order that things run in but no luck.

BUT, based on the question and answer below, I can now confirm that the function can 'see' and display all terms, across taxonomies. If I exclude the 'taxonomy => from the arguments it returns terms from across custom post types and taxonomies.

Ideally the basic function would read:

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;
}

Just wondering if you had any general thoughts? I know it’s difficult without seeing the whole code base, but I thought it would be worth an ask.

Wordpress Version 4.7.2

Woocommerce Version 2.6.14

UPDATE:

Slowly I'm trying to pinpoint my issue.

It appears that 'product_cat' can be accessed after all (good) but it's spitting out an array that's not displaying properly.

This is confusing to me as if I simply use get_terms() without any parameters, or specifying 'taxonomy' => 'category' the code above works flawlessly

The other pieces of code that I need to work with this are:

The array that I'd like the list of options to dump in to

    array(  
        'label'=> 'Collections',
        'desc'  => 'Select the collection you would like to display',
        'id'    => $prefix.'collection',
        'type'    => 'select',  
        'options' => product_cats()
),

the code which generates the select list (used for other meta fields)

// 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;

I have zero issues with any other meta fields working or displaying, including select lists.

I'd rather no re-write the entire meta box with all of its fields so I'm trying to work with what I have at the moment.

5
  • Tested the code under Ideally the basic function would read: and it works for me. Product categories are listed within a meta box on the edit product page. WP 4.7.2, WC 2.6.9. Feb 17, 2017 at 20:44
  • Care to share the code? Because while your answer is helpful in saying it should work, it doesn't provide any useful information. Feb 17, 2017 at 20:46
  • Sure, can you do the same? Feb 17, 2017 at 20:47
  • Without sharing the code for the entire site there's not much more to share. The function works, to a point, so something is breaking down or missing within it. If there was additional code to the function I'd share it for sure. Feb 17, 2017 at 20:49
  • I'll see what else I can dig up. Feb 17, 2017 at 20:51

4 Answers 4

1

You are maybe running an old version of WordPress (before 4.5).

Before WordPress 4.5.0, the first parameter of get_terms() was a taxonomy or list of taxonomies and since 4.5.0, taxonomies should be passed via the ‘taxonomy’ argument in the $args array (that what you are doing, it should work like that).

You will find all the details about these changes in the get_terms() reference page.

UPDATE : Sorry, I verify my code, and I use get_categories() not get_terms, and that right get_terms() don't work !

here is a working example to list all my product_cat

$product_categories = get_categories( array(
    'taxonomy'     => 'product_cat',
    'orderby'      => 'name',
    'pad_counts'   => false,
    'hierarchical' => 1,
    'hide_empty'   => false
) );

Hope it helps !

5
  • Wordpress Version is: Version 4.7.2 (I'm going to add more to the initial issues) Feb 17, 2017 at 20:42
  • no luck, if you want to add a meta_box on the product edit screen, are you using the action add_meta_boxes or another one to trigger the add_meta_box() ?
    – Benoti
    Feb 17, 2017 at 20:46
  • using add_meta_boxes. I don't believe it's an issue with the meta box but rather accessing the product_cat terms Feb 17, 2017 at 20:47
  • As Dave Romsey, told you in the comment, it should work, work also for me.
    – Benoti
    Feb 17, 2017 at 20:49
  • I made an update on my answer.
    – Benoti
    Feb 17, 2017 at 21:08
1

For the life of me I really want to get this working the right way. For the life of me I can't figure the integration out.

Previously I had looked at wp_dropdown_categories() and thought it was a better (and easier) solution. I landed working on the problem above because I couldn't figure out how to get it to working with the existing meta box syntax.

For now I've decided on the temporary fix found below. It's not ideal and certainly not the best way, but it allows me to move forward with calling the values in the templates that will utilize this field.

// Wrap all categories in a function
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;
}

I'll update more as I move along.

0

This is probably not gonna fix it, but wanted to share: I ran into the same issue today and this was caused by not having any products in my categories. If this is the case for you too, make sure to add 'hide_empty' => false.

That said. When you run get_terms() without any arguments. What is the output?

2
  • Adding 'hide_empty' => false doesn't help at all. As for running get_terms() without any arguments at all, not even specifying the taxonomy, well I get a massive list of EVERY term, across all taxonomies it appears (including product_cat which I'm trying to access. Which leads me to know wonder what the issue is, as it appears to be 'seeing' the product categories after all. I'll need to do a bit of testing to see if they are actually appearing. Feb 17, 2017 at 19:57
  • Confirmed, If I exclude the 'taxonomy' => from the arguments it returns terms from across custom post types and taxonomies. Which is a step in the right direction. Feb 17, 2017 at 20:06
0

Here is a fully working example of a meta box that displays a product category select box. The meta box will appear on the product post type.

add_action( 'add_meta_boxes', 'wpse256897_add_meta_box' );
add_action( 'save_post',     'wpse256897_save' );
/**
 * Adds the meta box container.
 */
function wpse256897_add_meta_box( $post_type ) {
    // Limit meta box to certain post types.
    $post_types = array( 'product' );

    if ( in_array( $post_type, $post_types ) ) {
        add_meta_box(
            'product_cat_selection',
             __( 'Product Category Selection', 'textdomain' ),
             'wpse256897_render_meta_box_content',
             $post_type,
             'advanced',
             'high'
        );
    }
}

/**
 * Save the meta when the post is saved.
 *
 * @param int $post_id The ID of the post being saved.
 */
function wpse256897_save( $post_id ) {
    /*
     * We need to verify this came from the our screen and with proper authorization,
     * because save_post can be triggered at other times.
     */

    // Check if our nonce is set.
    if ( ! isset( $_POST['myplugin_inner_custom_box_nonce'] ) ) {
            return $post_id;
    }

    $nonce = $_POST['myplugin_inner_custom_box_nonce'];

    // Verify that the nonce is valid.
    if ( ! wp_verify_nonce( $nonce, 'myplugin_inner_custom_box' ) ) {
            return $post_id;
    }

    /*
     * If this is an autosave, our form has not been submitted,
     * so we don't want to do anything.
     */
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return $post_id;
    }

    // Check the user's permissions.
    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, it's safe for us to save the data now. */

    // Sanitize the user input.
    $mydata = sanitize_text_field( $_POST['product_cat_selection'] );

    // Update the meta field.
    update_post_meta( $post_id, '_product_cat_selection', $mydata );
}

/**
 * Render Meta Box content.
 *
 * @param WP_Post $post The post object.
 */
function wpse256897_render_meta_box_content( $post ) {
    // Add an nonce field so we can check for it later.
    wp_nonce_field( 'myplugin_inner_custom_box', 'myplugin_inner_custom_box_nonce' );

    // Use get_post_meta to retrieve an existing value from the database.
    $current_product_cat = get_post_meta( $post->ID, '_product_cat_selection', true );

    // Display the form, using the current value.
    $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;
}

This is not the most elegant example (the naming conventions could be better). It was quickly adapted from the contributed notes on the Add Meta Box reference page, but it does demonstrate that wpse256897_product_cats() does get the product categories and that they can be saved and displayed in a select box on the product page within a meta box.

I'd also like to add that it might be worth checking out the wp_dropdown_categories() function. Which, despite its name, works with custom taxonomies too. This would save you from creating your own category dropdown markup.

Update: It sounds like the structure of the array returned by the product_cats() function is not jiving with your meta box implementation. Notice that in my example above, I used this line to loop over the categories when generating the options for the select element:

foreach ( $product_cats as $product_cat_id => $product_cat ) { ?>

This is because $product_cats is an associative array of category ids which each hold another array containing the label and slug for each category id.

It looks like you could possibly use this alternate version of product_cats() which formats the return value $options in a way that is compatible with your metabox code:

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;
}
2
  • Thanks Dave. This helped me to better understand what my actual issue is (update the original post). I'd like to not have to update my entire meta box (although if I need to, I need to) but rather trying to work with what I have at the moment. Thank for helping me to understand. note: I tried wp_dropdown_categories but was struggling even more to have it populate a select list. Feb 18, 2017 at 2:06
  • You got it! I've added a little update to my original answer. Feb 18, 2017 at 2:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.