WC_Product_Variable_Data_Store_CPT::read_price_data │ public │ WC 3.0.0
Get an array of all sale and regular prices from all variations. This is used for example when displaying the price range at variable product level or seeing if the variable product is on sale.
Can be filtered by plugins which modify costs, but otherwise will include the raw meta costs unlike get_price() which runs costs through the woocommerce_get_price filter. This is to ensure modified prices are not cached, unless intended.
Method of the class: WC_Product_Variable_Data_Store_CPT{}
Hooks from the method
Returns
Array. of prices
Usage
$WC_Product_Variable_Data_Store_CPT = new WC_Product_Variable_Data_Store_CPT(); $WC_Product_Variable_Data_Store_CPT->read_price_data( $product, $for_display );
- $product(WC_Product) (required) (passed by reference — &)
- Product object.
- $for_display(true|false)
- If true, prices will be adapted for display based on the
woocommerce_tax_display_shopsetting (including or excluding taxes).
Default:false
Changelog
| Since 3.0.0 | Introduced. |
WC_Product_Variable_Data_Store_CPT::read_price_data() WC Product Variable Data Store CPT::read price data code WC 10.7.0
public function read_price_data( &$product, $for_display = false ) {
/**
* Transient name for storing prices for this product (note: Max transient length is 45)
*
* @since 2.5.0 a single transient is used per product for all prices, rather than many transients per product.
*/
$transient_name = 'wc_var_prices_' . $product->get_id();
$transient_version = WC_Cache_Helper::get_transient_version( 'product' );
$price_hash = $this->get_price_hash( $product, $for_display );
$opposite_price_hash = $this->taxes_influence_price( $product ) ? null : $this->get_price_hash( $product, ! $for_display );
/**
* $this->prices_array is an array of values which may have been modified from what is stored in transients - this may not match $transient_cached_prices_array.
* If the value has already been generated, we don't need to grab the values again so just return them. They are already filtered.
*/
if ( empty( $this->prices_array[ $price_hash ] ) ) {
$transient_cached_prices_array = array_filter( (array) json_decode( strval( get_transient( $transient_name ) ), true ) );
// If the prices are not valid, reset the transient cache.
if ( ! $this->validate_prices_data( $transient_cached_prices_array, $transient_version ) ) {
$transient_cached_prices_array = array();
}
// If the prices are not stored for this hash, generate them and add to the transient.
// Check also the opposite price hash as it may have changed (see get_price_hash).
if ( empty( $transient_cached_prices_array[ $price_hash ] ) ||
( ! is_null( $opposite_price_hash ) && ( $opposite_price_hash !== $price_hash ) && empty( $transient_cached_prices_array[ $opposite_price_hash ] ) ) ) {
$prices_array = array(
'price' => array(),
'regular_price' => array(),
'sale_price' => array(),
);
$variation_ids = $product->get_visible_children();
if ( ! empty( $variation_ids ) ) {
// Prime caches to reduce future queries.
_prime_post_caches( $variation_ids );
}
$tax_display_mode = $for_display ? get_option( 'woocommerce_tax_display_shop' ) : null;
$price_decimals = wc_get_price_decimals();
foreach ( $variation_ids as $variation_id ) {
$variation = wc_get_product( $variation_id );
if ( $variation ) {
/**
* Filters the active price for a product variation before it is used in price calculations and caching.
*
* IMPORTANT: If your filter returns a price that varies by ANY factor (e.g., current user,
* time of day, user role, cart contents, etc.), you MUST also hook into the
* 'woocommerce_get_variation_prices_hash' filter to include that factor in the cache key.
* Otherwise, the wrong price may be cached and displayed to different users or contexts.
*
* Example: Applying a per-user discount and adapting the price hash info accordingly:
*
* class My_Custom_Pricing {
* public function __construct() {
* add_filter( 'woocommerce_variation_prices_price', array( $this, 'apply_user_discount' ), 10, 3 );
* add_filter( 'woocommerce_get_variation_prices_hash', array( $this, 'add_user_to_hash' ), 10, 3 );
* }
*
* public function apply_user_discount( $price, $variation, $product ) {
* return $price * $this->get_discount_for_user( get_current_user_id() );
* }
*
* public function add_user_to_hash( $price_hash, $product, $for_display ) {
* $price_hash[] = get_current_user_id();
* return $price_hash;
* }
* }
*
* @since 3.0.0
*
* @param string|float $price The variation's active price.
* @param WC_Product $variation The variation product object.
* @param WC_Product $product The parent variable product object.
*/
$price = apply_filters( 'woocommerce_variation_prices_price', $variation->get_price( 'edit' ), $variation, $product );
// Skip empty prices.
if ( '' === $price ) {
continue;
}
/**
* Filters the regular price for a product variation before it is used in price calculations and caching.
*
* IMPORTANT: see the documentation for the 'woocommerce_variation_prices_price' filter.
*
* @since 3.0.0
*
* @param string|float $regular_price The variation's regular price.
* @param WC_Product $variation The variation product object.
* @param WC_Product $product The parent variable product object.
*/
$regular_price = apply_filters( 'woocommerce_variation_prices_regular_price', $variation->get_regular_price( 'edit' ), $variation, $product );
/**
* Filters the sale price for a product variation before it is used in price calculations and caching.
*
* IMPORTANT: see the documentation for the 'woocommerce_variation_prices_price' filter.
*
* @since 3.0.0
*
* @param string|float $sale_price The variation's sale price.
* @param WC_Product $variation The variation product object.
* @param WC_Product $product The parent variable product object.
*/
$sale_price = apply_filters( 'woocommerce_variation_prices_sale_price', $variation->get_sale_price( 'edit' ), $variation, $product );
// If sale price does not equal price, the product is not yet on sale.
if ( $sale_price === $regular_price || $sale_price !== $price ) {
$sale_price = $regular_price;
}
// If we are getting prices for display, we need to account for taxes.
if ( $for_display ) {
if ( 'incl' === $tax_display_mode ) {
$price = '' === $price ? '' : wc_get_price_including_tax(
$variation,
array(
'qty' => 1,
'price' => $price,
)
);
$regular_price = '' === $regular_price ? '' : wc_get_price_including_tax(
$variation,
array(
'qty' => 1,
'price' => $regular_price,
)
);
$sale_price = '' === $sale_price ? '' : wc_get_price_including_tax(
$variation,
array(
'qty' => 1,
'price' => $sale_price,
)
);
} else {
$price = '' === $price ? '' : wc_get_price_excluding_tax(
$variation,
array(
'qty' => 1,
'price' => $price,
)
);
$regular_price = '' === $regular_price ? '' : wc_get_price_excluding_tax(
$variation,
array(
'qty' => 1,
'price' => $regular_price,
)
);
$sale_price = '' === $sale_price ? '' : wc_get_price_excluding_tax(
$variation,
array(
'qty' => 1,
'price' => $sale_price,
)
);
}
}
$prices_array['price'][ $variation_id ] = wc_format_decimal( $price, $price_decimals );
$prices_array['regular_price'][ $variation_id ] = wc_format_decimal( $regular_price, $price_decimals );
$prices_array['sale_price'][ $variation_id ] = wc_format_decimal( $sale_price, $price_decimals );
if ( has_filter( 'woocommerce_variation_prices_array' ) ) {
$original_prices_array = $prices_array;
/**
* Filter the variation prices array before storing in transient cache.
*
* This filter allows developers to modify the variation prices array for each variation
* during the price calculation process. It's called for each variation individually
* and can be used to add custom pricing data or modify existing prices.
*
* @since 3.6.0
*
* @param array $prices_array The prices array being built. Contains 'price', 'regular_price', and 'sale_price' keys.
* @param WC_Product $variation The variation product object.
* @param bool $for_display Whether prices are for display (with tax adjustments) or for calculations.
*/
$prices_array = apply_filters( 'woocommerce_variation_prices_array', $prices_array, $variation, $for_display );
if ( $opposite_price_hash ) {
// In principle, we know that prices for display and not for display are the same ones,
// but code hooking on woocommerce_variation_prices_array could make this different
// so we need to check.
$prices_array_hash = md5( wp_json_encode( $prices_array ) );
// phpcs:ignore WooCommerce.Commenting.CommentHooks
$opposite_prices_array = apply_filters( 'woocommerce_variation_prices_array', $original_prices_array, $variation, ! $for_display );
$opposite_prices_array_hash = md5( wp_json_encode( $opposite_prices_array ) );
if ( $opposite_prices_array_hash !== $prices_array_hash ) {
$opposite_price_hash = null;
}
}
}
}
}
// Add all pricing data to the transient array.
foreach ( $prices_array as $key => $values ) {
$transient_cached_prices_array[ $price_hash ][ $key ] = $values;
if ( ! is_null( $opposite_price_hash ) && $opposite_price_hash !== $price_hash ) {
$transient_cached_prices_array[ $opposite_price_hash ][ $key ] = $values;
}
}
// Validate the prices data before storing it in the transient.
if ( $this->validate_prices_data( $transient_cached_prices_array, $transient_version ) ) {
set_transient( $transient_name, wp_json_encode( $transient_cached_prices_array ), DAY_IN_SECONDS * 30 );
}
}
/**
* Filters the variation prices array for a variable product.
*
* This filter gives plugins one last chance to modify the variation prices array which has been
* generated and will be stored locally to the class. This value may differ from the transient cache.
* It is filtered once before storing locally.
*
* @since 3.0.0
*
* @param array $prices_array {
* Associative array of variation prices indexed by variation ID.
*
* @type array $price Array of active prices (variation_id => price).
* @type array $regular_price Array of regular prices (variation_id => price).
* @type array $sale_price Array of sale prices (variation_id => price).
* }
* @param WC_Product $product The variable product object.
* @param bool $for_display Whether prices are being retrieved for display.
*/
$this->prices_array[ $price_hash ] = apply_filters( 'woocommerce_variation_prices', $transient_cached_prices_array[ $price_hash ], $product, $for_display );
if ( ! is_null( $opposite_price_hash ) && $opposite_price_hash !== $price_hash ) {
// phpcs:ignore WooCommerce.Commenting.CommentHooks
$this->prices_array[ $opposite_price_hash ] = apply_filters( 'woocommerce_variation_prices', $transient_cached_prices_array[ $opposite_price_hash ], $product, ! $for_display );
}
}
return $this->prices_array[ $price_hash ];
}