[Product CRUD] Abstract todos (#12305)

* Get dimensions and weights, with soft deprecation

* Product attributes

* Ratings

* Fix read method

* Downloads

* Feedback
This commit is contained in:
Mike Jolley 2016-11-11 11:43:52 +00:00 committed by GitHub
parent 1fb8479358
commit 9a6136fcf8
24 changed files with 742 additions and 416 deletions

File diff suppressed because one or more lines are too long

View File

@ -1024,8 +1024,8 @@ p.demo_store,
}
}
.alt td,
.alt th {
tr:nth-child(even) td,
tr:nth-child(even) th {
background: rgba(0, 0, 0, 0.025);
}
}

View File

@ -661,4 +661,61 @@ abstract class WC_Abstract_Legacy_Product extends WC_Data {
_deprecated_function( 'WC_Product::get_matching_variation', '2.7', 'wc_find_matching_product_variation' );
return wc_find_matching_product_variation( $this, $match_attributes );
}
/**
* Returns whether or not we are showing dimensions on the product page.
* @deprecated 2.7.0 Unused.
* @return bool
*/
public function enable_dimensions_display() {
_deprecated_function( 'WC_Product::enable_dimensions_display', '2.7' );
return apply_filters( 'wc_product_enable_dimensions_display', true ) && ( $this->has_dimensions() || $this->has_weight() || $this->child_has_weight() || $this->child_has_dimensions() );
}
/**
* Returns the product rating in html format.
*
* @deprecated 2.7.0
* @param string $rating (default: '')
* @return string
*/
public function get_rating_html( $rating = null ) {
_deprecated_function( 'WC_Product::get_rating_html', '2.7', 'wc_get_rating_html' );
return wc_get_rating_html( $rating );
}
/**
* Sync product rating. Can be called statically.
*
* @deprecated 2.7.0
* @param int $post_id
*/
public static function sync_average_rating( $post_id ) {
_deprecated_function( 'WC_Product::sync_average_rating', '2.7', 'WC_Comments::get_average_rating_for_product or leave to CRUD.' );
$average = WC_Comments::get_average_rating_for_product( wc_get_product( $post_id ) );
update_post_meta( $post_id, '_wc_average_rating', $average );
}
/**
* Sync product rating count. Can be called statically.
*
* @deprecated 2.7.0
* @param int $post_id
*/
public static function sync_rating_count( $post_id ) {
_deprecated_function( 'WC_Product::sync_rating_count', '2.7', 'WC_Comments::get_rating_counts_for_product or leave to CRUD.' );
$counts = WC_Comments::get_rating_counts_for_product( wc_get_product( $post_id ) );
update_post_meta( $post_id, '_wc_rating_count', $counts );
}
/**
* Same as get_downloads in CRUD.
*
* @deprecated 2.7.0
* @return array
*/
public function get_files() {
wc_soft_deprecated_function( 'WC_Product::get_files', '2.7', '2.8', 'WC_Product::get_downloads' );
return $this->get_downloads();
}
}

View File

