/**
  * Loads an array of attributes used for variations, as well as their possible values.
  *
  * @param WC_Product
  */
 private function read_variation_attributes(&$product)
 {
     global $wpdb;
     $variation_attributes = array();
     $attributes = $product->get_attributes();
     $child_ids = $product->get_children();
     if (!empty($child_ids) && !empty($attributes)) {
         foreach ($attributes as $attribute) {
             if (empty($attribute['is_variation'])) {
                 continue;
             }
             // Get possible values for this attribute, for only visible variations.
             $values = array_unique($wpdb->get_col($wpdb->prepare("SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s AND post_id IN (" . implode(',', array_map('esc_sql', $child_ids)) . ")", wc_variation_attribute_name($attribute['name']))));
             // Empty value indicates that all options for given attribute are available.
             if (in_array('', $values) || empty($values)) {
                 $values = $attribute['is_taxonomy'] ? wc_get_object_terms($product->get_id(), $attribute['name'], 'slug') : wc_get_text_attributes($attribute['value']);
                 // Get custom attributes (non taxonomy) as defined.
             } elseif (!$attribute['is_taxonomy']) {
                 $text_attributes = wc_get_text_attributes($attribute['value']);
                 $assigned_text_attributes = $values;
                 $values = array();
                 // Pre 2.4 handling where 'slugs' were saved instead of the full text attribute
                 if (version_compare(get_post_meta($product->get_id(), '_product_version', true), '2.4.0', '<')) {
                     $assigned_text_attributes = array_map('sanitize_title', $assigned_text_attributes);
                     foreach ($text_attributes as $text_attribute) {
                         if (in_array(sanitize_title($text_attribute), $assigned_text_attributes)) {
                             $values[] = $text_attribute;
                         }
                     }
                 } else {
                     foreach ($text_attributes as $text_attribute) {
                         if (in_array($text_attribute, $assigned_text_attributes)) {
                             $values[] = $text_attribute;
                         }
                     }
                 }
             }
             $variation_attributes[$attribute['name']] = array_unique($values);
         }
     }
     $product->set_variation_attributes($variation_attributes);
 }
 /**
  * Get attribute options.
  *
  * @param int $product_id
  * @param array $attribute
  * @return array
  */
 protected function get_attribute_options($product_id, $attribute)
 {
     if (isset($attribute['is_taxonomy']) && $attribute['is_taxonomy']) {
         return wc_get_object_terms($product_id, $attribute['name'], 'name');
     } elseif (isset($attribute['value'])) {
         return array_map('trim', explode('|', $attribute['value']));
     }
     return array();
 }
/**
 * Wrapper for wp_get_post_terms which supports ordering by parent.
 *
 * NOTE: At this point in time, ordering by menu_order for example isn't possible with this function. wp_get_post_terms has no.
 *   filters which we can utilise to modify it's query. https://core.trac.wordpress.org/ticket/19094.
 *
 * @param  int    $product_id Product ID.
 * @param  string $taxonomy   Taxonomy slug.
 * @param  array  $args       Query arguments.
 * @return array
 */
