Esempio n. 1
0
 function __construct($bundled_item_id, $parent)
 {
     $this->item_id = $bundled_item_id;
     $this->product_id = $parent->bundle_data[$bundled_item_id]['product_id'];
     $this->bundle_id = $parent->id;
     $this->item_data = $parent->bundle_data[$bundled_item_id];
     // Do not process bundled item stock data in the back end, in order to speed things up just a bit
     $this->is_front_end = !is_admin() || defined('DOING_AJAX') && true == DOING_AJAX;
     do_action('woocommerce_before_init_bundled_item', $this);
     $bundled_product = WC_PB_Core_Compatibility::wc_get_product($this->product_id);
     // if not present, item cannot be purchased
     if ($bundled_product) {
         $this->product = $bundled_product;
         $this->title = !empty($this->item_data['override_title']) && $this->item_data['override_title'] === 'yes' ? $this->item_data['product_title'] : $bundled_product->get_title();
         $this->description = !empty($this->item_data['override_description']) && $this->item_data['override_description'] === 'yes' ? $this->item_data['product_description'] : $bundled_product->post->post_excerpt;
         $this->visibility = !empty($this->item_data['visibility']) && in_array($this->item_data['visibility'], array('hidden', 'secret')) ? $this->item_data['visibility'] : 'visible';
         $this->optional = !empty($this->item_data['optional']) && $this->item_data['optional'] === 'yes' ? 'yes' : 'no';
         $this->hide_thumbnail = !empty($this->item_data['hide_thumbnail']) && $this->item_data['hide_thumbnail'] === 'yes' ? 'yes' : 'no';
         $this->quantity = isset($this->item_data['bundle_quantity']) ? absint($this->item_data['bundle_quantity']) : 1;
         $this->discount = !empty($this->item_data['bundle_discount']) ? (double) $this->item_data['bundle_discount'] : 0.0;
         $this->sign_up_discount = !empty($this->item_data['bundle_sign_up_discount']) ? (double) $this->item_data['bundle_sign_up_discount'] : 0.0;
         $this->selection_overrides = !empty($this->item_data['override_defaults']) && $this->item_data['override_defaults'] === 'yes' ? $this->item_data['bundle_defaults'] : '';
         $this->allowed_variations = !empty($this->item_data['filter_variations']) && $this->item_data['filter_variations'] === 'yes' ? $this->item_data['allowed_variations'] : '';
         $this->per_product_pricing = $parent->is_priced_per_product();
         $this->sold_individually = false;
         $this->on_sale = false;
         $this->nyp = false;
         $this->purchasable = false;
         if ($bundled_product->is_purchasable()) {
             $this->purchasable = true;
             $this->init();
         }
     }
     do_action('woocommerce_after_init_bundled_item', $this);
 }
 /**
  * Allows ajax add-to-cart to work in WC 2.3/2.4.
  * Fixes QuickView support when ajax add-to-cart is active and QuickView operates without a separate button.
  *
  * @param   $link
  * @param   $WC_Product
  * @return  string
  */
 public function woo_bundles_loop_add_to_cart_link($link, $product)
 {
     if ($product->is_type('bundle')) {
         if ($product->is_in_stock() && !$product->requires_input()) {
             // In WC 2.5, this is controlled by adding 'ajax_add_to_cart' support in the product ->supports property.
             if (!WC_PB_Core_Compatibility::is_wc_version_gte_2_5()) {
                 $link = str_replace('product_type_bundle', 'product_type_bundle product_type_simple', $link);
             }
         } else {
             $link = str_replace('product_type_bundle', 'product_type_bundle product_type_bundle_input_required', $link);
         }
     }
     return $link;
 }
Esempio n. 3
0
function wc_bundles_get_product_terms($product_id, $attribute_name, $args)
{
    if (WC_PB_Core_Compatibility::is_wc_version_gte_2_3()) {
        return wc_get_product_terms($product_id, $attribute_name, $args);
    } else {
        $orderby = wc_attribute_orderby(sanitize_title($attribute_name));
        switch ($orderby) {
            case 'name':
                $args = array('orderby' => 'name', 'hide_empty' => false, 'menu_order' => false);
                break;
            case 'id':
                $args = array('orderby' => 'id', 'order' => 'ASC', 'menu_order' => false);
                break;
            case 'menu_order':
                $args = array('menu_order' => 'ASC');
                break;
        }
        $terms = get_terms(sanitize_title($attribute_name), $args);
        return $terms;
    }
}
 /**
  * Return a formatted product title based on variation id.
  *
  * @param  int    $item_id
  * @return string
  */
 public function get_product_variation_title($variation_id)
 {
     $variation = WC_PB_Core_Compatibility::wc_get_product($variation_id);
     if (!$variation) {
         return false;
     }
     $description = wc_get_formatted_variation($variation->get_variation_attributes(), true);
     $title = $variation->get_title();
     $sku = $variation->get_sku();
     if ($sku) {
         $sku = sprintf(__('(SKU: %s)', 'woocommerce-product-bundles'), $sku);
     }
     return $this->format_product_title($title, $sku, $description);
 }