@ -78,6 +78,9 @@ class WC_Product extends WC_Abstract_Legacy_Product {
'gallery_image_ids' => array(),
'download_limit' => -1,
'download_expiry' => -1,
'rating_counts' => array(),
'average_rating' => 0,
'review_count' => 0,
);
/**
@ -473,6 +476,24 @@ class WC_Product extends WC_Abstract_Legacy_Product {
return $this->get_prop( 'height', $context );
}
/**
* Returns formatted dimensions.
*
* @param $formatted True by default for legacy support - will be false/not set in future versions to return the array only. Use wc_format_dimensions for formatted versions instead.
* @return string|array
*/
public function get_dimensions( $formatted = true ) {
if ( $formatted ) {
wc_soft_deprecated_argument( 'WC_Product::get_dimensions', '2.7', '2.8', 'By default, get_dimensions has an argument set to true so that HTML is returned. This is to support the legacy version of the method. To get HTML dimensions, instead use wc_format_dimensions() function. Pass false to this method to return an array of dimensions. This will be the new default behavior in future versions.' );
return apply_filters( 'woocommerce_product_dimensions', wc_format_dimensions( $this->get_dimensions( false ) ), $this );
}
return array(
'length' => $this->get_length(),
'width' => $this->get_width(),
'height' => $this->get_height(),
);
}
/**
* Get upsel IDs.
*
@ -669,6 +690,33 @@ class WC_Product extends WC_Abstract_Legacy_Product {
return $this->get_prop( 'image_id', $context );
}
/**
* Get rating count.
* @param string $context
* @return array of counts
*/
public function get_rating_counts( $context = 'view' ) {
return $this->get_prop( 'rating_counts', $context );
}
/**
* Get average rating.
* @param string $context
* @return float
*/
public function get_average_rating( $context = 'view' ) {
return $this->get_prop( 'average_rating', $context );
}
/**
* Get review count.
* @param string $context
* @return int
*/
public function get_review_count( $context = 'view' ) {
return $this->get_prop( 'review_count', $context );
}
/*
|--------------------------------------------------------------------------
| Setters
@ -1124,65 +1172,42 @@ class WC_Product extends WC_Abstract_Legacy_Product {
* Set downloads.
*
* @since 2.7.0
* @param $raw_downloads array of arrays with download data (name/file)
* @param $downloads_array array of WC_Product_Download objects or arrays.
*/
public function set_downloads( $raw_downloads ) {
public function set_downloads( $downloads_array ) {
$downloads = array();
$errors = array();
$allowed_file_types = apply_filters( 'woocommerce_downloadable_file_allowed_mime_types', get_allowed_mime_types() );
foreach ( $raw_downloads as $raw_download ) {
$file_name = wc_clean( $raw_download['name'] );
// Find type and file URL
if ( 0 === strpos( $raw_download['file'], 'http' ) ) {
$file_is = 'absolute';
$file_url = esc_url_raw( $raw_download['file'] );
} elseif ( '[' === substr( $raw_download['file'], 0, 1 ) && ']' === substr( $raw_download['file'], -1 ) ) {
$file_is = 'shortcode';
$file_url = wc_clean( $raw_download['file'] );
foreach ( $downloads_array as $download ) {
if ( is_a( $download, 'WC_Product_Download' ) ) {
$download_object = $download;
} else {
$file_is = 'relative';
$file_url = wc_clean( $raw_download['file'] );
$download_object = new WC_Product_Download();
$download_object->set_id( md5( $download['file'] ) );
$download_object->set_name( $download['name'] );
$download_object->set_file( $download['file'] );
}
$file_name = wc_clean( $raw_download['name'] );
// Validate the file extension
if ( in_array( $file_is, array( 'absolute', 'relative' ) ) ) {
$file_type = wp_check_filetype( strtok( $file_url, '?' ), $allowed_file_types );
$parsed_url = parse_url( $file_url, PHP_URL_PATH );
$extension = pathinfo( $parsed_url, PATHINFO_EXTENSION );
if ( ! empty( $extension ) && ! in_array( $file_type['type'], $allowed_file_types ) ) {
$errors[] = sprintf( __( 'The downloadable file %1$s cannot be used as it does not have an allowed file type. Allowed types include: %2$s', 'woocommerce' ), '<code>' . basename( $file_url ) . '</code>', '<code>' . implode( ', ', array_keys( $allowed_file_types ) ) . '</code>' );
if ( ! $download_object->is_allowed_filetype() ) {
$errors[] = sprintf( __( 'The downloadable file %1$s cannot be used as it does not have an allowed file type. Allowed types include: %2$s', 'woocommerce' ), '<code>' . basename( $download_object->get_file() ) . '</code>', '<code>' . implode( ', ', array_keys( $download_object->get_allowed_mime_types() ) ) . '</code>' );
continue;
}
}
// Validate the file exists.
if ( 'relative' === $file_is ) {
$_file_url = $file_url;
if ( '..' === substr( $file_url, 0, 2 ) || '/' !== substr( $file_url, 0, 1 ) ) {
$_file_url = realpath( ABSPATH . $file_url );
}
if ( ! apply_filters( 'woocommerce_downloadable_file_exists', file_exists( $_file_url ), $file_url ) ) {
$errors[] = sprintf( __( 'The downloadable file %s cannot be used as it does not exist on the server.', 'woocommerce' ), '<code>' . $file_url . '</code>' );
if ( ! $download_object->file_exists() ) {
$errors[] = sprintf( __( 'The downloadable file %s cannot be used as it does not exist on the server.', 'woocommerce' ), '<code>' . $download_object->get_file() . '</code>' );
continue;
}
}
$downloads[ md5( $file_url ) ] = array(
'name' => $file_name,
'file' => $file_url,
);
$downloads[ $download_object->get_id() ] = $download_object;
}
$this->set_prop( 'downloads', $downloads );
if ( $errors ) {
$this->error( 'product_invalid_download', $errors[0] );
}
$this->set_prop( 'downloads', $downloads );
}
/**
@ -1225,6 +1250,30 @@ class WC_Product extends WC_Abstract_Legacy_Product {
$this->set_prop( 'image_id', $image_id );
}
/**
* Set rating counts. Read only.
* @param array $counts
*/
protected function set_rating_counts( $counts ) {
$this->set_prop( 'rating_counts', array_filter( array_map( 'absint', (array) $counts ) ) );
}
/**
* Set average rating. Read only.
* @param float $average
*/
protected function set_average_rating( $average ) {
$this->set_prop( 'average_rating', wc_format_decimal( $average ) );
}
/**
* Set review count. Read only.
* @param int $count
*/
protected function set_review_count( $count ) {
$this->set_prop( 'review_count', absint( $count ) );
}
/*
|--------------------------------------------------------------------------
| CRUD methods
@ -1304,6 +1353,7 @@ class WC_Product extends WC_Abstract_Legacy_Product {
) );
$this->read_meta_data();
$this->read_attributes();
$this->read_downloads();
$this->read_product_data();
// Set object_read true once all data is read.
@ -1317,6 +1367,25 @@ class WC_Product extends WC_Abstract_Legacy_Product {
*/
protected function read_product_data() {
$id = $this->get_id();
$review_count = get_post_meta( $id, '_wc_review_count', true );
$rating_counts = get_post_meta( $id, '_wc_rating_count', true );
$average_rating = get_post_meta( $id, '_wc_average_rating', true );
if ( '' === $review_count ) {
$review_count = WC_Comments::get_review_count_for_product( $this );
}
if ( '' === $rating_counts ) {
$rating_counts = WC_Comments::get_rating_counts_for_product( $this );
}
if ( '' === $average_rating ) {
$average_rating = WC_Comments::get_average_rating_for_product( $this );
}
$this->set_average_rating( $average_rating );
$this->set_rating_counts( $rating_counts );
$this->set_review_count( $review_count );
$this->set_props( array(
'featured' => get_post_meta( $id, '_featured', true ),
'catalog_visibility' => get_post_meta( $id, '_visibility', true ),
@ -1347,7 +1416,6 @@ class WC_Product extends WC_Abstract_Legacy_Product {
'shipping_class_id' => current( $this->get_term_ids( 'product_shipping_class' ) ),
'virtual' => get_post_meta( $id, '_virtual', true ),
'downloadable' => get_post_meta( $id, '_downloadable', true ),
'downloads' => array_filter( (array) get_post_meta( $id, '_downloadable_files', true ) ),
'gallery_image_ids' => array_filter( explode( ',', get_post_meta( $id, '_product_image_gallery', true ) ) ),
'download_limit' => get_post_meta( $id, '_download_limit', true ),
'download_expiry' => get_post_meta( $id, '_download_expiry', true ),
@ -1355,6 +1423,27 @@ class WC_Product extends WC_Abstract_Legacy_Product {
) );
}
/**
* Read downloads from post meta.
*
* @since 2.7.0
*/
protected function read_downloads() {
$meta_values = array_filter( (array) maybe_unserialize( get_post_meta( $this->get_id(), '_downloadable_files', true ) ) );
if ( $meta_values ) {
$downloads = array();
foreach ( $meta_values as $key => $value ) {
$download = new WC_Product_Download();
$download->set_id( $key );
$download->set_name( $value['name'] ? $value['name'] : wc_get_filename_from_url( $value['file'] ) );
$download->set_file( apply_filters( 'woocommerce_file_download_path', $value['file'], $this, $key ) );
$downloads[] = $download;
}
$this->set_downloads( $downloads );
}
}
/**
* Read attributes from post meta.
*
@ -1415,6 +1504,7 @@ class WC_Product extends WC_Abstract_Legacy_Product {
$this->update_post_meta();
$this->update_terms();
$this->update_attributes();
$this->update_downloads();
$this->save_meta_data();
do_action( 'woocommerce_new_' . $this->post_type, $id );
}
@ -1440,6 +1530,7 @@ class WC_Product extends WC_Abstract_Legacy_Product {
$this->update_post_meta();
$this->update_terms();
$this->update_attributes();
$this->update_downloads();
$this->save_meta_data();
do_action( 'woocommerce_update_' . $this->post_type, $this->get_id() );
}
@ -1578,8 +1669,10 @@ class WC_Product extends WC_Abstract_Legacy_Product {
'_downloadable_files' => 'downloads',
'_stock' => 'stock_quantity',
'_stock_status' => 'stock_status',
'_wc_average_rating' => 'average_rating',
'_wc_rating_count' => 'rating_counts',
'_wc_review_count' => 'review_count',
);
foreach ( $meta_key_to_props as $meta_key => $prop ) {
if ( ! in_array( $prop, $changed_props ) ) {
continue;
@ -1596,6 +1689,15 @@ class WC_Product extends WC_Abstract_Legacy_Product {
case 'gallery_image_ids' :
$updated = update_post_meta( $this->get_id(), $meta_key, implode( ',', $value ) );
break;
case 'downloads' :
// grant permission to any newly added files on any existing orders for this product prior to saving.
if ( $this->is_type( 'variation' ) ) {
do_action( 'woocommerce_process_product_file_download_paths', $this->get_parent_id(), $this->get_id(), $value );
} else {
do_action( 'woocommerce_process_product_file_download_paths', $this->get_id(), 0, $value );
}
$updated = update_post_meta( $this->get_id(), $meta_key, $value );
break;
case 'image_id' :
if ( ! empty( $value ) ) {
set_post_thumbnail( $this->get_id(), $value );
@ -1629,15 +1731,6 @@ class WC_Product extends WC_Abstract_Legacy_Product {
do_action( 'woocommerce_product_set_visibility', $this->get_id(), $this->get_catalog_visibility() );
}
if ( in_array( 'downloads', $updated_props ) ) {
// grant permission to any newly added files on any existing orders for this product prior to saving.
if ( $this->is_type( 'variation' ) ) {
do_action( 'woocommerce_process_product_file_download_paths', $this->get_parent_id(), $this->get_id(), $this->get_downloads() );
} else {
do_action( 'woocommerce_process_product_file_download_paths', $this->get_id(), 0, $this->get_downloads() );
}
}
if ( in_array( 'stock_quantity', $updated_props ) ) {
do_action( $this->is_type( 'variation' ) ? 'woocommerce_variation_set_stock' : 'woocommerce_product_set_stock' , $this );
}
@ -1699,6 +1792,24 @@ class WC_Product extends WC_Abstract_Legacy_Product {
update_post_meta( $this->get_id(), '_product_attributes', $meta_values );
}
/**
* Update downloads.
*
* @since 2.7.0
*/
protected function update_downloads() {
$downloads = $this->get_downloads();
$meta_values = array();
if ( $downloads ) {
foreach ( $downloads as $key => $download ) {
// Store in format WC uses in meta.
$meta_values[ $key ] = $download->get_data();
}
}
update_post_meta( $this->get_id(), '_downloadable_files', $meta_values );
}
/*
|--------------------------------------------------------------------------
| Conditionals
@ -1831,7 +1942,7 @@ class WC_Product extends WC_Abstract_Legacy_Product {
* @return bool
*/
public function has_dimensions() {
return $this->get_length() || $this->get_height() || $this->get_width();
return ( $this->get_length() || $this->get_height() || $this->get_width() ) && ! $this->get_virtual();
}
/**
@ -1840,7 +1951,7 @@ class WC_Product extends WC_Abstract_Legacy_Product {
* @return bool
*/
public function has_weight() {
return $this->get_weight() ? true : false;
return $this->get_weight() && ! $this->get_virtual();
}
/**
@ -1929,15 +2040,6 @@ class WC_Product extends WC_Abstract_Legacy_Product {
return ! $this->managing_stock() || $this->backorders_allowed() || $this->get_stock_quantity() >= $quantity;
}
/**
* Returns whether or not we are showing dimensions on the product page.
*
* @return bool
*/
public function enable_dimensions_display() {
return apply_filters( 'wc_product_enable_dimensions_display', ! $this->get_virtual() ) && ( $this->has_dimensions() || $this->has_weight() );
}
/**
* Returns whether or not the product has any visible attributes.
*
@ -1961,6 +2063,38 @@ class WC_Product extends WC_Abstract_Legacy_Product {
return 0 < count( $this->get_children() );
}
/**
* Does a child have dimensions?
*
* @since 2.7.0
* @return bool
*/
public function child_has_dimensions() {
return false;
}
/**
* Does a child have a weight?
*
* @since 2.7.0
* @return boolean
*/
public function child_has_weight() {
return false;
}
/**
* Check if downloadable product has a file attached.
*
* @since 1.6.2
*
* @param string $download_id file identifier
* @return bool Whether downloadable product has a file attached.
*/
public function has_file( $download_id = '' ) {
return $this->is_downloadable() && $this->get_file( $download_id );
}
/*
|--------------------------------------------------------------------------
| Non-CRUD Getters
@ -2108,56 +2242,21 @@ class WC_Product extends WC_Abstract_Legacy_Product {
return $attribute_object->is_taxonomy() ? implode( ', ', wc_get_product_terms( $this->get_id(), $attribute_object->get_name(), array( 'fields' => 'names' ) ) ) : wc_implode_text_attributes( $attribute_object->get_options() );
}
/*
|--------------------------------------------------------------------------
| @todo download functions
|--------------------------------------------------------------------------
*/
/**
* Check if downloadable product has a file attached.
*
* @since 1.6.2
*
* @param string $download_id file identifier
* @return bool Whether downloadable product has a file attached.
* Get the total amount (COUNT) of ratings, or just the count for one rating e.g. number of 5 star ratings.
* @param int $value Optional. Rating value to get the count for. By default returns the count of all rating values.
* @return int
*/
public function has_file( $download_id = '' ) {
return ( $this->is_downloadable() && $this->get_file( $download_id ) ) ? true : false;
public function get_rating_count( $value = null ) {
$counts = $this->get_rating_counts();
if ( is_null( $value ) ) {
return array_sum( $counts );
} elseif ( isset( $counts[ $value ] ) ) {
return absint( $counts[ $value ] );
} else {
return 0;
}
/**
* Gets an array of downloadable files for this product.
*
* @since 2.1.0
*
* @return array
*/
public function get_files() {
$downloads = $this->get_downloads();
$downloadable_files = array_filter( ! empty( $downloads ) ? (array) maybe_unserialize( $downloads ) : array() );
if ( ! empty( $downloadable_files ) ) {
foreach ( $downloadable_files as $key => $file ) {
if ( ! is_array( $file ) ) {
$downloadable_files[ $key ] = array(
'file' => $file,
'name' => '',
);
}
// Set default name
if ( empty( $file['name'] ) ) {
$downloadable_files[ $key ]['name'] = wc_get_filename_from_url( $file['file'] );
}
// Filter URL
$downloadable_files[ $key ]['file'] = apply_filters( 'woocommerce_file_download_path', $downloadable_files[ $key ]['file'], $this, $key );
}
}
return apply_filters( 'woocommerce_product_files', $downloadable_files, $this );
}
/**
@ -2167,8 +2266,7 @@ class WC_Product extends WC_Abstract_Legacy_Product {
* @return array|false if not found
*/
public function get_file( $download_id = '' ) {
$files = $this->get_files();
$files = $this->get_downloads();
if ( '' === $download_id ) {
$file = sizeof( $files ) ? current( $files ) : false;
@ -2178,7 +2276,6 @@ class WC_Product extends WC_Abstract_Legacy_Product {
$file = false;
}
// allow overriding based on the particular file being requested
return apply_filters( 'woocommerce_product_file', $file, $this, $download_id );
}
@ -2189,197 +2286,10 @@ class WC_Product extends WC_Abstract_Legacy_Product {
* @return string
*/
public function get_file_download_path( $download_id ) {
$files = $this->get_files();
if ( isset( $files[ $download_id ] ) ) {
$file_path = $files[ $download_id ]['file'];
} else {
$file_path = '';
}
$files = $this->get_downloads();
$file_path = isset( $files[ $download_id ] ) ? $files[ $download_id ]->get_file() : '';
// allow overriding based on the particular file being requested
return apply_filters( 'woocommerce_product_file_download_path', $file_path, $this, $download_id );
}
/*
|--------------------------------------------------------------------------
| @todo misc
|--------------------------------------------------------------------------
*/
/**
* Does a child have dimensions set?
*
* @since 2.7.0
* @return bool
*/
public function child_has_dimensions() {
return false;
}
/**
* Does a child have a weight set?
* @since 2.7.0
* @return boolean
*/
public function child_has_weight() {
return false;
}
/**
* Returns formatted dimensions.
* @return string
*/
public function get_dimensions() {
$dimensions = implode( ' x ', array_filter( array(
wc_format_localized_decimal( $this->get_length() ),
wc_format_localized_decimal( $this->get_width() ),
wc_format_localized_decimal( $this->get_height() ),
) ) );
if ( ! empty( $dimensions ) ) {
$dimensions .= ' ' . get_option( 'woocommerce_dimension_unit' );
}
return apply_filters( 'woocommerce_product_dimensions', $dimensions, $this );
}
/**
* Get the average rating of product. This is calculated once and stored in postmeta.
* @return string
*/
public function get_average_rating() {
// No meta data? Do the calculation
if ( ! metadata_exists( 'post', $this->get_id(), '_wc_average_rating' ) ) {
$this->sync_average_rating( $this->get_id() );
}
return (string) floatval( get_post_meta( $this->get_id(), '_wc_average_rating', true ) );
}
/**
* Get the total amount (COUNT) of ratings.
* @param int $value Optional. Rating value to get the count for. By default returns the count of all rating values.
* @return int
*/
public function get_rating_count( $value = null ) {
// No meta data? Do the calculation
if ( ! metadata_exists( 'post', $this->get_id(), '_wc_rating_count' ) ) {
$this->sync_rating_count( $this->get_id() );
}
$counts = get_post_meta( $this->get_id(), '_wc_rating_count', true );
if ( is_null( $value ) ) {
return array_sum( $counts );
} else {
return isset( $counts[ $value ] ) ? $counts[ $value ] : 0;
}
}
/**
* Sync product rating. Can be called statically.
* @param int $post_id
*/
public static function sync_average_rating( $post_id ) {
if ( ! metadata_exists( 'post', $post_id, '_wc_rating_count' ) ) {
self::sync_rating_count( $post_id );
}
$count = array_sum( (array) get_post_meta( $post_id, '_wc_rating_count', true ) );
if ( $count ) {
global $wpdb;
$ratings = $wpdb->get_var( $wpdb->prepare("
SELECT SUM(meta_value) FROM $wpdb->commentmeta
LEFT JOIN $wpdb->comments ON $wpdb->commentmeta.comment_id = $wpdb->comments.comment_ID
WHERE meta_key = 'rating'
AND comment_post_ID = %d
AND comment_approved = '1'
AND meta_value > 0
", $post_id ) );
$average = number_format( $ratings / $count, 2, '.', '' );
} else {
$average = 0;
}
update_post_meta( $post_id, '_wc_average_rating', $average );
}
/**
* Sync product rating count. Can be called statically.
* @param int $post_id
*/
public static function sync_rating_count( $post_id ) {
global $wpdb;
$counts = array();
$raw_counts = $wpdb->get_results( $wpdb->prepare( "
SELECT meta_value, COUNT( * ) as meta_value_count FROM $wpdb->commentmeta
LEFT JOIN $wpdb->comments ON $wpdb->commentmeta.comment_id = $wpdb->comments.comment_ID
WHERE meta_key = 'rating'
AND comment_post_ID = %d
AND comment_approved = '1'
AND meta_value > 0
GROUP BY meta_value
", $post_id ) );
foreach ( $raw_counts as $count ) {
$counts[ $count->meta_value ] = $count->meta_value_count;
}
update_post_meta( $post_id, '_wc_rating_count', $counts );
}
/**
* Returns the product rating in html format.
*
* @param string $rating (default: '')
*
* @return string
*/
public function get_rating_html( $rating = null ) {
$rating_html = '';
if ( ! is_numeric( $rating ) ) {
$rating = $this->get_average_rating();
}
if ( $rating > 0 ) {
$rating_html = '<div class="star-rating" title="' . sprintf( __( 'Rated %s out of 5', 'woocommerce' ), $rating ) . '">';
$rating_html .= '<span style="width:' . ( ( $rating / 5 ) * 100 ) . '%"><strong class="rating">' . $rating . '</strong> ' . __( 'out of 5', 'woocommerce' ) . '</span>';
$rating_html .= '</div>';
}
return apply_filters( 'woocommerce_product_get_rating_html', $rating_html, $rating );
}
/**
* Get the total amount (COUNT) of reviews.
*
* @since 2.3.2
* @return int The total numver of product reviews
*/
public function get_review_count() {
global $wpdb;
// No meta date? Do the calculation
if ( ! metadata_exists( 'post', $this->get_id(), '_wc_review_count' ) ) {
$count = $wpdb->get_var( $wpdb->prepare("
SELECT COUNT(*) FROM $wpdb->comments
WHERE comment_parent = 0
AND comment_post_ID = %d
AND comment_approved = '1'
", $this->get_id() ) );
update_post_meta( $this->get_id(), '_wc_review_count', $count );
} else {
$count = get_post_meta( $this->get_id(), '_wc_review_count', true );
}
return apply_filters( 'woocommerce_product_review_count', $count, $this );
}
}

View File

@ -2247,7 +2247,7 @@ class WC_Admin_Post_Types {
}
$product = wc_get_product( $product_id );
$existing_download_ids = array_keys( (array) $product->get_files() );
$existing_download_ids = array_keys( (array) $product->get_downloads() );
$updated_download_ids = array_keys( (array) $downloadable_files );
$new_download_ids = array_filter( array_diff( $updated_download_ids, $existing_download_ids ) );

View File

@ -238,7 +238,7 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
$downloads = array();
if ( $product->is_downloadable() ) {
foreach ( $product->get_files() as $file_id => $file ) {
foreach ( $product->get_downloads() as $file_id => $file ) {
$downloads[] = array(
'id' => $file_id, // MD5 hash.
'name' => $file['name'],

View File

@ -533,7 +533,7 @@ class WC_API_Products extends WC_API_Resource {
if ( $product->is_downloadable() ) {
foreach ( $product->get_files() as $file_id => $file ) {
foreach ( $product->get_downloads() as $file_id => $file ) {
$downloads[] = array(
'id' => $file_id, // do not cast as int as this is a hash

View File

@ -1944,7 +1944,7 @@ class WC_API_Products extends WC_API_Resource {
if ( $product->is_downloadable() ) {
foreach ( $product->get_files() as $file_id => $file ) {
foreach ( $product->get_downloads() as $file_id => $file ) {
$downloads[] = array(
'id' => $file_id, // do not cast as int as this is a hash

View File

@ -2529,7 +2529,7 @@ class WC_API_Products extends WC_API_Resource {
if ( $product->is_downloadable() ) {
foreach ( $product->get_files() as $file_id => $file ) {
foreach ( $product->get_downloads() as $file_id => $file ) {
$downloads[] = array(
'id' => $file_id, // do not cast as int as this is a hash

View File

@ -781,7 +781,7 @@ class WC_AJAX {
foreach ( $product_ids as $product_id ) {
$product = wc_get_product( $product_id );
$files = $product->get_files();
$files = $product->get_downloads();
if ( ! $order->get_billing_email() ) {
die();
@ -797,8 +797,8 @@ class WC_AJAX {
$loop ++;
$file_counter ++;
if ( isset( $file['name'] ) ) {
$file_count = $file['name'];
if ( $file->get_name() ) {
$file_count = $file->get_name();
} else {
$file_count = sprintf( __( 'File %d', 'woocommerce' ), $file_counter );
}

View File

@ -238,10 +238,10 @@ class WC_Comments {
public static function clear_transients( $post_id ) {
if ( 'product' === get_post_type( $post_id ) ) {
delete_post_meta( $post_id, '_wc_average_rating' );
delete_post_meta( $post_id, '_wc_rating_count' );
delete_post_meta( $post_id, '_wc_review_count' );
WC_Product::sync_average_rating( $post_id );
$product = wc_get_product( $post_id );
update_post_meta( $post_id, '_wc_rating_count', self::get_rating_counts_for_product( $product ) );
update_post_meta( $post_id, '_wc_average_rating', self::get_average_rating_for_product( $product ) );
update_post_meta( $post_id, '_wc_review_count', self::get_review_count_for_product( $product ) );
}
}
@ -328,6 +328,89 @@ class WC_Comments {
}
return $verified;
}
/**
* Get product rating for a product. Please note this is not cached.
*
* @since 2.7.0
* @param WC_Product $product
* @return float
*/
public static function get_average_rating_for_product( $product ) {
global $wpdb;
$count = $product->get_rating_count();
if ( $count ) {
$ratings = $wpdb->get_var( $wpdb->prepare("
SELECT SUM(meta_value) FROM $wpdb->commentmeta
LEFT JOIN $wpdb->comments ON $wpdb->commentmeta.comment_id = $wpdb->comments.comment_ID
WHERE meta_key = 'rating'
AND comment_post_ID = %d
AND comment_approved = '1'
AND meta_value > 0
", $product->get_id() ) );
$average = number_format( $ratings / $count, 2, '.', '' );
} else {
$average = 0;
}
update_post_meta( $product->get_id(), '_wc_average_rating', true );
return $average;
}
/**
* Get product review count for a product (not replies). Please note this is not cached.
*
* @since 2.7.0
* @param WC_Product $product
* @return int
*/
public static function get_review_count_for_product( $product ) {
global $wpdb;
$count = $wpdb->get_var( $wpdb->prepare("
SELECT COUNT(*) FROM $wpdb->comments
WHERE comment_parent = 0
AND comment_post_ID = %d
AND comment_approved = '1'
", $product->get_id() ) );
update_post_meta( $product->get_id(), '_wc_review_count', true );
return $count;
}
/**
* Get product rating count for a product. Please note this is not cached.
*
* @since 2.7.0
* @param WC_Product $product
* @return array of integers
*/
public static function get_rating_counts_for_product( $product ) {
global $wpdb;
$counts = array();
$raw_counts = $wpdb->get_results( $wpdb->prepare( "
SELECT meta_value, COUNT( * ) as meta_value_count FROM $wpdb->commentmeta
LEFT JOIN $wpdb->comments ON $wpdb->commentmeta.comment_id = $wpdb->comments.comment_ID
WHERE meta_key = 'rating'
AND comment_post_ID = %d
AND comment_approved = '1'
AND meta_value > 0
GROUP BY meta_value
", $product->get_id() ) );
foreach ( $raw_counts as $count ) {
$counts[ $count->meta_value ] = absint( $count->meta_value_count );
}
update_post_meta( $product->get_id(), '_wc_rating_count', true );
return $counts;
}
}
WC_Comments::init();

View File

@ -0,0 +1,221 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Represents a file which can be downloaded.
*
* @version 2.7.0
* @since 2.7.0
* @package WooCommerce/Classes
* @author WooThemes
*/
class WC_Product_Download implements ArrayAccess {
/**
* Data array.
* @since 2.7.0
* @var array
*/
protected $data = array(
'id' => '',
'name' => '',
'file' => '',
);
/**
* Returns all data for this object.
* @return array
*/
public function get_data() {
return $this->data;
}
/**
* Get allowed mime types.
* @return array
*/
public function get_allowed_mime_types() {
return apply_filters( 'woocommerce_downloadable_file_allowed_mime_types', get_allowed_mime_types() );
}
/**
* Get type of file path set.
* @param string $file_path optional.
* @return string absolute, relative, or shortcode.
*/
public function get_type_of_file_path( $file_path = '' ) {
$file_path = $file_path ? $file_path : $this->get_file();
if ( 0 === strpos( $file_path, 'http' ) ) {
return 'absolute';
} elseif ( '[' === substr( $file_path, 0, 1 ) && ']' === substr( $file_path, -1 ) ) {
return 'shortcode';
} else {
return 'relative';
}
}
/**
* Get file type.
* @return string
*/
public function get_file_type() {
$type = wp_check_filetype( strtok( $this->get_file(), '?' ), $this->get_allowed_mime_types() );
return $type['type'];
}
/**
* Get file extension.
* @return string
*/
public function get_file_extension() {
$parsed_url = parse_url( $this->get_file(), PHP_URL_PATH );
return pathinfo( $parsed_url, PATHINFO_EXTENSION );
}
/**
* Check if file is allowed.
* @return boolean
*/
public function is_allowed_filetype() {
if ( 'shortcode' === $this->get_type_of_file_path() ) {
return true;
}
return empty( $this->get_file_extension() ) || in_array( $this->get_file_type(), $this->get_allowed_mime_types() );
}
/**
* Validate file exists.
* @return boolean
*/
public function file_exists() {
if ( 'relative' !== $this->get_type_of_file_path() ) {
return true;
}
$file_url = $this->get_file();
if ( '..' === substr( $file_url, 0, 2 ) || '/' !== substr( $file_url, 0, 1 ) ) {
$file_url = realpath( ABSPATH . $file_url );
}
return apply_filters( 'woocommerce_downloadable_file_exists', file_exists( $file_url ), $this->get_file() );
}
/*
|--------------------------------------------------------------------------
| Setters
|--------------------------------------------------------------------------
*/
/**
* Set ID.
* @param string $value
*/
public function set_id( $value ) {
$this->data['id'] = wc_clean( $value );
}
/**
* Set name.
* @param string $value
*/
public function set_name( $value ) {
$this->data['name'] = wc_clean( $value );
}
/**
* Set file.
* @param string $value
*/
public function set_file( $value ) {
switch ( $this->get_type_of_file_path( $value ) ) {
case 'absolute' :
$this->data['file'] = esc_url_raw( $value );
break;
default:
$this->data['file'] = wc_clean( $value );
break;
}
}
/*
|--------------------------------------------------------------------------
| Getters
|--------------------------------------------------------------------------
*/
/**
* Get id.
* @return string
*/
public function get_id() {
return $this->data['id'];
}
/**
* Get name.
* @return string
*/
public function get_name() {
return $this->data['name'];
}
/**
* Get file.
* @return string
*/
public function get_file() {
return $this->data['file'];
}
/*
|--------------------------------------------------------------------------
| ArrayAccess/Backwards compatibility.
|--------------------------------------------------------------------------
*/
/**
* offsetGet
* @param string $offset
* @return mixed
*/
public function offsetGet( $offset ) {
switch ( $offset ) {
default :
if ( is_callable( array( $this, "get_$offset" ) ) ) {
return $this->{"get_$offset"}();
}
break;
}
return '';
}
/**
* offsetSet
* @param string $offset
* @param mixed $value
*/
public function offsetSet( $offset, $value ) {
switch ( $offset ) {
default :
if ( is_callable( array( $this, "set_$offset" ) ) ) {
return $this->{"set_$offset"}( $value );
}
break;
}
}
/**
* offsetUnset
* @param string $offset
*/
public function offsetUnset( $offset ) {}
/**
* offsetExists
* @param string $offset
* @return bool
*/
public function offsetExists( $offset ) {
return in_array( $offset, array_keys( $this->data ) );
}
}

View File

@ -255,8 +255,8 @@ class WC_Product_Variable extends WC_Product {
return apply_filters( 'woocommerce_available_variation', array_merge( $variation->get_data(), array(
'image' => wc_get_product_attachment_props( $variation->get_image_id() ),
'weight_html' => $variation->get_weight() ? $variation->get_weight() . ' ' . esc_attr( get_option( 'woocommerce_weight_unit' ) ) : '',
'dimensions_html' => $variation->get_dimensions(),
'weight_html' => wc_format_weight( $variation->get_weight() ),
'dimensions_html' => wc_format_dimensions( $variation->get_dimensions( false ) ),
'price_html' => apply_filters( 'woocommerce_show_variation_price', $variation->get_price() === "" || $this->get_variation_price( 'min' ) !== $this->get_variation_price( 'max' ), $this, $variation ) ? '<span class="price">' . $variation->get_price_html() . '</span>' : '',
'availability_html' => wc_get_stock_html( $variation ),
'variation_id' => $variation->get_id(),
@ -265,7 +265,7 @@ class WC_Product_Variable extends WC_Product {
'is_purchasable' => $variation->is_purchasable(),
'display_price' => wc_get_price_to_display( $variation ),
'display_regular_price' => wc_get_price_to_display( $variation, array( 'price' => $variation->get_regular_price() ) ),
'dimensions' => $variation->get_dimensions(),
'dimensions' => wc_format_dimensions( $variation->get_dimensions( false ) ),
'min_qty' => 1,
'max_qty' => $variation->backorders_allowed() ? '' : $variation->get_stock_quantity(),
'backorders_allowed' => $variation->backorders_allowed(),
@ -634,7 +634,7 @@ class WC_Product_Variable extends WC_Product {
* @return bool
*/
public function has_dimensions() {
return $this->get_length() || $this->get_height() || $this->get_width();
return parent::has_dimensions() || $this->child_has_dimensions();
}
/**
@ -643,16 +643,7 @@ class WC_Product_Variable extends WC_Product {
* @return bool
*/
public function has_weight() {
return $this->get_weight() ? true : false;
}
/**
* Returns whether or not we are showing dimensions on the product page.
*
* @return bool
*/
public function enable_dimensions_display() {
return apply_filters( 'wc_product_enable_dimensions_display', true ) && ( $this->has_dimensions() || $this->has_weight() || $this->child_has_weight() || $this->child_has_dimensions() );
return parent::has_weight() || $this->child_has_weight();
}
/*

View File

@ -987,7 +987,7 @@ class WC_CLI_Product extends WC_CLI_Command {
if ( $product->is_downloadable() ) {
foreach ( $product->get_files() as $file_id => $file ) {
foreach ( $product->get_downloads() as $file_id => $file ) {
$downloads[] = array(
'id' => $file_id, // do not cast as int as this is a hash

View File

@ -279,3 +279,14 @@ function wc_check_if_attribute_name_is_reserved( $attribute_name ) {
return in_array( $attribute_name, $reserved_terms );
}
/**
* Callback for array filter to get visible only.
*
* @since 2.7.0
* @param WC_Product $product
* @return bool
*/
function wc_attributes_array_filter_visible( $attribute ) {
return $attribute && is_a( $attribute, 'WC_Product_Attribute' ) && $attribute->get_visible() && ( ! $attribute->is_taxonomy() || taxonomy_exists( $attribute->get_name() ) );
}

View File

@ -1407,21 +1407,6 @@ function wc_get_logger() {
return new $class;
}
/**
* Runs a deprecated action with notice only if used.
* @since 2.7.0
* @param string $action
* @param array $args
* @param string $deprecated_in
* @param string $replacement
*/
function wc_do_deprecated_action( $action, $args, $deprecated_in, $replacement ) {
if ( has_action( $action ) ) {
_deprecated_function( 'Action: ' . $action, $deprecated_in, $replacement );
do_action_ref_array( $action, $args );
}
}
/**
* Store user agents. Used for tracker.
* @since 2.7.0

View File

@ -11,7 +11,55 @@
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit;
}
/**
* Runs a deprecated action with notice only if used.
*
* @since 2.7.0
* @param string $action
* @param array $args
* @param string $deprecated_in
* @param string $replacement
*/
function wc_do_deprecated_action( $action, $args, $deprecated_in, $replacement ) {
if ( has_action( $action ) ) {
_deprecated_function( 'Action: ' . $action, $deprecated_in, $replacement );
do_action_ref_array( $action, $args );
}
}
/**
* Soft deprecate a function so that it's technically deprecated, but not shown
* until a future version to ease transition for developers.
*
* @since 2.7.0
* @param string $function
* @param string $version
* @param string $deprecate_in_version
* @param string $replacement
*/
function wc_soft_deprecated_function( $function, $version, $deprecate_in_version, $replacement = null ) {
if ( version_compare( WC_VERSION, $deprecate_in_version, '>=' ) ) {
_deprecated_function( $function, $version, $replacement );
}
}
/**
* Soft deprecate an argument so that it's technically deprecated, but not shown
* until a future version to ease transition for developers.
*
* @since 2.7.0
* @param string $argument
* @param string $version
* @param string $deprecate_in_version
* @param string $replacement
*/
function wc_soft_deprecated_argument( $argument, $version, $deprecate_in_version, $message = null ) {
if ( version_compare( WC_VERSION, $deprecate_in_version, '>=' ) ) {
_deprecated_argument( $argument, $version, $message );
}
}
/**
@ -523,6 +571,8 @@ $wc_map_deprecated_filters = array(
'woocommerce_product_get_stock_quantity' => 'woocommerce_get_stock_quantity',
'woocommerce_product_get_attributes' => 'woocommerce_get_product_attributes',
'woocommerce_product_get_gallery_image_ids' => 'woocommerce_product_gallery_attachment_ids',
'woocommerce_product_get_review_count' => 'woocommerce_product_review_count',
'woocommerce_product_get_downloads' => 'woocommerce_product_files',
);
foreach ( $wc_map_deprecated_filters as $new => $old ) {

View File

@ -959,3 +959,41 @@ function wc_format_price_range( $from, $to ) {
$price = sprintf( _x( '%1$s &ndash; %2$s', 'Price range: from-to', 'woocommerce' ), is_numeric( $from ) ? wc_price( $from ) : $from, is_numeric( $to ) ? wc_price( $to ) : $to );
return apply_filters( 'woocommerce_format_price_range', $price, $from, $to );
}
/**
* Format a weight for display.
*
* @since 2.7.0
* @param float $weight Weight.
* @return string
*/
function wc_format_weight( $weight ) {
$weight_string = wc_format_localized_decimal( $weight );
if ( ! empty( $weight_string ) ) {
$weight_string .= ' ' . get_option( 'woocommerce_weight_unit' );
} else {
$weight_string = __( 'N/A', 'woocommerce' );
}
return apply_filters( 'woocommerce_format_weight', $weight_string, $weight );
}
/**
* Format dimensions for display.
*
* @since 2.7.0
* @param array $dimensions Array of dimensions.
* @return string
*/
function wc_format_dimensions( $dimensions ) {
$dimension_string = implode( ' x ', array_filter( array_map( 'wc_format_localized_decimal', $dimensions ) ) );
if ( ! empty( $dimension_string ) ) {
$dimension_string .= ' ' . get_option( 'woocommerce_dimension_unit' );
} else {
$dimension_string = __( 'N/A', 'woocommerce' );
}
return apply_filters( 'woocommerce_format_dimensions', $dimension_string, $dimensions );
}

View File

@ -497,7 +497,7 @@ function wc_downloadable_product_permissions( $order_id ) {
$_product = $item->get_product();
if ( $_product && $_product->exists() && $_product->is_downloadable() ) {
$downloads = $_product->get_files();
$downloads = $_product->get_downloads();
foreach ( array_keys( $downloads ) as $download_id ) {
wc_downloadable_file_permission( $download_id, $item['variation_id'] > 0 ? $item['variation_id'] : $item['product_id'], $order, $item['qty'] );

View File

@ -1133,7 +1133,7 @@ if ( ! function_exists( 'woocommerce_default_product_tabs' ) ) {
}
// Additional information tab - shows attributes
if ( $product && ( $product->has_attributes() || $product->enable_dimensions_display() ) ) {
if ( $product && ( $product->has_attributes() || apply_filters( 'wc_product_enable_dimensions_display', $product->has_weight() || $product->has_dimensions() ) ) ) {
$tabs['additional_information'] = array(
'title' => __( 'Additional information', 'woocommerce' ),
'priority' => 20,
@ -2466,13 +2466,15 @@ if ( ! function_exists( 'woocommerce_photoswipe' ) ) {
}
/**
* Outputs a list of product attributes.
* Outputs a list of product attributes for a product.
* @since 2.7.0
* @param WC_Product $product
*/
function wc_display_product_attributes( $product ) {
wc_get_template( 'single-product/product-attributes.php', array(
'product' => $product,
'attributes' => array_filter( $product->get_attributes(), 'wc_attributes_array_filter_visible' ),
'display_dimensions' => apply_filters( 'wc_product_enable_dimensions_display', $product->has_weight() || $product->has_dimensions() ),
) );
}
@ -2528,3 +2530,21 @@ function wc_get_price_suffix( $product, $price = '', $qty = 1 ) {
}
return apply_filters( 'woocommerce_get_price_suffix', $price_display_suffix, $product );
}
/**
* Get HTML for ratings.
*
* @since 2.7.0
* @param float $rating Rating being shown.
* @return string
*/
function wc_get_rating_html( $rating ) {
if ( $rating > 0 ) {
$rating_html = '<div class="star-rating" title="' . sprintf( __( 'Rated %s out of 5', 'woocommerce' ), $rating ) . '">';
$rating_html .= '<span style="width:' . ( ( $rating / 5 ) * 100 ) . '%"><strong class="rating">' . $rating . '</strong> ' . __( 'out of 5', 'woocommerce' ) . '</span>';
$rating_html .= '</div>';
} else {
$rating_html = '';
}
return apply_filters( 'woocommerce_product_get_rating_html', $rating_html, $rating );
}

View File

@ -73,7 +73,7 @@ class WC_Widget_Recent_Reviews extends WC_Widget {
$rating = intval( get_comment_meta( $comment->comment_ID, 'rating', true ) );
$rating_html = $_product->get_rating_html( $rating );
$rating_html = wc_get_rating_html( $rating );
echo '<li><a href="' . esc_url( get_comment_link( $comment->comment_ID ) ) . '">';

View File

@ -29,7 +29,7 @@ global $product; ?>
<span class="product-title"><?php echo $product->get_title(); ?></span>
</a>
<?php if ( ! empty( $show_rating ) ) : ?>
<?php echo $product->get_rating_html(); ?>
<?php echo wc_get_rating_html( $product->get_average_rating() ); ?>
<?php endif; ?>
<?php echo $product->get_price_html(); ?>
</li>

View File

@ -17,17 +17,12 @@
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit;
}
global $product;
if ( get_option( 'woocommerce_enable_review_rating' ) === 'no' )
return;
?>
<?php if ( $rating_html = $product->get_rating_html() ) : ?>
<?php echo $rating_html; ?>
<?php endif;
/* Omit closing PHP tag at the end of PHP files to avoid "headers already sent" issues. */
echo wc_get_rating_html( $product->get_average_rating() );

View File

@ -19,66 +19,31 @@
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
exit;
}
$has_row = false;
$alt = 1;
$attributes = $product->get_variation_attributes();
ob_start();
?>
<table class="shop_attributes">
<?php if ( $product->enable_dimensions_display() ) : ?>
<?php if ( $product->has_weight() || $product->child_has_weight() ) : $has_row = true; ?>
<tr class="<?php if ( ( $alt = $alt * -1 ) === 1 ) echo 'alt'; ?>">
<?php if ( $display_dimensions && $product->has_weight() ) : ?>
<tr>
<th><?php _e( 'Weight', 'woocommerce' ) ?></th>
<td class="product_weight"><?php echo $product->get_weight() ? wc_format_localized_decimal( $product->get_weight() ) . ' ' . esc_attr( get_option( 'woocommerce_weight_unit' ) ) : __( 'N/A', 'woocommerce' ); ?></td>
<td class="product_weight"><?php echo esc_html( wc_format_weight( $product->get_weight() ) ); ?></td>
</tr>
<?php endif; ?>
<?php if ( $product->has_dimensions() || $product->child_has_dimensions() ) : $has_row = true; ?>
<tr class="<?php if ( ( $alt = $alt * -1 ) === 1 ) echo 'alt'; ?>">
<?php if ( $display_dimensions && $product->has_dimensions() ) : ?>
<tr>
<th><?php _e( 'Dimensions', 'woocommerce' ) ?></th>
<td class="product_dimensions"><?php echo $product->get_dimensions() ? $product->get_dimensions() : __( 'N/A', 'woocommerce' ); ?></td>
<td class="product_dimensions"><?php echo esc_html( wc_format_dimensions( $product->get_dimensions( false ) ) ); ?></td>
</tr>
<?php endif; ?>
<?php endif; ?>
<?php foreach ( $attributes as $attribute ) :
if ( empty( $attribute['is_visible'] ) || ( $attribute['is_taxonomy'] && ! taxonomy_exists( $attribute['name'] ) ) ) {
continue;
} else {
$has_row = true;
}
?>
<tr class="<?php if ( ( $alt = $alt * -1 ) == 1 ) echo 'alt'; ?>">
<th><?php echo wc_attribute_label( $attribute['name'] ); ?></th>
<?php foreach ( $attributes as $attribute ) : ?>
<tr>
<th><?php echo wc_attribute_label( $attribute->get_name() ); ?></th>
<td><?php
if ( $attribute['is_taxonomy'] ) {
$values = wc_get_product_terms( $product->get_id(), $attribute['name'], array( 'fields' => 'names' ) );
$values = $attribute->is_taxonomy() ? wc_get_product_terms( $product->get_id(), $attribute->get_name(), array( 'fields' => 'names' ) ) : $attribute->get_options();
echo apply_filters( 'woocommerce_attribute', wpautop( wptexturize( implode( ', ', $values ) ) ), $attribute, $values );
} else {
// Convert pipes to commas and display values
$values = array_map( 'trim', explode( WC_DELIMITER, $attribute['value'] ) );
echo apply_filters( 'woocommerce_attribute', wpautop( wptexturize( implode( ', ', $values ) ) ), $attribute, $values );
}
?></td>
</tr>
<?php endforeach; ?>
</table>
<?php
if ( $has_row ) {
echo ob_get_clean();
} else {
ob_end_clean();
}