public static function init()
 {
     // Use WC ajax if available, otherwise fall back to WP ajax.
     if (WC_CP_Core_Compatibility::use_wc_ajax()) {
         add_action('wc_ajax_woocommerce_show_composited_product', __CLASS__ . '::show_composited_product_ajax');
         add_action('wc_ajax_woocommerce_show_component_options', __CLASS__ . '::show_component_options_ajax');
     } else {
         add_action('wp_ajax_woocommerce_show_composited_product', __CLASS__ . '::show_composited_product_ajax');
         add_action('wp_ajax_woocommerce_show_component_options', __CLASS__ . '::show_component_options_ajax');
         add_action('wp_ajax_nopriv_woocommerce_show_composited_product', __CLASS__ . '::show_composited_product_ajax');
         add_action('wp_ajax_nopriv_woocommerce_show_component_options', __CLASS__ . '::show_component_options_ajax');
     }
 }
 function __construct($product_id, $component_id, $parent)
 {
     $this->product = WC_CP_Core_Compatibility::wc_get_product($product_id);
     if ($this->product) {
         $this->component_data = $parent->get_component_data($component_id);
         $this->component_id = $component_id;
         $this->per_product_pricing = $parent->is_priced_per_product();
         $this->composite_id = $parent->id;
         $this->add_filters();
         $this->init();
         $this->remove_filters();
     }
 }
 /**
  * Front end styles and scripts.
  *
  * @return void
  */
 public function wc_cp_frontend_scripts()
 {
     $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
     $dependencies = array('jquery', 'jquery-blockui', 'wc-add-to-cart-variation');
     if (class_exists('WC_Bundles')) {
         $dependencies[] = 'wc-add-to-cart-bundle';
     }
     if (class_exists('Product_Addon_Display')) {
         $dependencies[] = 'woocommerce-addons';
     }
     // Add any custom script dependencies here.
     $dependencies = apply_filters('woocommerce_composite_script_dependencies', $dependencies);
     wp_register_script('wc-add-to-cart-composite', WC_CP()->plugin_url() . '/assets/js/add-to-cart-composite' . $suffix . '.js', $dependencies, WC_CP()->version);
     wp_register_style('wc-composite-single-css', WC_CP()->plugin_url() . '/assets/css/wc-composite-single.css', false, WC_CP()->version, 'all');
     wp_register_style('wc-composite-css', WC_CP()->plugin_url() . '/assets/css/wc-composite-styles.css', false, WC_CP()->version, 'all');
     wp_enqueue_style('wc-composite-css');
     $params = apply_filters('woocommerce_composite_front_end_params', array('small_width_threshold' => 450, 'full_width_threshold' => 450, 'legacy_width_threshold' => 450, 'i18n_qty_string' => _x(' &times; %s', 'qty string', 'woocommerce-composite-products'), 'i18n_price_string' => _x(' &ndash; %s', 'price suffix', 'woocommerce-composite-products'), 'i18n_title_string' => sprintf(_x('%1$s%2$s%3$s', 'title quantity price', 'woocommerce-composite-products'), '%t', '%q', '%p'), 'i18n_selected_product_string' => sprintf(_x('%1$s%2$s', 'product title followed by details', 'woocommerce-composite-products'), '%t', '%m'), 'i18n_free' => __('Free!', 'woocommerce'), 'i18n_total' => __('Total', 'woocommerce-composite-products') . ': ', 'i18n_none' => __('None', 'woocommerce-composite-products'), 'i18n_select_an_option' => __('Select an option&hellip;', 'woocommerce-composite-products'), 'i18n_previous_step' => __('Previous &ndash; %s', 'woocommerce-composite-products'), 'i18n_next_step' => __('Next &ndash; %s', 'woocommerce-composite-products'), 'i18n_final_step' => __('Review Configuration', 'woocommerce-composite-products'), 'i18n_reset_selection' => __('Reset selection', 'woocommerce-composite-products'), 'i18n_clear_selection' => __('Clear selection', 'woocommerce-composite-products'), 'i18n_validation_issues' => __('To continue, please resolve the following issues:', 'woocommerce-composite-products'), 'i18n_validation_issues_for' => sprintf(__('<span class="msg-source">%1$s</span> &rarr; <span class="msg-content">%2$s</span>', 'woocommerce-composite-products'), '%c', '%e'), 'i18n_unavailable_text' => __('Sorry, this product cannot be purchased at the moment.', 'woocommerce-composite-products'), 'i18n_select_component_option' => __('Select an option to continue&hellip;', 'woocommerce-composite-products'), 'i18n_select_component_option_for' => __('Select an option.', 'woocommerce-composite-products'), 'i18n_selected_component_options_no_stock' => __('Insufficient stock. To continue, please check your configuration&hellip;', 'woocommerce-composite-products'), 'i18n_selected_component_options_no_stock_for' => __('Insufficient stock. Please check your configuration.', 'woocommerce-composite-products'), 'i18n_select_product_options' => __('Select product options to continue&hellip;', 'woocommerce-composite-products'), 'i18n_select_product_options_for' => __('Select product options.', 'woocommerce-composite-products'), 'i18n_summary_empty_component' => __('Configure', 'woocommerce-composite-products'), 'i18n_summary_configured_component' => __('Change', 'woocommerce-composite-products'), 'i18n_summary_static_component' => __('View', 'woocommerce-composite-products'), 'i18n_insufficient_stock' => __('Insufficient stock: %s', 'woocommerce-composite-products'), 'i18n_comma_sep' => sprintf(_x('%1$s, %2$s', 'comma-separated items', 'woocommerce-composite-products'), '%s', '%v'), 'i18n_insufficient_item_stock' => sprintf(__('<span class="out-of-stock-component">%2$s</span> &rarr; <span class="out-of-stock-product">%1$s</span>', 'woocommerce-composite-products'), '%s', '%v'), 'i18n_reload_threshold_exceeded' => __('Loading &quot;%s&quot; options is taking a bit longer than usual. Would you like to keep trying?', 'woocommerce-composite-products'), 'i18n_no_compat_options' => __('No compatible options to display.', 'woocommerce-composite-products'), 'no_compat_options_autoload' => 'yes', 'currency_symbol' => get_woocommerce_currency_symbol(), 'currency_position' => esc_attr(stripslashes(get_option('woocommerce_currency_pos'))), 'currency_format_num_decimals' => absint(get_option('woocommerce_price_num_decimals')), 'currency_format_decimal_sep' => esc_attr(stripslashes(get_option('woocommerce_price_decimal_sep'))), 'currency_format_thousand_sep' => esc_attr(stripslashes(get_option('woocommerce_price_thousand_sep'))), 'currency_format_trim_zeros' => false === apply_filters('woocommerce_price_trim_zeros', false) ? 'no' : 'yes', 'script_debug' => 'no', 'show_quantity_buttons' => 'no', 'transition_type' => 'slide', 'relocated_content_reset_on_return' => 'yes', 'is_wc_version_gte_2_3' => WC_CP_Core_Compatibility::is_wc_version_gte_2_3() ? 'yes' : 'no', 'is_wc_version_gte_2_4' => WC_CP_Core_Compatibility::is_wc_version_gte_2_4() ? 'yes' : 'no', 'use_wc_ajax' => WC_CP_Core_Compatibility::use_wc_ajax() ? 'yes' : 'no'));
     wp_localize_script('wc-add-to-cart-composite', 'wc_composite_params', $params);
 }
