/**
  * Calculate subscriptions price html component by breaking up bundled subs into recurring scheme groups and adding up all prices in each group.
  *
  * @return string
  */
 public function apply_subs_price_html($price)
 {
     if (!empty($this->bundled_items)) {
         $subs_details = array();
         $subs_details_html = array();
         $non_optional_subs_exist = false;
         foreach ($this->bundled_items as $bundled_item_id => $bundled_item) {
             if ($bundled_item->is_sub()) {
                 $bundled_product = $bundled_item->product;
                 if ($bundled_item->is_variable_sub()) {
                     $product_id = get_post_meta($bundled_product->id, '_min_price_variation_id', true);
                     $product = $bundled_product->get_child($product_id);
                 } else {
                     $product = $bundled_product;
                 }
                 $sub_string = str_replace('_synced', '', WC_Subscriptions_Cart::get_recurring_cart_key(array('data' => $product), ' '));
                 if (!isset($subs_details[$sub_string]['bundled_items'])) {
                     $subs_details[$sub_string]['bundled_items'] = array();
                 }
                 if (!isset($subs_details[$sub_string]['price'])) {
                     $subs_details[$sub_string]['price'] = 0;
                     $subs_details[$sub_string]['regular_price'] = 0;
                     $subs_details[$sub_string]['is_range'] = false;
                 }
                 $subs_details[$sub_string]['bundled_items'][] = $bundled_item_id;
                 $subs_details[$sub_string]['price'] += $this->bundled_quantities_index['min'][$bundled_item_id] * WC_PB_Helpers::get_product_display_price($product, $bundled_item->min_recurring_price);
                 $subs_details[$sub_string]['regular_price'] += $this->bundled_quantities_index['min'][$bundled_item_id] * WC_PB_Helpers::get_product_display_price($product, $bundled_item->min_regular_recurring_price);
                 if ($bundled_item->is_variable_sub()) {
                     if ($bundled_product->min_variation_price !== $bundled_product->max_variation_price || $bundled_product->subscription_period !== $bundled_product->max_variation_period || $bundled_product->subscription_period_interval !== $bundled_product->max_variation_period_interval) {
                         $subs_details[$sub_string]['is_range'] = true;
                     }
                 }
                 if (!isset($subs_details[$sub_string]['price_html'])) {
                     $subs_details[$sub_string]['price_html'] = WC_PB_Helpers::get_recurring_price_html_component($product);
                 }
             }
         }
         if (!empty($subs_details)) {
             foreach ($subs_details as $sub_details) {
                 if ($sub_details['price'] > 0) {
                     $sub_price_html = wc_price($sub_details['price']);
                     if ($sub_details['price'] !== $sub_details['regular_price']) {
                         $sub_regular_price_html = wc_price($sub_details['regular_price']);
                         if ($sub_details['is_range']) {
                             $sub_price_html = sprintf(_x('%1$s%2$s', 'Price range: from', 'woocommerce-product-bundles'), _x('<span class="from">from </span>', 'min-price', 'woocommerce-product-bundles'), $this->get_price_html_from_to($sub_regular_price_html, $sub_price_html));
                         } else {
                             $sub_price_html = $this->get_price_html_from_to($sub_regular_price_html, $sub_price_html);
                         }
                     } elseif ($sub_details['price'] == 0 && !$sub_details['is_range']) {
                         $sub_price_html = __('Free!', 'woocommerce');
                     } else {
                         if ($sub_details['is_range']) {
                             $sub_price_html = sprintf(_x('%1$s%2$s', 'Price range: from', 'woocommerce-product-bundles'), _x('<span class="from">from </span>', 'min-price', 'woocommerce-product-bundles'), $sub_price_html);
                         }
                     }
                     $sub_price_html = sprintf($sub_details['price_html'], $sub_price_html);
                     $subs_details_html[] = '<span class="bundled_sub_price_html">' . $sub_price_html . '</span>';
                 }
             }
             $price_html = implode('<span class="plus"> + </span>', $subs_details_html);
             if ($this->min_bundle_regular_price != 0) {
                 $price = sprintf(_x('%1$s<span class="bundled_subscriptions_price_html" %2$s> now,</br>then %3$s</span>', 'subscription price html suffix', 'woocommerce-product-bundles'), $price, !empty($subs_details_html) ? '' : 'style="display:none"', $price_html);
             } else {
                 $price = '<span class="bundled_subscriptions_price_html">' . $price_html . '</span>';
             }
         }
     }
     return $price;
 }
 /**
  * Make sure that a switch items cart key is based on it's first renewal date, not the date calculated for the product.
  *
  * @since 2.0
  */
 public static function get_recurring_cart_key($cart_key, $cart_item)
 {
     if (isset($cart_item['subscription_switch']['first_payment_timestamp'])) {
         remove_filter('woocommerce_subscriptions_recurring_cart_key', __METHOD__, 10, 2);
         $cart_key = WC_Subscriptions_Cart::get_recurring_cart_key($cart_item, $cart_item['subscription_switch']['first_payment_timestamp']);
         add_filter('woocommerce_subscriptions_recurring_cart_key', __METHOD__, 10, 2);
     }
     return $cart_key;
 }
 /**
  * Modifies the results of get_available_variations() to implement variation filtering and bundle discounts for variable products.
  * Also calculates variation prices incl. or excl. tax.
  *
  * @param  array                  $variation_data     unmodified variation data
  * @param  WC_Product             $bundled_product    the bundled product
  * @param  WC_Product_Variation   $bundled_variation  the variation in question
  * @return array                                      modified variation data
  */
 public function bundled_item_available_variation($variation_data, $bundled_product, $bundled_variation)
 {
     $bundled_item_id = $this->item_id;
     // Disable if certain conditions are met...
     if (!empty($this->allowed_variations)) {
         if (!is_array($this->allowed_variations)) {
             return array();
         }
         if (!in_array($bundled_variation->variation_id, $this->allowed_variations)) {
             return array();
         }
     }
     if ($bundled_variation->price === '') {
         return array();
     }
     // Modify product id for JS (deprecated).
     $variation_data['product_id'] = $bundled_item_id;
     // Add price data with WC 2.2 missing display_regular_price/display_price compatibility.
     $variation_data['regular_price'] = isset($variation_data['display_regular_price']) ? $variation_data['display_regular_price'] : WC_PB_Helpers::get_product_display_price($bundled_variation, $bundled_variation->get_regular_price());
     $variation_data['price'] = isset($variation_data['display_price']) ? $variation_data['display_price'] : WC_PB_Helpers::get_product_display_price($bundled_variation, $bundled_variation->get_price());
     $variation_data['regular_recurring_price'] = '';
     $variation_data['recurring_price'] = '';
     $variation_data['recurring_html'] = '';
     $variation_data['recurring_key'] = '';
     if ($bundled_product->product_type === 'variable-subscription') {
         $variation_data['regular_recurring_price'] = $variation_data['regular_price'];
         $variation_data['recurring_price'] = $variation_data['price'];
         $signup_fee = WC_PB_Helpers::get_product_display_price($bundled_variation, $bundled_variation->get_sign_up_fee());
         $variation_data['regular_price'] = $this->get_prorated_price_for_subscription($variation_data['regular_price'], $signup_fee, $bundled_variation);
         $variation_data['price'] = $this->get_prorated_price_for_subscription($variation_data['price'], $signup_fee, $bundled_variation);
         $variation_data['recurring_html'] = WC_PB_Helpers::get_recurring_price_html_component($bundled_variation);
         $variation_data['recurring_key'] = str_replace('_synced', '', WC_Subscriptions_Cart::get_recurring_cart_key(array('data' => $bundled_variation), ' '));
     }
     $variation_price_html = '';
     if ($this->is_priced_per_product()) {
         $variation_price_html = $variation_data['price_html'] === '' ? '<p class="price">' . $bundled_variation->get_price_html() . '</p>' : $variation_data['price_html'];
     }
     $variation_data['price_html'] = $variation_price_html;
     // Modify availability data.
     $quantity = $this->get_quantity();
     $quantity_max = $this->get_quantity('max', true, $bundled_variation);
     $availability = $this->get_availability($bundled_variation);
     if (!$this->is_in_stock() || !$bundled_variation->is_in_stock() || !$bundled_variation->has_enough_stock($quantity)) {
         $variation_data['is_in_stock'] = false;
     }
     if ($bundled_variation->is_on_backorder() && $bundled_product->backorders_require_notification()) {
         $variation_data['is_on_backorder'] = 'available-on-backorder';
     }
     $availability_html = empty($availability['availability']) ? '' : '<p class="stock ' . esc_attr($availability['class']) . '">' . wp_kses_post($availability['availability']) . '</p>';
     $variation_data['availability_html'] = apply_filters('woocommerce_stock_html', $availability_html, $availability['availability'], $bundled_variation);
     $variation_data['min_qty'] = $quantity;
     $variation_data['max_qty'] = $quantity_max;
     if ($variation_data['min_qty'] !== $variation_data['max_qty']) {
         $variation_data['is_sold_individually'] = false;
     }
     return $variation_data;
 }