Esempio n. 5
0
 /**
  * Add a bundled product to the cart. Must be done without updating session data, recalculating totals or calling 'woocommerce_add_to_cart' recursively.
  * For the recursion issue, see: https://core.trac.wordpress.org/ticket/17817.
  *
  * @param int          $bundle_id
  * @param int          $product_id
  * @param int          $quantity
  * @param int          $variation_id
  * @param array        $variation
  * @param array        $cart_item_data
  * @return bool
  */
 public function bundled_add_to_cart($bundle_id, $product_id, $quantity = 1, $variation_id = '', $variation = '', $cart_item_data)
 {
     global $woocommerce_bundles;
     if ($quantity <= 0) {
         return false;
     }
     // Load cart item data when adding to cart
     $cart_item_data = (array) apply_filters('woocommerce_add_cart_item_data', $cart_item_data, $product_id, $variation_id);
     // Generate a ID based on product ID, variation ID, variation data, and other cart item data
     $cart_id = WC()->cart->generate_cart_id($product_id, $variation_id, $variation, $cart_item_data);
     // See if this product and its options is already in the cart
     $cart_item_key = WC()->cart->find_product_in_cart($cart_id);
     // Ensure we don't add a variation to the cart directly by variation ID
     if ('product_variation' == get_post_type($product_id)) {
         $variation_id = $product_id;
         $product_id = wp_get_post_parent_id($variation_id);
     }
     // Get the product
     $product_data = WC_PB_Core_Compatibility::wc_get_product($variation_id ? $variation_id : $product_id);
     // If cart_item_key is set, the item is already in the cart and its quantity will be handled by woo_bundles_update_quantity_in_cart.
     if (!$cart_item_key) {
         $cart_item_key = $cart_id;
         // Add item after merging with $cart_item_data - allow plugins and woo_bundles_add_cart_item_filter to modify cart item
         WC()->cart->cart_contents[$cart_item_key] = apply_filters('woocommerce_add_cart_item', array_merge($cart_item_data, array('product_id' => $product_id, 'variation_id' => $variation_id, 'variation' => $variation, 'quantity' => $quantity, 'data' => $product_data)), $cart_item_key);
     }
     return $cart_item_key;
 }
