/** * Handle adding variable products to the cart. * @since 2.4.6 Split from add_to_cart_action * @param int $product_id * @return bool success or not */ private static function add_to_cart_handler_variable($product_id) { $adding_to_cart = wc_get_product($product_id); $variation_id = empty($_REQUEST['variation_id']) ? '' : absint($_REQUEST['variation_id']); $quantity = empty($_REQUEST['quantity']) ? 1 : wc_stock_amount($_REQUEST['quantity']); $missing_attributes = array(); $variations = array(); $attributes = $adding_to_cart->get_attributes(); // If no variation ID is set, attempt to get a variation ID from posted attributes. if (empty($variation_id)) { $data_store = WC_Data_Store::load('product'); $variation_id = $data_store->find_matching_product_variation($adding_to_cart, wp_unslash($_POST)); } // Validate the attributes. try { if (empty($variation_id)) { throw new Exception(__('Please choose product options…', 'woocommerce')); } $variation_data = wc_get_product_variation_attributes($variation_id); foreach ($attributes as $attribute) { if (!$attribute['is_variation']) { continue; } $taxonomy = 'attribute_' . sanitize_title($attribute['name']); if (isset($_REQUEST[$taxonomy])) { // Get value from post data if ($attribute['is_taxonomy']) { // Don't use wc_clean as it destroys sanitized characters $value = sanitize_title(stripslashes($_REQUEST[$taxonomy])); } else { $value = wc_clean(stripslashes($_REQUEST[$taxonomy])); } // Get valid value from variation $valid_value = isset($variation_data[$taxonomy]) ? $variation_data[$taxonomy] : ''; // Allow if valid or show error. if ('' === $valid_value || $valid_value === $value) { $variations[$taxonomy] = $value; } else { throw new Exception(sprintf(__('Invalid value posted for %s', 'woocommerce'), wc_attribute_label($attribute['name']))); } } else { $missing_attributes[] = wc_attribute_label($attribute['name']); } } if (!empty($missing_attributes)) { throw new Exception(sprintf(_n('%s is a required field', '%s are required fields', sizeof($missing_attributes), 'woocommerce'), wc_format_list_of_items($missing_attributes))); } } catch (Exception $e) { wc_add_notice($e->getMessage(), 'error'); return false; } // Add to cart validation $passed_validation = apply_filters('woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations); if ($passed_validation && WC()->cart->add_to_cart($product_id, $quantity, $variation_id, $variations) !== false) { wc_add_to_cart_message(array($product_id => $quantity), true); return true; } return false; }
/** * Get method returns variation meta data if set, otherwise in most cases the data from the parent. * * @param string $key * @return mixed */ public function __get($key) { if (in_array($key, array_keys($this->variation_level_meta_data))) { $value = get_post_meta($this->variation_id, '_' . $key, true); if ('' === $value) { $value = $this->variation_level_meta_data[$key]; } } elseif (in_array($key, array_keys($this->variation_inherited_meta_data))) { $value = metadata_exists('post', $this->variation_id, '_' . $key) ? get_post_meta($this->variation_id, '_' . $key, true) : get_post_meta($this->id, '_' . $key, true); // Handle meta data keys which can be empty at variation level to cause inheritance if ('' === $value && in_array($key, array('sku', 'weight', 'length', 'width', 'height'))) { $value = get_post_meta($this->id, '_' . $key, true); } if ('' === $value) { $value = $this->variation_inherited_meta_data[$key]; } } elseif ('variation_data' === $key) { return $this->variation_data = wc_get_product_variation_attributes($this->variation_id); } elseif ('variation_has_stock' === $key) { return $this->managing_stock(); } else { $value = metadata_exists('post', $this->variation_id, '_' . $key) ? get_post_meta($this->variation_id, '_' . $key, true) : parent::__get($key); } return $value; }
/** * Reads a product from the database and sets its data to the class. * * @since 2.7.0 * @param WC_Product */ public function read(&$product) { $product->set_defaults(); if (!$product->get_id() || !($post_object = get_post($product->get_id()))) { return; } $id = $product->get_id(); $product->set_parent_id($post_object->post_parent); $parent_id = $product->get_parent_id(); // The post doesn't have a parent id, therefore its invalid and we should prevent this being created. if (empty($parent_id)) { throw new Exception(sprintf('No parent product set for variation #%d', $product->get_id()), 422); } // The post parent is not a valid variable product so we should prevent this being created. if ('product' !== get_post_type($product->get_parent_id())) { throw new Exception(sprintf('Invalid parent for variation #%d', $product->get_id()), 422); } $product->set_props(array('name' => get_the_title($post_object), 'slug' => $post_object->post_name, 'date_created' => $post_object->post_date, 'date_modified' => $post_object->post_modified, 'status' => $post_object->post_status, 'menu_order' => $post_object->menu_order, 'reviews_allowed' => 'open' === $post_object->comment_status)); $this->read_product_data($product); $product->set_attributes(wc_get_product_variation_attributes($product->get_id())); // Set object_read true once all data is read. $product->set_object_read(true); }
/** * Load variations via AJAX. */ public static function load_variations() { ob_start(); check_ajax_referer('load-variations', 'security'); // Check permissions again and make sure we have what we need if (!current_user_can('edit_products') || empty($_POST['product_id']) || empty($_POST['attributes'])) { die(-1); } global $post; $product_id = absint($_POST['product_id']); $post = get_post($product_id); // Set $post global so its available like within the admin screens $per_page = !empty($_POST['per_page']) ? absint($_POST['per_page']) : 10; $page = !empty($_POST['page']) ? absint($_POST['page']) : 1; // Get attributes $attributes = array(); $posted_attributes = wp_unslash($_POST['attributes']); foreach ($posted_attributes as $key => $value) { $attributes[$key] = array_map('wc_clean', $value); } // Get tax classes $tax_classes = WC_Tax::get_tax_classes(); $tax_class_options = array(); $tax_class_options[''] = __('Standard', 'woocommerce'); if (!empty($tax_classes)) { foreach ($tax_classes as $class) { $tax_class_options[sanitize_title($class)] = esc_attr($class); } } // Set backorder options $backorder_options = array('no' => __('Do not allow', 'woocommerce'), 'notify' => __('Allow, but notify customer', 'woocommerce'), 'yes' => __('Allow', 'woocommerce')); // set stock status options $stock_status_options = array('instock' => __('In stock', 'woocommerce'), 'outofstock' => __('Out of stock', 'woocommerce')); $parent_data = array('id' => $product_id, 'attributes' => $attributes, 'tax_class_options' => $tax_class_options, 'sku' => get_post_meta($product_id, '_sku', true), 'weight' => wc_format_localized_decimal(get_post_meta($product_id, '_weight', true)), 'length' => wc_format_localized_decimal(get_post_meta($product_id, '_length', true)), 'width' => wc_format_localized_decimal(get_post_meta($product_id, '_width', true)), 'height' => wc_format_localized_decimal(get_post_meta($product_id, '_height', true)), 'tax_class' => get_post_meta($product_id, '_tax_class', true), 'backorder_options' => $backorder_options, 'stock_status_options' => $stock_status_options); if (!$parent_data['weight']) { $parent_data['weight'] = wc_format_localized_decimal(0); } if (!$parent_data['length']) { $parent_data['length'] = wc_format_localized_decimal(0); } if (!$parent_data['width']) { $parent_data['width'] = wc_format_localized_decimal(0); } if (!$parent_data['height']) { $parent_data['height'] = wc_format_localized_decimal(0); } // Get variations $args = apply_filters('woocommerce_ajax_admin_get_variations_args', array('post_type' => 'product_variation', 'post_status' => array('private', 'publish'), 'posts_per_page' => $per_page, 'paged' => $page, 'orderby' => array('menu_order' => 'ASC', 'ID' => 'DESC'), 'post_parent' => $product_id), $product_id); $variations = get_posts($args); $loop = 0; if ($variations) { foreach ($variations as $variation) { $variation_id = absint($variation->ID); $variation_meta = get_post_meta($variation_id); $variation_data = array(); $shipping_classes = get_the_terms($variation_id, 'product_shipping_class'); $variation_fields = array('_sku' => '', '_stock' => '', '_regular_price' => '', '_sale_price' => '', '_weight' => '', '_length' => '', '_width' => '', '_height' => '', '_download_limit' => '', '_download_expiry' => '', '_downloadable_files' => '', '_downloadable' => '', '_virtual' => '', '_thumbnail_id' => '', '_sale_price_dates_from' => '', '_sale_price_dates_to' => '', '_manage_stock' => '', '_stock_status' => '', '_backorders' => null, '_tax_class' => null, '_variation_description' => ''); foreach ($variation_fields as $field => $value) { $variation_data[$field] = isset($variation_meta[$field][0]) ? maybe_unserialize($variation_meta[$field][0]) : $value; } // Add the variation attributes $variation_data = array_merge($variation_data, wc_get_product_variation_attributes($variation_id)); // Formatting $variation_data['_regular_price'] = wc_format_localized_price($variation_data['_regular_price']); $variation_data['_sale_price'] = wc_format_localized_price($variation_data['_sale_price']); $variation_data['_weight'] = wc_format_localized_decimal($variation_data['_weight']); $variation_data['_length'] = wc_format_localized_decimal($variation_data['_length']); $variation_data['_width'] = wc_format_localized_decimal($variation_data['_width']); $variation_data['_height'] = wc_format_localized_decimal($variation_data['_height']); $variation_data['_thumbnail_id'] = absint($variation_data['_thumbnail_id']); $variation_data['image'] = $variation_data['_thumbnail_id'] ? wp_get_attachment_thumb_url($variation_data['_thumbnail_id']) : ''; $variation_data['shipping_class'] = $shipping_classes && !is_wp_error($shipping_classes) ? current($shipping_classes)->term_id : ''; $variation_data['menu_order'] = $variation->menu_order; $variation_data['_stock'] = wc_stock_amount($variation_data['_stock']); include 'admin/meta-boxes/views/html-variation-admin.php'; $loop++; } } die; }
/** * Magic __get method for backwards compatibility. Maps legacy vars to new getters. * * @param string $key Key name. * @return mixed */ public function __get($key) { if ('post_type' === $key) { return $this->post_type; } wc_doing_it_wrong($key, __('Product properties should not be accessed directly.', 'woocommerce'), '2.7'); switch ($key) { case 'id': $value = $this->is_type('variation') ? $this->get_parent_id() : $this->get_id(); break; case 'variation_id': $value = $this->get_id(); break; case 'product_attributes': $value = isset($this->data['attributes']) ? $this->data['attributes'] : ''; break; case 'visibility': $value = $this->get_catalog_visibility(); break; case 'sale_price_dates_from': $value = $this->get_date_on_sale_from(); break; case 'sale_price_dates_to': $value = $this->get_date_on_sale_to(); break; case 'post': $value = get_post($this->get_id()); break; case 'download_type': return 'standard'; break; case 'product_image_gallery': $value = $this->get_gallery_image_ids(); break; case 'variation_shipping_class': case 'shipping_class': $value = $this->get_shipping_class(); break; case 'total_stock': $value = $this->get_total_stock(); break; case 'downloadable': case 'virtual': case 'manage_stock': case 'featured': case 'sold_individually': $value = $this->{"get_{$key}"}() ? 'yes' : 'no'; break; case 'crosssell_ids': $value = $this->get_cross_sell_ids(); break; case 'upsell_ids': $value = $this->get_upsell_ids(); break; case 'parent': $value = wc_get_product($this->get_parent_id()); break; case 'variation_data': $value = wc_get_product_variation_attributes($this->get_id()); break; case 'variation_has_stock': $value = $this->managing_stock(); break; case 'variation_shipping_class_id': $value = $this->get_shipping_class_id(); break; default: if (in_array($key, array_keys($this->data))) { $value = $this->{"get_{$key}"}(); } else { $value = get_post_meta($this->id, '_' . $key, true); } break; } return $value; }
/** * Load variations via AJAX. */ public static function load_variations() { ob_start(); check_ajax_referer('load-variations', 'security'); if (!current_user_can('edit_products') || empty($_POST['product_id'])) { die(-1); } // Set $post global so its available, like within the admin screens global $post; $loop = 0; $product_id = absint($_POST['product_id']); $post = get_post($product_id); $product_object = wc_get_product($product_id); $per_page = !empty($_POST['per_page']) ? absint($_POST['per_page']) : 10; $page = !empty($_POST['page']) ? absint($_POST['page']) : 1; $variations = wc_get_products(array('status' => array('private', 'publish'), 'type' => 'variation', 'parent' => $product_id, 'limit' => $per_page, 'page' => $page, 'orderby' => array('menu_order' => 'ASC', 'ID' => 'DESC'), 'return' => 'objects')); if ($variations) { foreach ($variations as $variation_object) { $variation_id = $variation_object->get_id(); $variation = get_post($variation_id); $variation_data = array_merge(array_map('maybe_unserialize', get_post_custom($variation_id)), wc_get_product_variation_attributes($variation_id)); // kept for BW compat. include 'admin/meta-boxes/views/html-variation-admin.php'; $loop++; } } die; }
/** * @param $product * @param array $item_data * @return array */ private function get_item_datas($product, $item_data = array()) { $attrs = $product->get_attributes(); $variations = array(); if (!empty($product->variation_id)) { $variations = wc_get_product_variation_attributes($product->variation_id); } if (count($attrs)) { foreach ($attrs as $name => $attribute) { $label = wc_attribute_label($attribute['name']); if (count($variations)) { $term = get_term_by('slug', $variations['attribute_' . $name], $name); $item_data[] = array('key' => $label, 'label' => $label, 'value' => wpautop(wptexturize($term->name))); } else { $values = wc_get_product_terms($product->id, $attribute['name']); $item_data[] = array('key' => $label, 'label' => $label, 'value' => wpautop(wptexturize(implode(', ', $values)))); } } } return $item_data; }
/** * Generate YML body with offers. * * @since 0.3.0 * @param $currency * @param $query * * @return string */ private function yml_offers($currency, $query) { $yml = ''; while ($query->have_posts()) { $query->the_post(); $product = wc_get_product($query->post->ID); // We use a seperate variable for offer because we will be rewriting it for variable products. $offer = $product; /* * By default we set $variation_count to 1. * That means that there is at least one product available. * Variation products will have more than 1 count. */ $variation_count = 1; if ($product->is_type('variable')) { $variation_count = count($offer->get_children()); $variations = $product->get_available_variations(); } while ($variation_count > 0) { $variation_count--; // If variable product, get product id from $variations array. $offerID = $product->is_type('variable') ? $variations[$variation_count]['variation_id'] : $product->id; // Prepare variation link. $var_link = ''; if ($product->is_type('variable')) { $variable_attribute = wc_get_product_variation_attributes($offerID); $var_link = '?' . key($variable_attribute) . '=' . current($variable_attribute); // This has to work but we need to think of a way to save the initial offer variable. $offer = new WC_Product_Variation($offerID); } // NOTE: Below this point we start using $offer instead of $product. $yml .= ' <offer id="' . $offerID . '" available="' . ($offer->is_in_stock() ? "true" : "false") . '">' . PHP_EOL; $yml .= ' <url>' . get_permalink($offer->id) . $var_link . '</url>' . PHP_EOL; // Price. if ($offer->sale_price && $offer->sale_price < $offer->regular_price) { $yml .= ' <price>' . $offer->sale_price . '</price>' . PHP_EOL; $yml .= ' <oldprice>' . $offer->regular_price . '</oldprice>' . PHP_EOL; } else { $yml .= ' <price>' . $offer->regular_price . '</price>' . PHP_EOL; } $yml .= ' <currencyId>' . $currency . '</currencyId>' . PHP_EOL; // Category. // Not using $offerID, because variable products inherit category from parent. $categories = get_the_terms($product->id, 'product_cat'); $category = array_shift($categories); $yml .= ' <categoryId>' . $category->term_id . '</categoryId>' . PHP_EOL; // Market category. if (isset($this->settings['market_category']) && $this->settings['market_category'] != 'not_set') { $market_category = wc_get_product_terms($offerID, 'pa_' . $this->settings['market_category'], array('fields' => 'names')); if ($market_category) { $yml .= ' <market_category>' . wp_strip_all_tags(array_shift($market_category)) . '</market_category>' . PHP_EOL; } } // TODO: get all the images $image = get_the_post_thumbnail_url(null, 'full'); //foreach ( $images as $image ): if (strlen(utf8_decode($image)) <= 512) { $yml .= ' <picture>' . esc_url($image) . '</picture>' . PHP_EOL; } //endforeach; $yml .= ' <delivery>true</delivery>' . PHP_EOL; $yml .= ' <name>' . $offer->get_title() . '</name>' . PHP_EOL; // Vendor. if (isset($this->settings['vendor']) && $this->settings['vendor'] != 'not_set') { $vendor = wc_get_product_terms($offer->ID, 'pa_' . $this->settings['vendor'], array('fields' => 'names')); if ($vendor) { $yml .= ' <vendor>' . wp_strip_all_tags(array_shift($vendor)) . '</vendor>' . PHP_EOL; } } // Vendor code. if ($offer->sku) { $yml .= ' <vendorCode>' . $offer->sku . '</vendorCode>' . PHP_EOL; } // Description. if ($offer->post->post_content) { $yml .= ' <description><![CDATA[' . html_entity_decode($offer->post->post_content, ENT_COMPAT, "UTF-8") . ']]></description>' . PHP_EOL; } // Sales notes. if ($this->settings['sales_notes'] == 'yes' && $offer->post->post_excerpt) { $yml .= ' <sales_notes>' . wp_strip_all_tags($offer->post->post_excerpt) . '</sales_notes>' . PHP_EOL; } $yml .= ' </offer>' . PHP_EOL; } } return $yml; }
/** * 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(__('"%1$s" (#%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(__('"%1$s" (#%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(__('"%1$s" (#%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 "%1$s%2$s" (#%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(__('"%1$s" (#%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 "%1$s%2$s" (#%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 "%1$s%2$s" (#%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 "%1$s%2$s" (#%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(__('"%1$s%2$s" (#%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(__('"%1$s%2$s" (#%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; } }