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(); } }
/** * 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; } }
/** * Return a formatted product title based on variation id. * * @param int $item_id * @return string */ public function get_product_variation_title($variation_id) { if (is_object($variation_id)) { $variation = $variation_id; } else { $variation = WC_CP_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) { $identifier = $sku; } else { $identifier = '#' . $variation->variation_id; } return $this->format_product_title($title, $identifier, $description); }
/** * 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) . ' ' . __('— All Variations', 'woocommerce-composite-products'); } else { $found_products[$post] = $woocommerce_composite_products->api->get_product_title($product); } } $loop++; } } wp_send_json($found_products); }
/** * 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 "%1$s" configuration cannot be added to the cart — only 1 "%2$s" 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 "%1$s" configuration cannot be added to the cart — "%2$s" 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 "%1$s" configuration cannot be added to the cart — your "%2$s" selection is out of stock.', 'woocommerce-composite-products'), get_the_title($composite_id), $product_data->get_title()), 'error'); } else { wc_add_notice(sprintf(__('This "%1$s" configuration cannot be added to the cart — "%2$s" 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 "%1$s" configuration cannot be added to the cart — your "%2$s" 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 "%1$s" configuration cannot be added to the cart — there is not enough stock of "%2$s" (%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 "%1$s" configuration cannot be added to the cart because there is not enough stock of "%2$s" — 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 "%1$s" configuration cannot be added to the cart because there is not enough stock of "%2$s" — 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">× ' . $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') . ' <em>' . __('Accurate pricing info available in cart.', 'woocommerce-composite-products') . '</em></p>'; } }