Esempio n. 6
0
 /**
  * Validate that all managed items in the collection are in stock.
  *
  * @param  int    $bundle_id
  * @return boolean
  */
 public function validate_stock($bundle_id)
 {
     $managed_items = $this->get_managed_items();
     if (empty($managed_items)) {
         return true;
     }
     // Stock Validation
     foreach ($managed_items as $managed_item_id => $managed_item) {
         $quantity = $managed_item['quantity'];
         // Get the product
         $product_data = WC_PB_Core_Compatibility::wc_get_product($managed_item_id);
         if (!$product_data) {
             return false;
         }
         // is_sold_individually
         if ($product_data->sold_individually === 'yes' && $quantity > 1) {
             wc_add_notice(sprintf(__('&quot;%1$s&quot; cannot be added to the cart &mdash; only 1 &quot;%2$s&quot; may be purchased.', 'woocommerce-product-bundles'), get_the_title($bundle_id), $product_data->get_title()), 'error');
             return false;
         }
         // Stock check - only check if we're managing stock and backorders are not allowed
         if (!$product_data->is_in_stock()) {
             if ($product_data->product_type === 'variable') {
                 wc_add_notice(sprintf(__('&quot;%1$s&quot; cannot be added to the cart because your &quot;%2$s&quot; selection is out of stock.', 'woocommerce-product-bundles'), get_the_title($bundle_id), $product_data->get_title()), 'error');
             } else {
                 wc_add_notice(sprintf(__('&quot;%1$s&quot; cannot be added to the cart because &quot;%2$s&quot; is out of stock.', 'woocommerce-product-bundles'), get_the_title($bundle_id), $product_data->get_title()), 'error');
             }
             return false;
         } elseif (!$product_data->has_enough_stock($quantity)) {
             if ($product_data->product_type === 'variable') {
                 wc_add_notice(sprintf(__('&quot;%1$s&quot; cannot be added to the cart because your &quot;%2$s&quot; selection does not have enough stock (%3$s remaining).', 'woocommerce-product-bundles'), get_the_title($bundle_id), $product_data->get_title(), $product_data->get_stock_quantity()), 'error');
             } else {
                 wc_add_notice(sprintf(__('&quot;%1$s&quot; cannot be added to the cart because there is not enough stock of &quot;%2$s&quot; (%3$s remaining).', 'woocommerce-product-bundles'), get_the_title($bundle_id), $product_data->get_title(), $product_data->get_stock_quantity()), 'error');
             }
             return false;
         }
         // Stock check - this time accounting for whats already in-cart
         $product_qty_in_cart = WC()->cart->get_cart_item_quantities();
         if ($product_data->managing_stock()) {
             // Variations
             if ($managed_item['is_variation'] && $product_data->variation_has_stock) {
                 if (isset($product_qty_in_cart[$managed_item_id]) && !$product_data->has_enough_stock($product_qty_in_cart[$managed_item_id] + $quantity)) {
                     wc_add_notice(sprintf('<a href="%s" class="button wc-forward">%s</a> %s', WC()->cart->get_cart_url(), __('View Cart', 'woocommerce'), sprintf(__('&quot;%1$s&quot; cannot be added to the cart because the option selected for &quot;%2$s&quot; does not have enough stock &mdash; we have %3$s in stock and you already have %4$s in your cart.', 'woocommerce-product-bundles'), get_the_title($bundle_id), $product_data->get_title(), $product_data->get_stock_quantity(), $product_qty_in_cart[$managed_item_id])), 'error');
                     return false;
                 }
                 // Products
             } else {
                 if (isset($product_qty_in_cart[$managed_item_id]) && !$product_data->has_enough_stock($product_qty_in_cart[$managed_item_id] + $quantity)) {
                     wc_add_notice(sprintf('<a href="%s" class="button wc-forward">%s</a> %s', WC()->cart->get_cart_url(), __('View Cart', 'woocommerce'), sprintf(__('&quot;%1$s&quot; cannot be added to the cart because there is not enough stock of &quot;%2$s&quot; &mdash; we have %3$s in stock and you already have %4$s in your cart.', 'woocommerce-product-bundles'), get_the_title($bundle_id), $product_data->get_title(), $product_data->get_stock_quantity(), $product_qty_in_cart[$managed_item_id])), 'error');
                     return false;
                 }
             }
         }
     }
     return true;
 }
 /**
  * Handles adding bundled products via ajax.
  *
  * @return void
  */
 function ajax_add_bundled_product()
 {
     global $woocommerce_bundles;
     check_ajax_referer('wc_bundles_add_bundled_product', 'security');
     $loop = intval($_POST['id']);
     $post_id = intval($_POST['post_id']);
     $product_id = intval($_POST['product_id']);
     $title = $woocommerce_bundles->helpers->get_product_title($product_id);
     $product = WC_PB_Core_Compatibility::wc_get_product($product_id);
     $response = array();
     $response['markup'] = '';
     $response['message'] = '';
     if ($title && $product) {
         if (in_array($product->product_type, array('simple', 'variable', 'subscription'))) {
             ob_start();
             include 'html-bundled-product-admin.php';
             $response['markup'] = ob_get_clean();
         } else {
             $response['message'] = __('The selected product cannot be bundled. Please select a simple product, a variable product, or a simple subscription.', 'woocommerce-product-bundles');
         }
     } else {
         $response['message'] = __('The selected product is invalid.', 'woocommerce-product-bundles');
     }
     header('Content-Type: application/json; charset=utf-8');
     echo json_encode($response);
     die;
 }
 /**
  * Hide attributes if they correspond to filtered-out variations.
  *
  * @param  string   $output     original output
  * @param  array    $attribute  attribute data
  * @param  array    $values     attribute values
  * @return string               modified output
  */
 public function bundled_item_attribute($output, $attribute, $values)
 {
     if ($attribute['is_variation']) {
         $variation_attribute_values = array();
         $bundled_item = $this->get_bundled_item($this->listing_attributes_of);
         $bundled_item_variations = $bundled_item->get_product_variations();
         if (empty($bundled_item_variations)) {
             return $output;
         }
         $attribute_key = 'attribute_' . sanitize_title($attribute['name']);
         // Find active attribute values from the bundled item variation data.
         foreach ($bundled_item_variations as $variation_data) {
             if (isset($variation_data['attributes'][$attribute_key])) {
                 $variation_attribute_values[] = $variation_data['attributes'][$attribute_key];
                 $variation_attribute_values = array_unique($variation_attribute_values);
             }
         }
         if (!empty($variation_attribute_values) && in_array('', $variation_attribute_values)) {
             return $output;
         }
         $attribute_name = $attribute['name'];
         $filtered_values = array();
         if ($attribute['is_taxonomy']) {
             $product_terms = WC_PB_Core_Compatibility::wc_get_product_terms($bundled_item->product_id, $attribute_name, array('fields' => 'all'));
             foreach ($product_terms as $product_term) {
                 if (in_array($product_term->slug, $variation_attribute_values)) {
                     $filtered_values[] = $product_term->name;
                 }
             }
             return wpautop(wptexturize(implode(', ', $filtered_values)));
         } else {
             foreach ($values as $value) {
                 $check_value = WC_PB_Core_Compatibility::is_wc_version_gte_2_4() ? $value : sanitize_title($value);
                 if (in_array($check_value, $variation_attribute_values)) {
                     $filtered_values[] = $value;
                 }
             }
             return wpautop(wptexturize(implode(', ', $filtered_values)));
         }
     }
     return $output;
 }
">
						<td class="label">
							<label for="<?php 
        echo sanitize_title($attribute_name) . '_' . $bundled_item->item_id;
        ?>
"><?php 
        echo wc_attribute_label($attribute_name);
        ?>
 <abbr class="required" title="<?php 
        _e('Required option', 'woocommerce-product-bundles');
        ?>
">*</abbr></label>
						</td>
						<td class="value"><?php 
        $selected = isset($_REQUEST[$bundle_fields_prefix . 'bundle_attribute_' . sanitize_title($attribute_name) . '_' . $bundled_item->item_id]) ? wc_clean($_REQUEST[$bundle_fields_prefix . 'bundle_attribute_' . sanitize_title($attribute_name) . '_' . $bundled_item->item_id]) : $bundled_item->get_selected_product_variation_attribute($attribute_name);
        WC_PB_Core_Compatibility::wc_dropdown_variation_attribute_options(array('options' => $options, 'attribute' => $attribute_name, 'name' => $bundle_fields_prefix . 'bundle_attribute_' . sanitize_title($attribute_name) . '_' . $bundled_item->item_id, 'product' => $bundled_product, 'selected' => $selected));
        echo end($attribute_keys) === $attribute_name ? '<a class="reset_variations" href="#">' . __('Clear', 'woocommerce-product-bundles') . '</a>' : '';
        ?>
</td>
					</tr><?php 
    }
    ?>
