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; } }
/** * Validates add-to-cart for bundles. * Basically ensures that stock for all bundled products exists before attempting to add them to cart. * * @param boolean $add core validation add to cart flag * @param int $product_id the product id * @param int $product_quantity quantity * @param mixed $variation_id variation id * @param array $variations variation data * @param array $cart_item_data cart item data * @return boolean modified add to cart validation flag */ public function woo_bundles_validation($add, $product_id, $product_quantity, $variation_id = '', $variations = array(), $cart_item_data = array()) { // 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'; // Ordering again? $order_again = isset($_GET['order_again']) && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'woocommerce-order_again'); // prevent bundled items from getting validated - they will be added by the container item. if (isset($cart_item_data['is_bundled']) && $order_again) { return false; } if ($product_type === 'bundle') { $product = wc_get_product($product_id); if (!$product) { return false; } if (!apply_filters('woocommerce_bundle_before_validation', true, $product)) { return false; } // If a stock-managed product / variation exists in the bundle multiple times, its stock will be checked only once for the sum of all bundled quantities. // The stock manager class keeps a record of stock-managed product / variation ids. $bundled_stock = new WC_PB_Stock_Manager($product); // Grab bundled items. $bundled_items = $product->get_bundled_items(); if (!$bundled_items) { return $add; } foreach ($bundled_items as $bundled_item_id => $bundled_item) { $id = $bundled_item->product_id; $bundled_product_type = $bundled_item->product->product_type; // Optional. $is_optional = $bundled_item->is_optional(); if ($is_optional) { if (isset($cart_item_data['stamp'][$bundled_item_id]['optional_selected']) && $order_again) { $is_optional_selected = 'yes' === $cart_item_data['stamp'][$bundled_item_id]['optional_selected'] ? true : false; } elseif (isset($_REQUEST[apply_filters('woocommerce_product_bundle_field_prefix', '', $product_id) . 'bundle_selected_optional_' . $bundled_item_id])) { $is_optional_selected = isset($_REQUEST[apply_filters('woocommerce_product_bundle_field_prefix', '', $product_id) . 'bundle_selected_optional_' . $bundled_item_id]); } else { $is_optional_selected = false; } } if ($is_optional && !$is_optional_selected) { continue; } // Check quantity. $item_quantity_min = $bundled_item->get_quantity(); $item_quantity_max = $bundled_item->get_quantity('max'); if (isset($_REQUEST[apply_filters('woocommerce_product_bundle_field_prefix', '', $product_id) . 'bundle_quantity_' . $bundled_item_id]) && is_numeric($_REQUEST[apply_filters('woocommerce_product_bundle_field_prefix', '', $product_id) . 'bundle_quantity_' . $bundled_item_id])) { $item_quantity = absint($_REQUEST[apply_filters('woocommerce_product_bundle_field_prefix', '', $product_id) . 'bundle_quantity_' . $bundled_item_id]); } elseif (isset($cart_item_data['stamp'][$bundled_item_id]['quantity']) && $order_again) { $item_quantity = $cart_item_data['stamp'][$bundled_item_id]['quantity']; } else { $item_quantity = $item_quantity_min; } if ($item_quantity < $item_quantity_min) { wc_add_notice(sprintf(__('"%1$s" cannot be added to the cart. The quantity of "%2$s" cannot be lower than %3$d.', 'woocommerce-product-bundles'), get_the_title($product_id), $bundled_item->get_raw_title(), $item_quantity_min), 'error'); return false; } elseif ($item_quantity_max && $item_quantity > $item_quantity_max) { wc_add_notice(sprintf(__('"%1$s" cannot be added to the cart. The quantity of "%2$s" cannot be higher than %3$d.', 'woocommerce-product-bundles'), get_the_title($product_id), $bundled_item->get_raw_title(), $item_quantity_max), 'error'); return false; } $quantity = $item_quantity * $product_quantity; // If quantity is zero, continue. if ($quantity == 0) { continue; } // Purchasable if (!$bundled_item->is_purchasable()) { wc_add_notice(sprintf(__('"%1$s" cannot be added to the cart because "%2$s" cannot be purchased at the moment.', 'woocommerce-product-bundles'), get_the_title($product_id), $bundled_item->get_raw_title()), 'error'); return false; } // Validate variation id. if ($bundled_product_type === 'variable' || $bundled_product_type === 'variable-subscription') { $variation_id = ''; if (isset($cart_item_data['stamp'][$bundled_item_id]['variation_id']) && $order_again) { $variation_id = $cart_item_data['stamp'][$bundled_item_id]['variation_id']; } elseif (isset($_REQUEST[apply_filters('woocommerce_product_bundle_field_prefix', '', $product_id) . 'bundle_variation_id_' . $bundled_item_id])) { $variation_id = $_REQUEST[apply_filters('woocommerce_product_bundle_field_prefix', '', $product_id) . 'bundle_variation_id_' . $bundled_item_id]; } if ($variation_id && is_numeric($variation_id) && $variation_id > 1) { if (get_post_meta($variation_id, '_price', true) === '') { wc_add_notice(sprintf(__('"%1$s" cannot be added to the cart. The selected variation of "%2$s" cannot be purchased.', 'woocommerce-product-bundles'), get_the_title($product_id), $bundled_item->product->get_title()), 'error'); return false; } // Add item for validation. $bundled_stock->add_item($id, $variation_id, $quantity); } // Verify all attributes for the variable product were set. $bundled_variation = wc_get_product($variation_id); $attributes = (array) maybe_unserialize(get_post_meta($id, '_product_attributes', true)); $variation_data = array(); $missing_attributes = array(); $all_set = true; if ($bundled_variation) { $variation_data = $bundled_variation->variation_data; // Verify all attributes. foreach ($attributes as $attribute) { if (!$attribute['is_variation']) { continue; } $taxonomy = 'attribute_' . sanitize_title($attribute['name']); if (!empty($_REQUEST[apply_filters('woocommerce_product_bundle_field_prefix', '', $product_id) . 'bundle_' . $taxonomy . '_' . $bundled_item_id])) { if (WC_PB_Core_Compatibility::is_wc_version_gte_2_4()) { // Get value from post data. if ($attribute['is_taxonomy']) { $value = sanitize_title(stripslashes($_REQUEST[apply_filters('woocommerce_product_bundle_field_prefix', '', $product_id) . 'bundle_' . $taxonomy . '_' . $bundled_item_id])); } else { $value = wc_clean(stripslashes($_REQUEST[apply_filters('woocommerce_product_bundle_field_prefix', '', $product_id) . 'bundle_' . $taxonomy . '_' . $bundled_item_id])); } } else { // Get value from post data. $value = sanitize_title(trim(stripslashes($_REQUEST[apply_filters('woocommerce_product_bundle_field_prefix', '', $product_id) . 'bundle_' . $taxonomy . '_' . $bundled_item_id]))); } // Get valid value from variation. $valid_value = $variation_data[$taxonomy]; // Allow if valid if ($valid_value === '' || $valid_value === $value) { continue; } } elseif (isset($cart_item_data['stamp'][$bundled_item_id]['attributes'][$taxonomy]) && isset($cart_item_data['stamp'][$bundled_item_id]['variation_id']) && $order_again) { if (WC_PB_Core_Compatibility::is_wc_version_gte_2_4()) { // Get value from post data if ($attribute['is_taxonomy']) { $value = sanitize_title(stripslashes($cart_item_data['stamp'][$bundled_item_id]['attributes'][$taxonomy])); } else { $value = wc_clean(stripslashes($cart_item_data['stamp'][$bundled_item_id]['attributes'][$taxonomy])); } } else { // Get value from post data $value = sanitize_title(trim(stripslashes($cart_item_data['stamp'][$bundled_item_id]['attributes'][$taxonomy]))); } $valid_value = $variation_data[$taxonomy]; if ($valid_value === '' || $valid_value === $value) { continue; } } else { $missing_attributes[] = wc_attribute_label($attribute['name']); } $all_set = false; } } else { $all_set = false; } if (!$all_set) { if ($missing_attributes && WC_PB_Core_Compatibility::is_wc_version_gte_2_3()) { $required_fields_notice = sprintf(_n('%1$s is a required "%2$s" field', '%1$s are required "%2$s" fields', sizeof($missing_attributes), 'woocommerce-product-bundles'), wc_format_list_of_items($missing_attributes), $bundled_item->product->get_title()); wc_add_notice(sprintf(__('"%1$s" cannot be added to the cart. %2$s.', 'woocommerce-product-bundles'), get_the_title($product_id), $required_fields_notice), 'error'); return false; } else { wc_add_notice(sprintf(__('"%1$s" cannot be added to the cart. Please choose "%2$s" options…', 'woocommerce-product-bundles'), get_the_title($product_id), $bundled_item->product->get_title()), 'error'); return false; } } } elseif ($bundled_product_type === 'simple' || $bundled_product_type === 'subscription') { // Add item for validation. $bundled_stock->add_item($id, false, $quantity); } if (!apply_filters('woocommerce_bundled_item_add_to_cart_validation', true, $product, $bundled_item, $quantity, $variation_id)) { return false; } } // Check stock for stock-managed bundled items. // If out of stock, don't proceed. if (false === apply_filters('woocommerce_add_to_cart_bundle_validation', $bundled_stock->validate_stock(), $product_id, $bundled_stock)) { return false; } // Composite Products compatibility. WC_PB_Compatibility::$stock_data = $bundled_stock; } return $add; }
/** * Write panel for Product Bundles. * * @return void */ function woo_bundles_product_write_panel() { global $woocommerce_bundles, $post, $wpdb; $bundle_data = maybe_unserialize(get_post_meta($post->ID, '_bundle_data', true)); $bundled_variable_num = 0; ?> <div id="bundled_product_data" class="panel woocommerce_options_panel"> <div class="options_group wc-metaboxes-wrapper wc-bundle-metaboxes-wrapper"> <div id="wc-bundle-metaboxes-wrapper-inner"> <p class="toolbar"> <a href="#" class="close_all"><?php _e('Close all', 'woocommerce'); ?> </a> <a href="#" class="expand_all"><?php _e('Expand all', 'woocommerce'); ?> </a> </p> <div class="wc-bundled-items wc-metaboxes"><?php if (!empty($bundle_data)) { $loop = 0; foreach ($bundle_data as $item_id => $item_data) { $sep = explode('_', $item_id); $product_id = $item_data['product_id']; $suffix = (string) $product_id != (string) $item_id ? '#' . $sep[1] : ''; $title = $woocommerce_bundles->helpers->get_product_title($product_id, $suffix); if (!$title) { continue; } ?> <div class="wc-bundled-item wc-metabox closed" rel="<?php echo $loop; ?> "> <h3> <button type="button" class="remove_row button"><?php echo __('Remove', 'woocommerce'); ?> </button> <div class="handlediv" title="<?php echo __('Click to toggle', 'woocommerce'); ?> "></div> <strong class="item-title"><?php echo $title . ' – #' . $product_id; ?> </strong> </h3> <div class="item-data wc-metabox-content"> <input type="hidden" name="bundle_data[<?php echo $loop; ?> ][bundle_order]" class="bundled_item_position" value="<?php echo $loop; ?> " /> <input type="hidden" name="bundle_data[<?php echo $loop; ?> ][item_id]" class="item_id" value="<?php echo $item_id; ?> " /> <input type="hidden" name="bundle_data[<?php echo $loop; ?> ][product_id]" class="product_id" value="<?php echo $product_id; ?> " /><?php do_action('woocommerce_bundled_product_admin_config_html', $loop, $product_id, $item_data, $post->ID); ?> </div> </div><!-- metabox --><?php $loop++; } } ?> </div> </div> </div><!-- options group --> <p class="bundled_products_toolbar toolbar"> <span class="bundled_products_toolbar_wrapper"> <span class="bundled_product_selector"><?php if (WC_PB_Core_Compatibility::is_wc_version_gte_2_3()) { ?> <input type="hidden" class="wc-product-search" style="width: 250px;" id="bundled_product" name="bundled_product" data-placeholder="<?php _e('Search for a product…', 'woocommerce'); ?> " data-action="woocommerce_json_search_products" data-multiple="false" data-selected="" value="" /><?php } else { ?> <select id="bundled_product" name="bundled_product" class="ajax_chosen_select_products" data-placeholder="<?php _e('Search for a product…', 'woocommerce'); ?> "> <option></option> </select><?php } ?> </span> <button type="button" class="button button-primary add_bundled_product"><?php _e('Add Product', 'woocommerce-product-bundles'); ?> </button> </span> </p> </div><?php }
/** * Admin writepanel scripts. * * @return void */ public function woo_bundles_admin_scripts() { $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min'; if (WC_PB_Core_Compatibility::is_wc_version_gte_2_2()) { $writepanel_dependency = 'wc-admin-meta-boxes'; } else { $writepanel_dependency = 'woocommerce_admin_meta_boxes'; } wp_register_script('woo_bundles_writepanel', WC_PB()->woo_bundles_plugin_url() . '/assets/js/bundled-product-write-panels' . $suffix . '.js', array('jquery', 'jquery-ui-datepicker', $writepanel_dependency), WC_PB()->version); wp_register_style('woo_bundles_css', WC_PB()->woo_bundles_plugin_url() . '/assets/css/bundles-write-panels.css', array('woocommerce_admin_styles'), WC_PB()->version); wp_register_style('woo_bundles_edit_order_css', WC_PB()->woo_bundles_plugin_url() . '/assets/css/bundles-edit-order.css', array('woocommerce_admin_styles'), WC_PB()->version); // Get admin screen id. $screen = get_current_screen(); // WooCommerce admin pages. if (in_array($screen->id, array('product'))) { wp_enqueue_script('woo_bundles_writepanel'); $params = array('add_bundled_product_nonce' => wp_create_nonce('wc_bundles_add_bundled_product'), 'is_wc_version_gte_2_3' => WC_PB_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…', 'enhanced select', 'woocommerce'), 'i18n_searching' => _x('Searching…', 'enhanced select', 'woocommerce')); wp_localize_script('woo_bundles_writepanel', 'wc_bundles_admin_params', $params); } if (in_array($screen->id, array('edit-product', 'product'))) { wp_enqueue_style('woo_bundles_css'); } if (in_array($screen->id, array('shop_order', 'edit-shop_order'))) { wp_enqueue_style('woo_bundles_edit_order_css'); } }