function wc_composite_get_product_terms($product_id, $attribute_name, $args)
{
    if (WC_CP_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 static function get_product_variation_title($variation_id)
 {
     if (is_object($variation_id)) {
         $variation = $variation_id;
     } else {
         $variation = wc_get_product($variation_id);
     }
     if (!$variation) {
         return false;
     }
     if (WC_CP_Core_Compatibility::is_wc_version_gte_2_5()) {
         $description = $variation->get_formatted_variation_attributes(true);
     } else {
         $description = wc_get_formatted_variation($variation->get_variation_attributes(), true);
     }
     $title = $variation->get_title();
     $sku = $variation->get_sku();
     if ($sku) {
         $identifier = $sku;
     } else {
         $identifier = '#' . $variation->variation_id;
     }
     return self::format_product_title($title, $identifier, $description);
 }
 /**
  * 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 wc_cp_coupon_validity($valid, $product, $coupon, $cart_item)
 {
     if (!empty(WC()->cart)) {
         $cart_contents = WC()->cart->cart_contents;
         if (!empty($cart_item['composite_parent']) && !empty($cart_item['composite_item'])) {
             $composite_cart_key = $cart_item['composite_parent'];
             if (isset($cart_contents[$composite_cart_key])) {
                 $composite = $cart_contents[$composite_cart_key]['data'];
                 $composite_id = $composite->id;
                 if (apply_filters('woocommerce_composite_inherit_coupon_validity', true, $product, $coupon, $cart_item, $cart_contents[$composite_cart_key])) {
                     if ($valid) {
                         $parent_excluded = false;
                         // Parent ID excluded from the discount.
                         if (sizeof($coupon->exclude_product_ids) > 0) {
                             if (in_array($composite_id, $coupon->exclude_product_ids)) {
                                 $parent_excluded = true;
                             }
                         }
                         // Parent category excluded from the discount.
                         if (sizeof($coupon->exclude_product_categories) > 0) {
                             $product_cats = WC_CP_Core_Compatibility::wc_get_product_cat_ids($composite_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($composite_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_CP_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($composite, $cart_contents[$composite_cart_key])) {
                             $valid = true;
                         }
                     }
                 }
             }
         }
     }
     return $valid;
 }
 /**
  * Get min/max composite regular price.
  *
  * @param  string $min_or_max
  * @return double
  */
 public function get_composite_regular_price($min_or_max = 'min', $display = false)
 {
     if ($this->is_priced_per_product()) {
         if (!$this->is_synced()) {
             $this->sync_composite();
         }
         $price = $min_or_max === 'min' ? $this->min_composite_regular_price : $this->max_composite_regular_price;
         if ($price && $display) {
             $display_price = WC_CP()->api->get_composited_product_price($this, $this->get_base_regular_price());
             foreach ($this->price_index['regular_price'][$min_or_max] as $component_id => $product_id) {
                 $component_data = $this->get_component_data($component_id);
                 $item_qty = $component_data['optional'] === 'yes' && $min_or_max === 'min' ? 0 : $component_data['quantity_' . $min_or_max];
                 if ($item_qty) {
                     $composited_product = $this->get_composited_product($component_id, $product_id);
                     $display_price += $item_qty * $composited_product->get_regular_price($min_or_max, true);
                 }
             }
             $price = $display_price;
         }
     } else {
         $price = parent::get_regular_price();
         if ($display) {
             $price = WC_CP_Core_Compatibility::is_wc_version_gte_2_4() ? parent::get_display_price($price) : WC_CP()->api->get_composited_product_price($this, $price);
         }
     }
     return $price;
 }
 /**
  * Adds configuration-specific cart-item data.
  *
  * @param  array 	$cart_item_data
  * @param  int 		$product_id
  * @return void
  */
 function wc_cp_add_cart_item_data($cart_item_data, $product_id)
 {
     global $woocommerce_composite_products;
     // Get product type
     $terms = get_the_terms($product_id, 'product_type');
     $product_type = !empty($terms) && isset(current($terms)->name) ? sanitize_title(current($terms)->name) : 'simple';
     if ($product_type === 'composite' && isset($_REQUEST['wccp_component_selection']) && is_array($_REQUEST['wccp_component_selection'])) {
         // Create a unique array with the composite configuration
         $composite_config = array();
         // Get composite data
         $composite = WC_CP_Core_Compatibility::wc_get_product($product_id);
         $composite_data = $composite->get_composite_data();
         foreach ($_REQUEST['wccp_component_selection'] as $component_id => $composited_product_id) {
             $composited_product_quantity = isset($_REQUEST['wccp_component_quantity'][$component_id]) ? absint($_REQUEST['wccp_component_quantity'][$component_id]) : absint($composite_data[$component_id]['quantity_min']);
             if ($composited_product_id) {
                 $composited_product_wrapper = $composite->get_composited_product($component_id, $composited_product_id);
                 if (!$composited_product_wrapper) {
                     continue;
                 }
                 $composited_product = $composited_product_wrapper->get_product();
                 $composited_product_type = $composited_product->product_type;
                 if ($composited_product->sold_individually === 'yes' && $composited_product_quantity > 1) {
                     $composited_product_quantity = 1;
                 }
             }
             $composite_config[$component_id]['product_id'] = $composited_product_id;
             $composite_config[$component_id]['composite_id'] = $product_id;
             $composite_config[$component_id]['quantity'] = $composited_product_quantity;
             $composite_config[$component_id]['title'] = $composite_data[$component_id]['title'];
             $composite_config[$component_id]['quantity_min'] = $composite_data[$component_id]['quantity_min'];
             $composite_config[$component_id]['quantity_max'] = $composite_data[$component_id]['quantity_max'];
             $composite_config[$component_id]['discount'] = isset($composite_data[$component_id]['discount']) ? $composite_data[$component_id]['discount'] : 0;
             $composite_config[$component_id]['optional'] = $composite_data[$component_id]['optional'];
             // Continue when selected product is 'None'
             if (!$composited_product_id || $composited_product_id === '' || $composited_product_quantity === 0) {
                 $composite_config[$component_id]['type'] = 'none';
                 $composite_config[$component_id]['price'] = 0;
                 continue;
             } else {
                 $composite_config[$component_id]['type'] = $composited_product_type;
             }
             if ($composited_product_type === 'variable') {
                 $attributes_config = array();
                 $attributes = (array) maybe_unserialize(get_post_meta($composited_product_id, '_product_attributes', true));
                 foreach ($attributes as $attribute) {
                     if (!$attribute['is_variation']) {
                         continue;
                     }
                     $taxonomy = 'attribute_' . sanitize_title($attribute['name']);
                     // has already been checked for validity in function 'wc_cp_validation'
                     $value = sanitize_title(trim(stripslashes($_REQUEST['wccp_' . $taxonomy][$component_id])));
                     if ($attribute['is_taxonomy']) {
                         $attributes_config[$taxonomy] = $value;
                     } else {
                         // For custom attributes, get the name from the slug
                         $options = array_map('trim', explode(WC_DELIMITER, $attribute['value']));
                         foreach ($options as $option) {
                             if (sanitize_title($option) == $value) {
                                 $value = $option;
                                 break;
                             }
                         }
                         $attributes_config[$taxonomy] = $value;
                     }
                 }
                 $composite_config[$component_id]['variation_id'] = $_REQUEST['wccp_variation_id'][$component_id];
                 $composite_config[$component_id]['attributes'] = $attributes_config;
             }
             $composited_product_variation_id = isset($composite_config[$component_id]['variation_id']) ? $composite_config[$component_id]['variation_id'] : '';
             $composite_config[$component_id]['price'] = $this->wc_cp_get_composited_product_price($composited_product_id, $composited_product_variation_id, $component_id, $composite);
             $composite_config[$component_id] = apply_filters('woocommerce_composite_component_cart_item_identifier', $composite_config[$component_id], $component_id);
         }
         $cart_item_data['composite_data'] = $composite_config;
         // Prepare additional data for later use
         $cart_item_data['composite_children'] = array();
         return $cart_item_data;
     } else {
         return $cart_item_data;
     }
 }
 /**
  * Initialize composited product price data, if needed.
  *
  * @return void
  */
 public function init()
 {
     // Init prices
     $this->min_price = 0;
     $this->max_price = 0;
     $this->min_regular_price = 0;
     $this->max_regular_price = 0;
     $this->min_price_incl_tax = 0;
     $this->min_price_excl_tax = 0;
     $id = $this->get_product()->id;
     // Sold individually status.
     $this->is_sold_individually = get_post_meta($id, '_sold_individually', true);
     // Purchasable status.
     if (!$this->per_product_pricing && $this->product->price === '') {
         $this->product->price = 0;
     }
     $this->is_purchasable = $this->product->is_purchasable();
     // Calculate product prices.
     if ($this->per_product_pricing && $this->is_purchasable) {
         $composited_product = $this->product;
         $product_type = $composited_product->product_type;
         $this->is_nyp = false;
         /*-----------------------------------------------------------------------------------*/
         /*  Simple Products and Static Bundles.                                              */
         /*-----------------------------------------------------------------------------------*/
         if ($product_type === 'simple') {
             $product_price = $this->get_raw_price();
             $product_regular_price = $this->get_raw_regular_price();
             // Name your price support.
             if (WC_CP()->compatibility->is_nyp($composited_product)) {
                 $product_price = $product_regular_price = WC_Name_Your_Price_Helpers::get_minimum_price($id) ? WC_Name_Your_Price_Helpers::get_minimum_price($id) : 0;
                 $this->is_nyp = true;
             }
             $this->min_price = $this->max_price = $product_price;
             $this->min_regular_price = $this->max_regular_price = $product_regular_price;
             /*-----------------------------------------------------------------------------------*/
             /*  Variable Products.                                                               */
             /*-----------------------------------------------------------------------------------*/
         } elseif ($product_type === 'variable') {
             if (WC_CP_Core_Compatibility::is_wc_version_gte_2_4()) {
                 $variation_prices = $composited_product->get_variation_prices(false);
                 if (!empty($this->component_data['discount']) && apply_filters('woocommerce_composited_product_discount_from_regular', true, $this->component_id, $this->composite->id)) {
                     $variation_price_ids = array_keys($variation_prices['regular_price']);
                 } else {
                     $variation_price_ids = array_keys($variation_prices['price']);
                 }
                 $min_variation_price_id = current($variation_price_ids);
                 $max_variation_price_id = end($variation_price_ids);
             } else {
                 if (!empty($this->component_data['discount']) && apply_filters('woocommerce_composited_product_discount_from_regular', true, $this->component_id, $this->composite->id)) {
                     // Product may need to be synced.
                     if ($composited_product->get_variation_regular_price('min', false) === false) {
                         $composited_product->variable_product_sync();
                     }
                     $min_variation_price_id = get_post_meta($this->product->id, '_min_regular_price_variation_id', true);
                     $max_variation_price_id = get_post_meta($this->product->id, '_max_regular_price_variation_id', true);
                 } else {
                     // Product may need to be synced.
                     if ($composited_product->get_variation_price('min', false) === false) {
                         $composited_product->variable_product_sync();
                     }
                     $min_variation_price_id = get_post_meta($this->product->id, '_min_price_variation_id', true);
                     $max_variation_price_id = get_post_meta($this->product->id, '_max_price_variation_id', true);
                 }
             }
             $min_variation = $composited_product->get_child($min_variation_price_id);
             $max_variation = $composited_product->get_child($max_variation_price_id);
             if ($min_variation && $max_variation) {
                 $this->min_price_product = $this->min_regular_price_product = $min_variation;
                 $this->max_price_product = $this->min_regular_price_product = $max_variation;
                 $this->min_price = $this->get_raw_price($min_variation);
                 $this->max_price = $this->get_raw_price($max_variation);
                 $min_variation_regular_price = $this->get_raw_regular_price($min_variation);
                 $max_variation_regular_price = $this->get_raw_regular_price($max_variation);
                 // The variation with the lowest price may have a higher regular price then the variation with the highest price.
                 if ($max_variation_regular_price < $min_variation_regular_price) {
                     $this->min_regular_price_product = $max_variation;
                     $this->max_regular_price_product = $min_variation;
                 }
                 $this->min_regular_price = min($min_variation_regular_price, $max_variation_regular_price);
                 $this->max_regular_price = max($min_variation_regular_price, $max_variation_regular_price);
             }
             /*-----------------------------------------------------------------------------------*/
             /*  Other Product Types.                                                             */
             /*-----------------------------------------------------------------------------------*/
         } else {
             $price = $this->get_raw_price();
             $this->min_price = apply_filters('woocommerce_composited_product_min_price', $price, $this);
             $this->max_price = apply_filters('woocommerce_composited_product_max_price', $price, $this);
             $regular_price = $this->get_raw_regular_price();
             $this->min_regular_price = apply_filters('woocommerce_composited_product_min_regular_price', $regular_price, $this);
             $this->max_regular_price = apply_filters('woocommerce_composited_product_max_regular_price', $regular_price, $this);
             $this->is_nyp = apply_filters('woocommerce_composited_product_is_nyp', $this->is_nyp, $this);
         }
     }
 }
 /**
  * Search for component options and echo json.
  *
  * @param   string $x (default: '')
  * @param   string $post_types (default: array('product'))
  * @return  void
  */
 public function json_search_component_options($x = 'default', $post_types = array('product'))
 {
     global $woocommerce_composite_products;
     ob_start();
     check_ajax_referer('search-products', 'security');
     $term = (string) wc_clean(stripslashes($_GET['term']));
     $composite_id = $_GET['composite_id'];
     $component_id = $_GET['component_id'];
     if (empty($term) || empty($composite_id) || empty($component_id)) {
         die;
     }
     $composite_data = get_post_meta($composite_id, '_bto_data', true);
     $component_data = isset($composite_data[$component_id]) ? $composite_data[$component_id] : false;
     if (false == $composite_data || false == $component_data) {
         die;
     }
     // Run query to get component option ids
     $component_options = $woocommerce_composite_products->api->get_component_options($component_data);
     // Add variation ids to component option ids
     if ($x == 'search_component_options_in_scenario') {
         $variations_args = array('post_type' => array('product_variation'), 'post_status' => 'publish', 'posts_per_page' => -1, 'post_parent' => array_merge(array('0'), $component_options), 'fields' => 'ids');
         $component_options_variations = get_posts($variations_args);
         $component_options = array_merge($component_options, $component_options_variations);
     }
     if (is_numeric($term)) {
         $args = array('post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => -1, 'post__in' => array(0, $term), 'fields' => 'ids');
         $args2 = array('post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => -1, 'meta_query' => array(array('key' => '_sku', 'value' => $term, 'compare' => 'LIKE')), 'fields' => 'ids');
         $args3 = array('post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => -1, 'post_parent' => $term, 'fields' => 'ids');
         $posts = array_unique(array_intersect($component_options, array_merge(get_posts($args), get_posts($args2), get_posts($args3))));
     } else {
         $args = array('post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => -1, 's' => $term, 'fields' => 'ids');
         $args2 = array('post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => -1, 'meta_query' => array(array('key' => '_sku', 'value' => $term, 'compare' => 'LIKE')), 'fields' => 'ids');
         $posts = array_unique(array_intersect($component_options, array_merge(get_posts($args), get_posts($args2))));
     }
     $found_products = array();
     $loop = 0;
     if ($posts) {
         foreach ($posts as $post) {
             if ($loop > 1000) {
                 continue;
             }
             $product = WC_CP_Core_Compatibility::wc_get_product($post);
             if ($product->product_type === 'variation') {
                 $found_products[$post] = $woocommerce_composite_products->api->get_product_variation_title($product);
             } else {
                 if ($x == 'search_component_options_in_scenario' && $product->product_type === 'variable') {
                     $found_products[$post] = $woocommerce_composite_products->api->get_product_title($product) . ' ' . __('&mdash; All Variations', 'woocommerce-composite-products');
                 } else {
                     $found_products[$post] = $woocommerce_composite_products->api->get_product_title($product);
                 }
             }
             $loop++;
         }
     }
     wp_send_json($found_products);
 }
">
					<td class="label">
						<label for="<?php 
    echo sanitize_title($attribute_name);
    ?>
"><?php 
    echo wc_attribute_label($attribute_name);
    ?>
 <abbr class="required" title="<?php 
    _e('Required option', 'woocommerce-composite-products');
    ?>
">*</abbr></label>
					</td>
					<td class="value"><?php 
    $selected = isset($_REQUEST['wccp_attribute_' . sanitize_title($attribute_name)][$component_id]) ? wc_clean($_REQUEST['wccp_attribute_' . sanitize_title($attribute_name)][$component_id]) : WC_CP_Core_Compatibility::wc_get_variation_default_attribute($product, $attribute_name);
    WC_CP_Core_Compatibility::wc_dropdown_variation_attribute_options(array('options' => $options, 'attribute' => $attribute_name, 'name' => 'wccp_attribute_' . sanitize_title($attribute_name) . '[' . $component_id . ']', 'product' => $product, 'selected' => $selected));
    echo end($attribute_keys) === $attribute_name ? '<a class="reset_variations" href="#">' . __('Clear', 'woocommerce-composite-products') . '</a>' : '';
    ?>
</td>
				</tr><?php 
}
?>
</tbody>
	</table><?php 
/**
 * woocommerce_composited_product_add_to_cart hook.
 *
 * Useful for outputting content normally hooked to 'woocommerce_before_add_to_cart_button'.
 */
do_action('woocommerce_composited_product_add_to_cart', $product, $component_id, $composite_product);
?>
 /**
  * Admin writepanel scripts.
  *
  * @return void
  */
 public function composite_admin_scripts()
 {
     $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
     if (WC_CP_Core_Compatibility::is_wc_version_gte_2_2()) {
         $writepanel_dependency = 'wc-admin-meta-boxes';
     } else {
         $writepanel_dependency = 'woocommerce_admin_meta_boxes';
     }
     wp_register_script('wc_composite_writepanel', WC_CP()->plugin_url() . '/assets/js/wc-composite-write-panels' . $suffix . '.js', array('jquery', 'jquery-ui-datepicker', $writepanel_dependency), WC_CP()->version);
     wp_register_style('wc_composite_writepanel_css', WC_CP()->plugin_url() . '/assets/css/wc-composite-write-panels.css', array('woocommerce_admin_styles'), WC_CP()->version);
     wp_register_style('wc_composite_edit_order_css', WC_CP()->plugin_url() . '/assets/css/wc-composite-edit-order.css', array('woocommerce_admin_styles'), WC_CP()->version);
     // Get admin screen id.
     $screen = get_current_screen();
     // WooCommerce admin pages.
     if (in_array($screen->id, array('product'))) {
         wp_enqueue_script('wc_composite_writepanel');
         $params = array('save_composite_nonce' => wp_create_nonce('wc_bto_save_composite'), 'add_component_nonce' => wp_create_nonce('wc_bto_add_component'), 'add_scenario_nonce' => wp_create_nonce('wc_bto_add_scenario'), 'i18n_no_default' => __('No default option&hellip;', 'woocommerce-composite-products'), 'i18n_all' => __('All Products and Variations', 'woocommerce-composite-products'), 'i18n_none' => __('None', 'woocommerce-composite-products'), 'is_wc_version_gte_2_3' => WC_CP_Core_Compatibility::is_wc_version_gte_2_3() ? 'yes' : 'no', 'i18n_matches_1' => _x('One result is available, press enter to select it.', 'enhanced select', 'woocommerce'), 'i18n_matches_n' => _x('%qty% results are available, use up and down arrow keys to navigate.', 'enhanced select', 'woocommerce'), 'i18n_no_matches' => _x('No matches found', 'enhanced select', 'woocommerce'), 'i18n_ajax_error' => _x('Loading failed', 'enhanced select', 'woocommerce'), 'i18n_input_too_short_1' => _x('Please enter 1 or more characters', 'enhanced select', 'woocommerce'), 'i18n_input_too_short_n' => _x('Please enter %qty% or more characters', 'enhanced select', 'woocommerce'), 'i18n_input_too_long_1' => _x('Please delete 1 character', 'enhanced select', 'woocommerce'), 'i18n_input_too_long_n' => _x('Please delete %qty% characters', 'enhanced select', 'woocommerce'), 'i18n_selection_too_long_1' => _x('You can only select 1 item', 'enhanced select', 'woocommerce'), 'i18n_selection_too_long_n' => _x('You can only select %qty% items', 'enhanced select', 'woocommerce'), 'i18n_load_more' => _x('Loading more results&hellip;', 'enhanced select', 'woocommerce'), 'i18n_searching' => _x('Searching&hellip;', 'enhanced select', 'woocommerce'));
         wp_localize_script('wc_composite_writepanel', 'wc_composite_admin_params', $params);
     }
     if (in_array($screen->id, array('edit-product', 'product'))) {
         wp_enqueue_style('wc_composite_writepanel_css');
     }
     if (in_array($screen->id, array('shop_order', 'edit-shop_order'))) {
         wp_enqueue_style('wc_composite_edit_order_css');
     }
 }
function wc_composite_dropdown_variation_attribute_options($args = array())
{
    _deprecated_function('wc_composite_dropdown_variation_attribute_options()', '3.5.0', 'WC_CP_Core_Compatibility::wc_dropdown_variation_attribute_options()');
    return WC_CP_Core_Compatibility::wc_dropdown_variation_attribute_options($args);
}
 /**
  * Validate that all managed items in the collection are in stock.
  *
  * @param  int    $composite_id
  * @return boolean
  */
 public function validate_stock($composite_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_CP_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(__('This &quot;%1$s&quot; configuration cannot be added to the cart &mdash; only 1 &quot;%2$s&quot; may be purchased.', 'woocommerce-composite-products'), get_the_title($composite_id), $product_data->get_title()), 'error');
             return false;
         }
         // Check product is_purchasable
         if (!$product_data->is_purchasable()) {
             wc_add_notice(sprintf(__('This &quot;%1$s&quot; configuration cannot be added to the cart &mdash; &quot;%2$s&quot; cannot be purchased.', 'woocommerce-composite-products'), get_the_title($composite_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(__('This &quot;%1$s&quot; configuration cannot be added to the cart &mdash; your &quot;%2$s&quot; selection is out of stock.', 'woocommerce-composite-products'), get_the_title($composite_id), $product_data->get_title()), 'error');
             } else {
                 wc_add_notice(sprintf(__('This &quot;%1$s&quot; configuration cannot be added to the cart &mdash; &quot;%2$s&quot; is out of stock.', 'woocommerce-composite-products'), get_the_title($composite_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(__('This &quot;%1$s&quot; configuration cannot be added to the cart &mdash; your &quot;%2$s&quot; selection does not have enough stock (%3$s remaining).', 'woocommerce-composite-products'), get_the_title($composite_id), $product_data->get_title(), $product_data->get_stock_quantity()), 'error');
             } else {
                 wc_add_notice(sprintf(__('This &quot;%1$s&quot; configuration cannot be added to the cart &mdash; there is not enough stock of &quot;%2$s&quot; (%3$s remaining).', 'woocommerce-composite-products'), get_the_title($composite_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(__('This &quot;%1$s&quot; configuration 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-composite-products'), get_the_title($composite_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(__('This &quot;%1$s&quot; configuration 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-composite-products'), get_the_title($composite_id), $product_data->get_title(), $product_data->get_stock_quantity(), $product_qty_in_cart[$managed_item_id])), 'error');
                     return false;
                 }
             }
         }
     }
     return true;
 }
 /**
  * Inserts bundle contents after main wishlist bundle item is displayed.
  *
  * @param  array    $item       Wishlist item
  * @param  array    $wishlist   Wishlist
  * @return void
  */
 public function wishlist_after_list_item_name($item, $wishlist)
 {
     global $woocommerce_composite_products;
     if (!empty($item['composite_data'])) {
         echo '<dl>';
         foreach ($item['composite_data'] as $composited_item => $composited_item_data) {
             echo '<dt class="component_title_meta wishlist_component_title_meta">' . $composited_item_data['title'] . ':</dt>';
             echo '<dd class="component_option_meta wishlist_component_option_meta">' . get_the_title($composited_item_data['product_id']) . ' <strong class="component_quantity_meta wishlist_component_quantity_meta product-quantity">&times; ' . $composited_item_data['quantity'] . '</strong></dd>';
             if (!empty($composited_item_data['attributes'])) {
                 $attributes = '';
                 foreach ($composited_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);
                         $composited_product = WC_CP_Core_Compatibility::wc_get_product($composited_item_data['product_id']);
                         $product_attributes = $composited_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="component_attribute_meta wishlist_component_attribute_meta">' . rtrim($attributes, ', ') . '</dd>';
             }
         }
         echo '</dl>';
         echo '<p class="component_notice wishlist_component_notice">' . __('*', 'woocommerce-composite-products') . '&nbsp;&nbsp;<em>' . __('Accurate pricing info available in cart.', 'woocommerce-composite-products') . '</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_composite_filter_order_items', false, $order)) {
         $return_items = array();
         foreach ($items as $item_id => $item) {
             if (isset($item['composite_children']) && isset($item['composite_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['composite_cart_key'];
                     // Aggregate contents
                     $meta_key = __('Contents', 'woocommerce-composite-products');
                     $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['composite_parent']) && $child_item['composite_parent'] === $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_CP_Product::get_title_string($child_item['name'], $child_item['qty']);
                             $meta = '';
                             if (!empty($child_item['item_meta'])) {
                                 if (!empty($child_item['item_meta'][__('Part of', 'woocommerce-composite-products')])) {
                                     unset($child_item['item_meta'][__('Part of', 'woocommerce-composite-products')]);
                                 }
                                 if (WC_CP_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_CP_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_CP_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['composite_parent']) && isset($item['composite_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;
 }