</tbody>
		</table><?php 
    /**
     * woocommerce_bundled_product_add_to_cart hook.
     *
     * Used to output content normally hooked to 'woocommerce_before_add_to_cart_button'.
     */
    do_action('woocommerce_bundled_product_add_to_cart', $bundled_product->id, $bundled_item);
    ?>
 /**
  * Inherit coupon validity from parent:
  *
  * - Coupon is invalid for bundled item if parent is excluded.
  * - Coupon is valid for bundled item if valid for parent, unless bundled item is excluded.
  *
  * @param  bool       $valid
  * @param  WC_Product $product
  * @param  WC_Coupon  $coupon
  * @param  array      $cart_item
  * @return bool
  */
 public function woo_bundles_coupon_validity($valid, $product, $coupon, $cart_item)
 {
     if (!empty(WC()->cart)) {
         $cart_contents = WC()->cart->cart_contents;
         if (!empty($cart_item['bundled_by']) && !empty($cart_item['bundled_item_id'])) {
             $bundle_cart_key = $cart_item['bundled_by'];
             if (isset($cart_contents[$bundle_cart_key])) {
                 $bundle = $cart_contents[$bundle_cart_key]['data'];
                 $bundle_id = $bundle->id;
                 if (apply_filters('woocommerce_bundles_inherit_coupon_validity', true, $product, $coupon, $cart_item, $cart_contents[$bundle_cart_key])) {
                     if ($valid) {
                         $parent_excluded = false;
                         // Parent ID excluded from the discount.
                         if (sizeof($coupon->exclude_product_ids) > 0) {
                             if (in_array($bundle_id, $coupon->exclude_product_ids)) {
                                 $parent_excluded = true;
                             }
                         }
                         // Parent category excluded from the discount.
                         if (sizeof($coupon->exclude_product_categories) > 0) {
                             $product_cats = WC_PB_Core_Compatibility::wc_get_product_cat_ids($bundle_id);
                             if (sizeof(array_intersect($product_cats, $coupon->exclude_product_categories)) > 0) {
                                 $parent_excluded = true;
                             }
                         }
                         // Sale Items excluded from discount and parent on sale.
                         if ($coupon->exclude_sale_items == 'yes') {
                             $product_ids_on_sale = wc_get_product_ids_on_sale();
                             if (in_array($bundle_id, $product_ids_on_sale, true)) {
                                 $parent_excluded = true;
                             }
                         }
                         if ($parent_excluded) {
                             $valid = false;
                         }
                     } else {
                         $bundled_product_excluded = false;
                         // Bundled product ID excluded from the discount.
                         if (sizeof($coupon->exclude_product_ids) > 0) {
                             if (in_array($product->id, $coupon->exclude_product_ids) || isset($product->variation_id) && in_array($product->variation_id, $coupon->exclude_product_ids) || in_array($product->get_parent(), $coupon->exclude_product_ids)) {
                                 $bundled_product_excluded = true;
                             }
                         }
                         // Bundled product category excluded from the discount.
                         if (sizeof($coupon->exclude_product_categories) > 0) {
                             $product_cats = WC_PB_Core_Compatibility::wc_get_product_cat_ids($product->id);
                             if (sizeof(array_intersect($product_cats, $coupon->exclude_product_categories)) > 0) {
                                 $bundled_product_excluded = true;
                             }
                         }
                         // Bundled product on sale and sale items excluded from discount.
                         if ($coupon->exclude_sale_items == 'yes') {
                             $product_ids_on_sale = wc_get_product_ids_on_sale();
                             if (isset($product->variation_id)) {
                                 if (in_array($product->variation_id, $product_ids_on_sale, true)) {
                                     $bundled_product_excluded = true;
                                 }
                             } elseif (in_array($product->id, $product_ids_on_sale, true)) {
                                 $bundled_product_excluded = true;
                             }
                         }
                         if (!$bundled_product_excluded && $coupon->is_valid_for_product($bundle, $cart_contents[$bundle_cart_key])) {
                             $valid = true;
                         }
                     }
                 }
             }
         }
     }
     return $valid;
 }