function wc_get_product_terms($product_id, $taxonomy, $args = array())
{
    if (!taxonomy_exists($taxonomy)) {
        return array();
    }
    if (empty($args['orderby']) && taxonomy_is_product_attribute($taxonomy)) {
        $args['orderby'] = wc_attribute_orderby($taxonomy);
    }
    // Support ordering by parent.
    if (!empty($args['orderby']) && in_array($args['orderby'], array('name_num', 'parent'))) {
        $fields = isset($args['fields']) ? $args['fields'] : 'all';
        $orderby = $args['orderby'];
        // Unset for wp_get_post_terms.
        unset($args['orderby']);
        unset($args['fields']);
        $terms = _wc_get_cached_product_terms($product_id, $taxonomy, $args);
        switch ($orderby) {
            case 'name_num':
                usort($terms, '_wc_get_product_terms_name_num_usort_callback');
                break;
            case 'parent':
                usort($terms, '_wc_get_product_terms_parent_usort_callback');
                break;
        }
        switch ($fields) {
            case 'names':
                $terms = wp_list_pluck($terms, 'name');
                break;
            case 'ids':
                $terms = wp_list_pluck($terms, 'term_id');
                break;
            case 'slugs':
                $terms = wp_list_pluck($terms, 'slug');
                break;
        }
    } elseif (!empty($args['orderby']) && 'menu_order' === $args['orderby']) {
        // wp_get_post_terms doesn't let us use custom sort order.
        $args['include'] = wc_get_object_terms($product_id, $taxonomy, 'id');
        if (empty($args['include'])) {
            $terms = array();
        } else {
            // This isn't needed for get_terms.
            unset($args['orderby']);
            // Set args for get_terms.
            $args['menu_order'] = isset($args['order']) ? $args['order'] : 'ASC';
            $args['hide_empty'] = isset($args['hide_empty']) ? $args['hide_empty'] : 0;
            $args['fields'] = isset($args['fields']) ? $args['fields'] : 'names';
            // Ensure slugs is valid for get_terms - slugs isn't supported.
            $args['fields'] = 'slugs' === $args['fields'] ? 'id=>slug' : $args['fields'];
            $terms = get_terms($taxonomy, $args);
        }
    } else {
        $terms = _wc_get_cached_product_terms($product_id, $taxonomy, $args);
    }
    return apply_filters('woocommerce_get_product_terms', $terms, $product_id, $taxonomy, $args);
}
 /**
  * Count terms. These are done at this point so all product props are set in advance.
  *
  * @param WC_Product
  * @since 2.7.0
  */
 protected function update_term_counts(&$product)
 {
     if (!wp_defer_term_counting()) {
         global $wc_allow_term_recount;
         $wc_allow_term_recount = true;
         $post_type = $product->is_type('variation') ? 'product_variation' : 'product';
         // Update counts for the post's terms.
         foreach ((array) get_object_taxonomies($post_type) as $taxonomy) {
             $tt_ids = wc_get_object_terms($product->get_id(), $taxonomy, 'term_taxonomy_id');
             wp_update_term_count($tt_ids, $taxonomy);
         }
     }
 }
 /**
  * Output a list of variation attributes for use in the cart forms.
  *
  * @param array $args
  * @since 2.4.0
  */
 function wc_dropdown_variation_attribute_options($args = array())
 {
     $args = wp_parse_args(apply_filters('woocommerce_dropdown_variation_attribute_options_args', $args), array('options' => false, 'attribute' => false, 'product' => false, 'selected' => false, 'name' => '', 'id' => '', 'class' => '', 'show_option_none' => __('Choose an option', 'woocommerce')));
     $options = $args['options'];
     $product = $args['product'];
     $attribute = $args['attribute'];
     $name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title($attribute);
     $id = $args['id'] ? $args['id'] : sanitize_title($attribute);
     $class = $args['class'];
     $show_option_none = $args['show_option_none'] ? true : false;
     if (empty($options) && !empty($product) && !empty($attribute)) {
         $attributes = $product->get_variation_attributes();
         $options = $attributes[$attribute];
     }
     $html = '<select id="' . esc_attr($id) . '" class="' . esc_attr($class) . '" name="' . esc_attr($name) . '" data-attribute_name="attribute_' . esc_attr(sanitize_title($attribute)) . '" data-show_option_none="' . ($show_option_none ? 'yes' : 'no') . '">';
     if ($show_option_none) {
         $html .= '<option value="">' . esc_html($args['show_option_none']) . '</option>';
     }
     if (!empty($options)) {
         if ($product && taxonomy_exists($attribute)) {
             // Get terms if this is a taxonomy - ordered. We need the names too.
             $terms = wc_get_object_terms($product->get_id(), $attribute);
             foreach ($terms as $term) {
                 if (in_array($term->slug, $options)) {
                     $html .= '<option value="' . esc_attr($term->slug) . '" ' . selected(sanitize_title($args['selected']), $term->slug, false) . '>' . esc_html(apply_filters('woocommerce_variation_option_name', $term->name)) . '</option>';
                 }
             }
         } else {
             foreach ($options as $option) {
                 // This handles < 2.4.0 bw compatibility where text attributes were not sanitized.
                 $selected = sanitize_title($args['selected']) === $args['selected'] ? selected($args['selected'], sanitize_title($option), false) : selected($args['selected'], $option, false);
                 $html .= '<option value="' . esc_attr($option) . '" ' . $selected . '>' . esc_html(apply_filters('woocommerce_variation_option_name', $option)) . '</option>';
             }
         }
     }
     $html .= '</select>';
     echo apply_filters('woocommerce_dropdown_variation_attribute_options_html', $html, $args);
 }
 /**
  * Returns a single product attribute as a string.
  * @param  string $attribute to get.
  * @return string
  */
 public function get_attribute($attribute)
 {
     $attributes = $this->get_attributes();
     $attribute = sanitize_title($attribute);
     if (isset($attributes[$attribute])) {
         $attribute_object = $attributes[$attribute];
     } elseif (isset($attributes['pa_' . $attribute])) {
         $attribute_object = $attributes['pa_' . $attribute];
     } else {
         return '';
     }
     return $attribute_object->is_taxonomy() ? implode(', ', wc_get_object_terms($this->get_id(), $attribute_object->get_name(), 'name')) : wc_implode_text_attributes($attribute_object->get_options());
 }
 /**
  * Copy the taxonomies of a post to another post.
  *
  * @param mixed $id
  * @param mixed $new_id
  * @param mixed $post_type
  */
 private function duplicate_post_taxonomies($id, $new_id, $post_type)
 {
     $exclude = array_filter(apply_filters('woocommerce_duplicate_product_exclude_taxonomies', array()));
     $taxonomies = array_diff(get_object_taxonomies($post_type), $exclude);
     foreach ($taxonomies as $taxonomy) {
         $post_terms = wc_get_object_terms($id, $taxonomy);
         $post_terms_count = sizeof($post_terms);
         for ($i = 0; $i < $post_terms_count; $i++) {
             wp_set_object_terms($new_id, $post_terms[$i]->slug, $taxonomy, true);
         }
     }
 }
    _e('Dimensions', 'woocommerce');
    ?>
</th>
			<td class="product_dimensions"><?php 
    echo esc_html(wc_format_dimensions($product->get_dimensions(false)));
    ?>
</td>
		</tr>
	<?php 
}
?>

	<?php 
foreach ($attributes as $attribute) {
    ?>
		<tr>
			<th><?php 
    echo wc_attribute_label($attribute->get_name());
    ?>
</th>
			<td><?php 
    $values = $attribute->is_taxonomy() ? wc_get_object_terms($product->get_id(), $attribute->get_name(), 'name') : $attribute->get_options();
    echo apply_filters('woocommerce_attribute', wpautop(wptexturize(implode(', ', $values))), $attribute, $values);
    ?>
</td>
		</tr>
	<?php 
}
?>
</table>