Esempio n. 11
0
 /**
  * Inserts bundle contents after main wishlist bundle item is displayed.
  *
  * @param  array    $item       Wishlist item
  * @param  array    $wishlist   Wishlist
  * @return void
  */
 function woo_bundles_wishlist_after_list_item_name($item, $wishlist)
 {
     if ($item['data']->is_type('bundle') && !empty($item['stamp'])) {
         echo '<dl>';
         foreach ($item['stamp'] as $bundled_item_id => $bundled_item_data) {
             echo '<dt class="bundled_title_meta wishlist_bundled_title_meta">' . get_the_title($bundled_item_data['product_id']) . ' <strong class="bundled_quantity_meta wishlist_bundled_quantity_meta product-quantity">&times; ' . $bundled_item_data['quantity'] . '</strong></dt>';
             if (!empty($bundled_item_data['attributes'])) {
                 $attributes = '';
                 foreach ($bundled_item_data['attributes'] as $attribute_name => $attribute_value) {
                     $taxonomy = wc_attribute_taxonomy_name(str_replace('attribute_pa_', '', urldecode($attribute_name)));
                     // If this is a term slug, get the term's nice name
                     if (taxonomy_exists($taxonomy)) {
                         $term = get_term_by('slug', $attribute_value, $taxonomy);
                         if (!is_wp_error($term) && $term && $term->name) {
                             $attribute_value = $term->name;
                         }
                         $label = wc_attribute_label($taxonomy);
                         // If this is a custom option slug, get the options name
                     } else {
                         $attribute_value = apply_filters('woocommerce_variation_option_name', $attribute_value);
                         $bundled_product = WC_PB_Core_Compatibility::wc_get_product($bundled_item_data['product_id']);
                         $product_attributes = $bundled_product->get_attributes();
                         if (isset($product_attributes[str_replace('attribute_', '', $attribute_name)])) {
                             $label = wc_attribute_label($product_attributes[str_replace('attribute_', '', $attribute_name)]['name']);
                         } else {
                             $label = $attribute_name;
                         }
                     }
                     $attributes = $attributes . $label . ': ' . $attribute_value . ', ';
                 }
                 echo '<dd class="bundled_attribute_meta wishlist_bundled_attribute_meta">' . rtrim($attributes, ', ') . '</dd>';
             }
         }
         echo '</dl>';
         echo '<p class="bundled_notice wishlist_component_notice">' . __('*', 'woocommerce-product-bundles') . '&nbsp;&nbsp;<em>' . __('For accurate pricing details, please add the product in your cart.', 'woocommerce-product-bundles') . '</em></p>';
     }
 }
 /**
  * Order API Modification #3 (unused):
  *
  * Exclude/modify order items depending on the "per-item pricing" and "per-item shipping" settings.
  *
  * @param  array    $items
  * @param  WC_Order $order
  * @return array
  */
 public function order_items($items, $order)
 {
     $return_items = $items;
     if (false === self::$override_order_items_filters && apply_filters('woocommerce_bundles_filter_order_items', false, $order)) {
         $return_items = array();
         foreach ($items as $item_id => $item) {
             if (isset($item['bundled_items']) && isset($item['bundle_cart_key'])) {
                 /*
                  * Do not export bundled items that are shipped packaged in the container ("bundled" shipping).
                  * Instead, add their totals into the container and create a container "Contents" meta field to provide a description of the included products.
                  */
                 if (isset($item['per_product_shipping']) && $item['per_product_shipping'] === 'no') {
                     $bundle_key = $item['bundle_cart_key'];
                     // Aggregate contents
                     $meta_key = __('Contents', 'woocommerce-product-bundles');
                     $meta_values = array();
                     // Aggregate prices
                     $bundle_totals = array('line_subtotal' => $item['line_subtotal'], 'line_total' => $item['line_total'], 'line_subtotal_tax' => $item['line_subtotal_tax'], 'line_tax' => $item['line_tax'], 'line_tax_data' => maybe_unserialize($item['line_tax_data']));
                     foreach ($items as $child_item_id => $child_item) {
                         if (isset($child_item['bundled_by']) && $child_item['bundled_by'] === $bundle_key && isset($child_item['bundled_shipping']) && $child_item['bundled_shipping'] === 'no') {
                             /*
                              * Aggregate bundled items shipped within the container as "Contents" meta of container.
                              */
                             $child = $order->get_product_from_item($child_item);
                             if (!$child) {
                                 continue;
                             }
                             $sku = $child->get_sku();
                             if (!$sku) {
                                 $sku = '#' . (isset($child->variation_id) ? $child->variation_id : $child->id);
                             }
                             $title = WC_PB_Helpers::format_product_shop_title($child_item['name'], $child_item['qty']);
                             $meta = '';
                             if (!empty($child_item['item_meta'])) {
                                 if (!empty($child_item['item_meta'][__('Part of', 'woocommerce-product-bundles')])) {
                                     unset($child_item['item_meta'][__('Part of', 'woocommerce-product-bundles')]);
                                 }
                                 if (WC_PB_Core_Compatibility::is_wc_version_gte_2_4()) {
                                     $item_meta = new WC_Order_Item_Meta($child_item);
                                 } else {
                                     $item_meta = new WC_Order_Item_Meta($child_item['item_meta']);
                                 }
                                 $formatted_meta = $item_meta->display(true, true, '_', ', ');
                                 if ($formatted_meta) {
                                     $meta = $formatted_meta;
                                 }
                             }
                             $meta_values[] = WC_PB_Helpers::format_product_title($title, $sku, $meta, true);
                             /*
                              * Aggregate the totals of bundled items shipped within the container into the container price.
                              */
                             $bundle_totals['line_subtotal'] += $child_item['line_subtotal'];
                             $bundle_totals['line_total'] += $child_item['line_total'];
                             $bundle_totals['line_subtotal_tax'] += $child_item['line_subtotal_tax'];
                             $bundle_totals['line_tax'] += $child_item['line_tax'];
                             $child_item_line_tax_data = maybe_unserialize($child_item['line_tax_data']);
                             $bundle_totals['line_tax_data']['total'] = array_merge($bundle_totals['line_tax_data']['total'], $child_item_line_tax_data['total']);
                         }
                     }
                     $items[$item_id]['line_tax_data'] = serialize($bundle_totals['line_tax_data']);
                     $items[$item_id] = array_merge($item, $bundle_totals);
                     if (WC_PB_Core_Compatibility::is_wc_version_gte_2_4()) {
                         // Terrible hack: add an element in the 'item_meta_array' array.
                         // A puppy somewhere just died.
                         if (!empty($items[$item_id]['item_meta_array'])) {
                             $keys = array_keys($items[$item_id]['item_meta_array']);
                             $last_key = end($keys);
                             $entry = new stdClass();
                             $entry->key = $meta_key;
                             $entry->value = implode(', ', $meta_values);
                             $items[$item_id]['item_meta_array'][$last_key + 1] = $entry;
                         }
                     }
                     $items[$item_id]['item_meta'][$meta_key] = implode(', ', $meta_values);
                     $return_items[$item_id] = $items[$item_id];
                     /*
                      * If the bundled items are shipped individually ("per-item" shipping), do not export the container unless it has a non-zero price.
                      * In this case, instead of marking it as virtual, modify its weight and dimensions (tiny values) to avoid any extra shipping costs and ensure that its value is included in the shipment - @see get_product_from_item
                      */
                 } elseif ($item['line_total'] > 0) {
                     $return_items[$item_id] = $items[$item_id];
                 }
             } elseif (isset($item['bundled_by']) && isset($item['bundle_cart_key'])) {
                 if (!isset($item['bundled_shipping']) || $item['bundled_shipping'] === 'yes') {
                     $return_items[$item_id] = $items[$item_id];
                 }
             } else {
                 $return_items[$item_id] = $items[$item_id];
             }
         }
     }
     return $return_items;
 }
 /**
  * Update bundle post_meta on save.
  *
  * @return 	mixed     bundle data array configuration or false if unsuccessful
  */
 public function build_bundle_config($post_id, $posted_bundle_data)
 {
     // Process Bundled Product Configuration.
     $bundle_data = array();
     $ordered_bundle_data = array();
     $bundle_data_old = get_post_meta($post_id, '_bundle_data', true);
     $bundled_subs = 0;
     // Now start saving new data.
     $times = array();
     $save_defaults = array();
     $ordering = array();
     if (!empty($posted_bundle_data)) {
         foreach ($posted_bundle_data as $val => $data) {
             $id = isset($data['product_id']) ? $data['product_id'] : false;
             if (!$id) {
                 continue;
             }
             $terms = get_the_terms($id, 'product_type');
             $product_type = !empty($terms) && isset(current($terms)->name) ? sanitize_title(current($terms)->name) : 'simple';
             $is_sub = class_exists('WC_Subscriptions') && WC_PB()->compatibility->is_subscription($id);
             if ($id && $id > 0 && ($product_type === 'simple' || $product_type === 'variable' || $is_sub) && $post_id != $id) {
                 // Only allow saving 1 sub.
                 if ($is_sub) {
                     if ($bundled_subs > 0 && version_compare(WC_Subscriptions::$version, '2.0.0', '<')) {
                         $this->add_admin_error(sprintf(__('&quot;%1$s&quot; (#%2$s) was not saved. Only one simple Subscription per Bundle is supported.', 'woocommerce-product-bundles'), get_the_title($id), $id));
                         continue;
                     } else {
                         $bundled_subs++;
                     }
                 }
                 // Allow bundling the same item id multiple times by adding a suffix.
                 if (!isset($times[$id])) {
                     $times[$id] = 1;
                     $val = $id;
                 } else {
                     // Only allow multiple instances of non-sold-individually items.
                     if (get_post_meta($id, '_sold_individually', true) == 'yes') {
                         $this->add_admin_error(sprintf(__('&quot;%1$s&quot; (#%2$s) is sold individually and cannot be bundled more than once.', 'woocommerce-product-bundles'), get_the_title($id), $id));
                         continue;
                     }
                     $times[$id] += 1;
                     $val = isset($data['item_id']) ? $data['item_id'] : $id . '_' . $times[$id];
                 }
                 $bundle_data[$val] = array();
                 $bundle_data[$val]['product_id'] = $id;
                 // Save thumbnail preferences first.
                 if (isset($data['hide_thumbnail'])) {
                     $bundle_data[$val]['hide_thumbnail'] = 'yes';
                 } else {
                     $bundle_data[$val]['hide_thumbnail'] = 'no';
                 }
                 // Save title preferences.
                 if (isset($data['override_title'])) {
                     $bundle_data[$val]['override_title'] = 'yes';
                     $bundle_data[$val]['product_title'] = isset($data['product_title']) ? $data['product_title'] : '';
                 } else {
                     $bundle_data[$val]['override_title'] = 'no';
                 }
                 // Save description preferences.
                 if (isset($data['override_description'])) {
                     $bundle_data[$val]['override_description'] = 'yes';
                     $bundle_data[$val]['product_description'] = isset($data['product_description']) ? wp_kses_post(stripslashes($data['product_description'])) : '';
                 } else {
                     $bundle_data[$val]['override_description'] = 'no';
                 }
                 // Save optional.
                 if (isset($data['optional'])) {
                     $bundle_data[$val]['optional'] = 'yes';
                 } else {
                     $bundle_data[$val]['optional'] = 'no';
                 }
                 // Save quantity data.
                 if (isset($data['bundle_quantity'])) {
                     if (is_numeric($data['bundle_quantity'])) {
                         $quantity = absint($data['bundle_quantity']);
                         if ($quantity >= 0 && $data['bundle_quantity'] - $quantity == 0) {
                             if ($quantity !== 1 && get_post_meta($id, '_sold_individually', true) === 'yes') {
                                 $this->add_admin_error(sprintf(__('&quot;%1$s&quot; (#%2$s) is sold individually and cannot be bundled with a minimum quantity higher than 1.', 'woocommerce-product-bundles'), get_the_title($id), $id));
                                 $bundle_data[$val]['bundle_quantity'] = 1;
                             } else {
                                 $bundle_data[$val]['bundle_quantity'] = $quantity;
                             }
                         } else {
                             $this->add_admin_error(sprintf(__('The quantity you entered for &quot;%1$s%2$s&quot; (#%3$s) was not valid and has been reset. Please enter a non-negative integer value.', 'woocommerce-product-bundles'), get_the_title($id), $id != $val ? ' #' . $times[$id] : '', $id));
                         }
                     }
                 } else {
                     $bundle_data[$val]['bundle_quantity'] = 1;
                 }
                 $quantity_min = $bundle_data[$val]['bundle_quantity'];
                 // Save max quantity data.
                 if (isset($data['bundle_quantity_max']) && (is_numeric($data['bundle_quantity_max']) || $data['bundle_quantity_max'] === '')) {
                     $quantity = $data['bundle_quantity_max'] !== '' ? absint($data['bundle_quantity_max']) : '';
                     if ($quantity === '' || $quantity > 0 && $quantity >= $quantity_min && $data['bundle_quantity_max'] - $quantity == 0) {
                         if ($quantity !== 1 && get_post_meta($id, '_sold_individually', true) === 'yes') {
                             $this->add_admin_error(sprintf(__('&quot;%1$s&quot; (#%2$s) is sold individually and cannot be bundled with a maximum quantity higher than 1.', 'woocommerce-product-bundles'), get_the_title($id), $id));
                             $bundle_data[$val]['bundle_quantity_max'] = 1;
                         } else {
                             $bundle_data[$val]['bundle_quantity_max'] = $quantity;
                         }
                     } else {
                         $this->add_admin_error(sprintf(__('The maximum product quantity that you entered for &quot;%1$s%2$s&quot; (#%3$s) was not valid and has been reset. Please enter a positive integer value, at least as high as the minimum quantity. Otherwise, leave the field empty for an unlimited maximum quantity.', 'woocommerce-product-bundles'), get_the_title($id), $id != $val ? ' #' . $times[$id] : '', $id));
                     }
                 } else {
                     $bundle_data[$val]['bundle_quantity_max'] = max($quantity_min, 1);
                 }
                 // Save sale price data.
                 if (isset($data['bundle_discount'])) {
                     if (is_numeric($data['bundle_discount'])) {
                         $discount = (double) wc_format_decimal($data['bundle_discount']);
                         if ($discount < 0 || $discount > 100) {
                             $this->add_admin_error(sprintf(__('The discount value you entered for &quot;%1$s%2$s&quot; (#%3$s) was not valid and has been reset. Please enter a positive number between 0-100.', 'woocommerce-product-bundles'), get_the_title($id), $id != $val ? ' #' . $times[$id] : '', $id));
                             $bundle_data[$val]['bundle_discount'] = '';
                         } else {
                             $bundle_data[$val]['bundle_discount'] = $discount;
                         }
                     } else {
                         $bundle_data[$val]['bundle_discount'] = '';
                     }
                 } else {
                     $bundle_data[$val]['bundle_discount'] = '';
                 }
                 // Save data related to variable items.
                 if ($product_type === 'variable') {
                     // Save variation filtering options.
                     if (isset($data['filter_variations'])) {
                         if (isset($data['allowed_variations']) && count($data['allowed_variations']) > 0) {
                             $bundle_data[$val]['filter_variations'] = 'yes';
                             $bundle_data[$val]['allowed_variations'] = $data['allowed_variations'];
                             if (isset($data['hide_filtered_variations'])) {
                                 $bundle_data[$val]['hide_filtered_variations'] = 'yes';
                             } else {
                                 $bundle_data[$val]['hide_filtered_variations'] = 'no';
                             }
                         } else {
                             $bundle_data[$val]['filter_variations'] = 'no';
                             $this->add_admin_error(__('Please select at least one variation for each bundled product you want to filter.', 'woocommerce-product-bundles'));
                         }
                     } else {
                         $bundle_data[$val]['filter_variations'] = 'no';
                     }
                     // Save defaults options.
                     if (isset($data['override_defaults'])) {
                         if (isset($data['default_attributes'])) {
                             // if filters are set, check that the selections are valid.
                             if (isset($data['filter_variations']) && !empty($data['allowed_variations'])) {
                                 $allowed_variations = $data['allowed_variations'];
                                 // the array to store all valid attribute options of the iterated product.
                                 $filtered_attributes = array();
                                 // populate array with valid attributes.
                                 foreach ($allowed_variations as $variation) {
                                     $variation_data = array();
                                     // sweep the post meta for attributes.
                                     if (WC_PB_Core_Compatibility::is_wc_version_gte_2_4()) {
                                         $variation_data = wc_get_product_variation_attributes($variation);
                                     } else {
                                         $post_meta = get_post_meta($variation);
                                         foreach ($post_meta as $field => $value) {
                                             if (!strstr($field, 'attribute_')) {
                                                 continue;
                                             }
                                             $variation_data[$field] = $value[0];
                                         }
                                     }
                                     foreach ($variation_data as $name => $value) {
                                         $attribute_name = substr($name, strlen('attribute_'));
                                         $attribute_value = sanitize_title($value);
                                         // Populate array.
                                         if (!isset($filtered_attributes[sanitize_title($attribute_name)])) {
                                             $filtered_attributes[sanitize_title($attribute_name)][] = $attribute_value;
                                         } elseif (!in_array($attribute_value, $filtered_attributes[sanitize_title($attribute_name)])) {
                                             $filtered_attributes[sanitize_title($attribute_name)][] = $attribute_value;
                                         }
                                     }
                                 }
                                 // Check validity.
                                 foreach ($data['default_attributes'] as $sanitized_name => $value) {
                                     if ($value === '') {
                                         continue;
                                     }
                                     if (!in_array(sanitize_title($value), $filtered_attributes[$sanitized_name]) && !in_array('', $filtered_attributes[$sanitized_name])) {
                                         // Set option to "Any".
                                         $data['default_attributes'][$sanitized_name] = '';
                                         // Throw an error.
                                         $this->add_admin_error(sprintf(__('The defaults that you selected for &quot;%1$s%2$s&quot; (#%3$s) are inconsistent with the set of active variations. Always double-check your preferences before saving, and always save any changes made to the variation filters before choosing new defaults.', 'woocommerce-product-bundles'), get_the_title($id), $id != $val ? ' #' . $times[$id] : '', $id));
                                         continue;
                                     }
                                 }
                             }
                             // Save.
                             foreach ($data['default_attributes'] as $sanitized_name => $value) {
                                 $bundle_data[$val]['bundle_defaults'][$sanitized_name] = $value;
                             }
                             $bundle_data[$val]['override_defaults'] = 'yes';
                         }
                     } else {
                         $bundle_data[$val]['override_defaults'] = 'no';
                     }
                 }
                 // Save visibility preferences.
                 $visibility = array('product' => 'visible', 'cart' => 'visible', 'order' => 'visible');
                 $visibility['product'] = isset($data['visibility']['product']) ? 'visible' : 'hidden';
                 $visibility['cart'] = isset($data['visibility']['cart']) ? 'visible' : 'hidden';
                 $visibility['order'] = isset($data['visibility']['order']) ? 'visible' : 'hidden';
                 if ($visibility['product'] === 'hidden') {
                     if ($product_type === 'variable') {
                         if ($bundle_data[$val]['override_defaults'] === 'yes') {
                             if (isset($data['default_attributes'])) {
                                 foreach ($data['default_attributes'] as $default_name => $default_value) {
                                     if (!$default_value) {
                                         $visibility['product'] = 'visible';
                                         $this->add_admin_error(sprintf(__('&quot;%1$s%2$s&quot; (#%s) cannot be hidden from the single-product template unless all default options of the bundled product are defined.', 'woocommerce-product-bundles'), get_the_title($id), $id != $val ? ' #' . $times[$id] : '', $id));
                                         break;
                                     }
                                 }
                             } else {
                                 $visibility['product'] = 'visible';
                             }
                         } else {
                             $this->add_admin_error(sprintf(__('&quot;%1$s%2$s&quot; (#%3$s) cannot be hidden from the single-product template unless all default options of the bundled product are defined.', 'woocommerce-product-bundles'), get_the_title($id), $id != $val ? ' #' . $times[$id] : '', $id));
                             $visibility['product'] = 'visible';
                         }
                     }
                 }
                 $bundle_data[$val]['visibility'] = $visibility;
                 // Save position data.
                 if (isset($data['bundle_order'])) {
                     $ordering[(int) $data['bundle_order']] = $val;
                 } else {
                     $ordering[count($ordering)] = $val;
                 }
                 $bundle_data[$val] = apply_filters('woocommerce_bundles_process_bundled_item_admin_data', $bundle_data[$val], $data, $val, $post_id);
             }
         }
         // Check empty.
         if (empty($bundle_data)) {
             return false;
         }
         // Sorting
         ksort($ordering);
         $ordered_bundle_data = array();
         foreach ($ordering as $item_id) {
             $ordered_bundle_data[$item_id] = $bundle_data[$item_id];
         }
         return $ordered_bundle_data;
     } else {
         return false;
     }
 }
 /**
  * Get bundled product price after discount, price filters excluded.
  *
  * @return mixed
  */
 private function get_bundled_product_price($product = false)
 {
     if (!$product) {
         $product = $this->product;
     }
     $price = $product->price;
     if ($price === '') {
         return $price;
     }
     if (!$this->is_priced_per_product()) {
         return 0;
     }
     if (apply_filters('woocommerce_bundled_item_discount_from_regular', true, $this)) {
         $regular_price = $product->regular_price;
     } else {
         $regular_price = $price;
     }
     $discount = $this->get_discount();
     $bundled_item_price = empty($discount) ? $price : (empty($regular_price) ? $regular_price : round((double) $regular_price * (100 - $discount) / 100, WC_PB_Core_Compatibility::wc_get_price_decimals()));
     $price = apply_filters('woocommerce_bundled_item_price', $bundled_item_price, $product, $discount, $this);
     return $price;
 }
function wc_bundles_get_product_terms($product_id, $attribute_name, $args)
{
    _deprecated_function('wc_bundles_get_product_terms', '4.13.1', 'WC_PB_Core_Compatibility::wc_get_product_terms');
    return WC_PB_Core_Compatibility::wc_get_product_terms($product_id, $attribute_name, $args);
}
 /**
  * Filter get_price() calls for bundled products to include discounts.
  *
  * @param  double       $price      unmodified price
  * @param  WC_Product   $product    the bundled product
  * @return double                   modified price
  */
 public static function filter_get_price($price, $product)
 {
     $bundled_item = self::$bundled_item;
     if ($bundled_item) {
         if ($price === '') {
             return $price;
         }
         if (!$bundled_item->is_priced_per_product()) {
             return 0;
         }
         if (apply_filters('woocommerce_bundled_item_discount_from_regular', true, $bundled_item)) {
             $regular_price = $product->get_regular_price();
         } else {
             $regular_price = $price;
         }
         $discount = $bundled_item->get_discount();
         $bundled_item_price = empty($discount) ? $price : (empty($regular_price) ? $regular_price : round((double) $regular_price * (100 - $discount) / 100, WC_PB_Core_Compatibility::wc_get_price_decimals()));
         $product->bundled_item_price = $bundled_item_price;
         $price = apply_filters('woocommerce_bundled_item_price', $bundled_item_price, $product, $discount, $bundled_item);
     }
     return $price;
 }