/**
  * Get grouped products data
  *
  * @since  2.5.0
  * @param  WC_Product $product
  *
  * @return array
  */
 private function get_grouped_products_data($product)
 {
     $products = array();
     foreach ($product->get_children() as $child_id) {
         $_product = $product->get_child($child_id);
         if (!$_product->exists()) {
             continue;
         }
         $products[] = $this->get_product_data($_product);
     }
     return $products;
 }
 /**
  * Get an individual variation's data
  *
  * @since 2.1
  * @param WC_Product $product
  * @return array
  */
 private function get_variation_data($product)
 {
     $variations = array();
     foreach ($product->get_children() as $child_id) {
         $variation = $product->get_child($child_id);
         if (!$variation->exists()) {
             continue;
         }
         $variations[] = array('id' => $variation->get_variation_id(), 'created_at' => $this->server->format_datetime($variation->get_post_data()->post_date_gmt), 'updated_at' => $this->server->format_datetime($variation->get_post_data()->post_modified_gmt), 'downloadable' => $variation->is_downloadable(), 'virtual' => $variation->is_virtual(), 'permalink' => $variation->get_permalink(), 'sku' => $variation->get_sku(), 'price' => wc_format_decimal($variation->get_price(), 2), 'regular_price' => wc_format_decimal($variation->get_regular_price(), 2), 'sale_price' => $variation->get_sale_price() ? wc_format_decimal($variation->get_sale_price(), 2) : null, 'taxable' => $variation->is_taxable(), 'tax_status' => $variation->get_tax_status(), 'tax_class' => $variation->get_tax_class(), 'stock_quantity' => (int) $variation->get_stock_quantity(), 'in_stock' => $variation->is_in_stock(), 'backordered' => $variation->is_on_backorder(), 'purchaseable' => $variation->is_purchasable(), 'visible' => $variation->variation_is_visible(), 'on_sale' => $variation->is_on_sale(), 'weight' => $variation->get_weight() ? wc_format_decimal($variation->get_weight(), 2) : null, 'dimensions' => array('length' => $variation->length, 'width' => $variation->width, 'height' => $variation->height, 'unit' => get_option('woocommerce_dimension_unit')), 'shipping_class' => $variation->get_shipping_class(), 'shipping_class_id' => 0 !== $variation->get_shipping_class_id() ? $variation->get_shipping_class_id() : null, 'image' => $this->get_images($variation), 'attributes' => $this->get_attributes($variation), 'downloads' => $this->get_downloads($variation), 'download_limit' => (int) $product->download_limit, 'download_expiry' => (int) $product->download_expiry);
     }
     return $variations;
 }
function woocommerce_link_all_variations()
{
    check_ajax_referer('link-variations', 'security');
    @set_time_limit(0);
    $post_id = intval($_POST['post_id']);
    if (!$post_id) {
        die;
    }
    $variations = array();
    $_product = new WC_Product($post_id);
    // Put variation attributes into an array
    foreach ($_product->get_attributes() as $attribute) {
        if (!$attribute['is_variation']) {
            continue;
        }
        $attribute_field_name = 'attribute_' . sanitize_title($attribute['name']);
        if ($attribute['is_taxonomy']) {
            $post_terms = wp_get_post_terms($post_id, $attribute['name']);
            $options = array();
            foreach ($post_terms as $term) {
                $options[] = $term->slug;
            }
        } else {
            $options = explode('|', $attribute['value']);
        }
        $options = array_map('trim', $options);
        $variations[$attribute_field_name] = $options;
    }
    // Quit out if none were found
    if (sizeof($variations) == 0) {
        die;
    }
    // Get existing variations so we don't create duplicated
    $available_variations = array();
    foreach ($_product->get_children() as $child_id) {
        $child = $_product->get_child($child_id);
        if ($child instanceof WC_Product_Variation) {
            $available_variations[] = $child->get_variation_attributes();
        }
    }
    // Created posts will all have the following data
    $variation_post_data = array('post_title' => 'Product #' . $post_id . ' Variation', 'post_content' => '', 'post_status' => 'publish', 'post_author' => get_current_user_id(), 'post_parent' => $post_id, 'post_type' => 'product_variation');
    // Now find all combinations and create posts
    if (!function_exists('array_cartesian')) {
        function array_cartesian($input)
        {
            $result = array();
            while (list($key, $values) = each($input)) {
                // If a sub-array is empty, it doesn't affect the cartesian product
                if (empty($values)) {
                    continue;
                }
                // Special case: seeding the product array with the values from the first sub-array
                if (empty($result)) {
                    foreach ($values as $value) {
                        $result[] = array($key => $value);
                    }
                } else {
                    // Second and subsequent input sub-arrays work like this:
                    //   1. In each existing array inside $product, add an item with
                    //      key == $key and value == first item in input sub-array
                    //   2. Then, for each remaining item in current input sub-array,
                    //      add a copy of each existing array inside $product with
                    //      key == $key and value == first item in current input sub-array
                    // Store all items to be added to $product here; adding them on the spot
                    // inside the foreach will result in an infinite loop
                    $append = array();
                    foreach ($result as &$product) {
                        // Do step 1 above. array_shift is not the most efficient, but it
                        // allows us to iterate over the rest of the items with a simple
                        // foreach, making the code short and familiar.
                        $product[$key] = array_shift($values);
                        // $product is by reference (that's why the key we added above
                        // will appear in the end result), so make a copy of it here
                        $copy = $product;
                        // Do step 2 above.
                        foreach ($values as $item) {
                            $copy[$key] = $item;
                            $append[] = $copy;
                        }
                        // Undo the side effecst of array_shift
                        array_unshift($values, $product[$key]);
                    }
                    // Out of the foreach, we can add to $results now
                    $result = array_merge($result, $append);
                }
            }
            return $result;
        }
    }
    $variation_ids = array();
    $added = 0;
    $possible_variations = array_cartesian($variations);
    foreach ($possible_variations as $variation) {
        // Check if variation already exists
        if (in_array($variation, $available_variations)) {
            continue;
        }
        $variation_id = wp_insert_post($variation_post_data);
        $variation_ids[] = $variation_id;
        foreach ($variation as $key => $value) {
            update_post_meta($variation_id, $key, $value);
        }
        $added++;
        // Max 100
        if ($added > 49) {
            break;
        }
    }
    echo $added;
    die;
}
 /**
  * Get an individual variation's data.
  *
  * @param WC_Product $product
  * @return array
  */
 protected function get_variation_data($product)
 {
     $variations = array();
     foreach ($product->get_children() as $child_id) {
         $variation = $product->get_child($child_id);
         if (!$variation->exists()) {
             continue;
         }
         $post_data = get_post($variation->get_variation_id());
         $variations[] = array('id' => $variation->get_variation_id(), 'date_created' => wc_rest_prepare_date_response($post_data->post_date_gmt), 'date_modified' => wc_rest_prepare_date_response($post_data->post_modified_gmt), 'permalink' => $variation->get_permalink(), 'sku' => $variation->get_sku(), 'price' => $variation->get_price(), 'regular_price' => $variation->get_regular_price(), 'sale_price' => $variation->get_sale_price(), 'date_on_sale_from' => $variation->sale_price_dates_from ? date('Y-m-d', $variation->sale_price_dates_from) : '', 'date_on_sale_to' => $variation->sale_price_dates_to ? date('Y-m-d', $variation->sale_price_dates_to) : '', 'on_sale' => $variation->is_on_sale(), 'purchasable' => $variation->is_purchasable(), 'visible' => $variation->is_visible(), 'virtual' => $variation->is_virtual(), 'downloadable' => $variation->is_downloadable(), 'downloads' => $this->get_downloads($variation), 'download_limit' => '' !== $variation->download_limit ? (int) $variation->download_limit : -1, 'download_expiry' => '' !== $variation->download_expiry ? (int) $variation->download_expiry : -1, 'tax_status' => $variation->get_tax_status(), 'tax_class' => $variation->get_tax_class(), 'manage_stock' => $variation->managing_stock(), 'stock_quantity' => $variation->get_stock_quantity(), 'in_stock' => $variation->is_in_stock(), 'backorders' => $variation->backorders, 'backorders_allowed' => $variation->backorders_allowed(), 'backordered' => $variation->is_on_backorder(), 'weight' => $variation->get_weight(), 'dimensions' => array('length' => $variation->get_length(), 'width' => $variation->get_width(), 'height' => $variation->get_height()), 'shipping_class' => $variation->get_shipping_class(), 'shipping_class_id' => $variation->get_shipping_class_id(), 'image' => $this->get_images($variation), 'attributes' => $this->get_attributes($variation));
     }
     return $variations;
 }
 function load_bundle_data()
 {
     global $woocommerce_bundles;
     // stores bundle pricing strategy info and price table
     $this->bundle_price_data = array();
     $this->bundle_price_data['currency_symbol'] = get_woocommerce_currency_symbol();
     $this->bundle_price_data['woocommerce_price_num_decimals'] = (int) get_option('woocommerce_price_num_decimals');
     $this->bundle_price_data['woocommerce_currency_pos'] = get_option('woocommerce_currency_pos');
     $this->bundle_price_data['woocommerce_price_decimal_sep'] = stripslashes(get_option('woocommerce_price_decimal_sep'));
     $this->bundle_price_data['woocommerce_price_thousand_sep'] = stripslashes(get_option('woocommerce_price_thousand_sep'));
     $this->bundle_price_data['woocommerce_price_trim_zeros'] = get_option('woocommerce_price_trim_zeros');
     $this->bundle_price_data['free'] = __('Free!', 'woocommerce');
     $this->bundle_price_data['per_product_pricing'] = $this->per_product_pricing_active;
     $this->bundle_price_data['prices'] = array();
     $this->bundle_price_data['regular_prices'] = array();
     $this->bundle_price_data['total'] = $this->per_product_pricing_active ? (double) 0 : (double) ($this->get_price() == '' ? -1 : $this->get_price());
     $this->bundle_price_data['regular_total'] = $this->per_product_pricing_active ? (double) 0 : (double) $this->regular_price;
     $this->bundle_price_data['total_description'] = __('Total', 'woo-bundles') . ': ';
     $this->bundle_attributes = array();
     $this->available_bundle_variations = array();
     $this->selected_bundle_attributes = array();
     $this->bundled_products = array();
     foreach ($this->bundled_item_ids as $bundled_item_id) {
         // remove suffix
         $sep = explode('_', $bundled_item_id);
         $product_id = $sep[0];
         $bundled_product_post = get_post($product_id);
         if (get_post_status($product_id) != 'publish') {
             continue;
         }
         if ($this->is_wc_v2) {
             $bundled_product = get_product($product_id);
         } else {
             $bundled_product = new WC_Product($product_id);
         }
         $this->bundled_products[$bundled_item_id] = $bundled_product;
         if ($bundled_product->product_type == 'simple') {
             if (!$bundled_product->is_sold_individually()) {
                 $this->sold_individually = false;
             }
             // price for simple products gets stored now, for variable products jquery gets the job done
             $this->bundle_price_data['prices'][$bundled_product->id] = (double) $bundled_product->get_price();
             $this->bundle_price_data['regular_prices'][$bundled_product->id] = (double) $bundled_product->regular_price;
             // no variation data to load - product is simple
             $this->min_bundle_price = $this->min_bundle_price + $this->bundled_item_quantities[$bundled_item_id] * $bundled_product->get_price();
             $this->min_bundle_regular_price = $this->min_bundle_regular_price + $this->bundled_item_quantities[$bundled_item_id] * $bundled_product->regular_price;
             $this->max_bundle_price = $this->max_bundle_price + $this->bundled_item_quantities[$bundled_item_id] * $bundled_product->get_price();
             $this->max_bundle_regular_price = $this->max_bundle_regular_price + $this->bundled_item_quantities[$bundled_item_id] * $bundled_product->regular_price;
         } elseif ($bundled_product->product_type == 'variable') {
             // prepare price variable for jquery
             $this->bundle_price_data['prices'][$bundled_item_id] = 0;
             $this->bundle_price_data['regular_prices'][$bundled_item_id] = 0;
             // get all available attributes and settings
             $this->bundle_attributes[$bundled_item_id] = $bundled_product->get_variation_attributes();
             $default_product_attributes = array();
             if ($this->bundle_defaults_active[$bundled_item_id]) {
                 $default_product_attributes = $this->bundle_defaults[$bundled_item_id];
             } else {
                 $default_product_attributes = (array) maybe_unserialize(get_post_meta($bundled_product_post->ID, '_default_attributes', true));
             }
             $this->selected_bundle_attributes[$bundled_item_id] = apply_filters('woocommerce_product_default_attributes', $default_product_attributes);
             // calculate min-max variation prices
             $min_variation_regular_price = '';
             $min_variation_sale_price = '';
             $max_variation_regular_price = '';
             $max_variation_sale_price = '';
             foreach ($bundled_product->get_children() as $child_id) {
                 $variation = $bundled_product->get_child($child_id);
                 // stop here if this variation is not within the active set (prices will not include this variation)
                 if ($this->variation_filters_active[$bundled_item_id]) {
                     if (!is_array($this->allowed_variations[$bundled_item_id])) {
                         continue;
                     }
                     if (!in_array($child_id, $this->allowed_variations[$bundled_item_id])) {
                         continue;
                     }
                 }
                 if ($variation instanceof WC_Product_Variation) {
                     if (get_post_status($variation->get_variation_id()) != 'publish') {
                         continue;
                     }
                     // Disabled
                     if (!$variation->is_sold_individually()) {
                         $this->sold_individually = false;
                     }
                     // variation min-max price calculation
                     $variation_price = get_post_meta($child_id, '_price', true);
                     $variation_sale_price = get_post_meta($child_id, '_sale_price', true);
                     // Low price
                     if (!is_numeric($min_variation_regular_price) || $variation_price < $min_variation_regular_price) {
                         $min_variation_regular_price = $variation_price;
                     }
                     if ($variation_sale_price !== '' && (!is_numeric($min_variation_sale_price) || $variation_sale_price < $min_variation_sale_price)) {
                         $min_variation_sale_price = $variation_sale_price;
                     }
                     // High price
                     if (!is_numeric($max_variation_regular_price) || $variation_price > $max_variation_regular_price) {
                         $max_variation_regular_price = $variation_price;
                     }
                     if ($variation_sale_price !== '' && (!is_numeric($max_variation_sale_price) || $variation_sale_price > $max_variation_sale_price)) {
                         $max_variation_sale_price = $variation_sale_price;
                     }
                     // prepare available options
                     $variation_attributes = $variation->get_variation_attributes();
                     $availability = $variation->get_availability();
                     if (!is_admin() && !$woocommerce_bundles->validate_stock($product_id, $variation->variation_id, get_post_meta($this->id, 'bundle_quantity_' . $bundled_item_id, true), true, true)) {
                         $availability = array('availability' => __('Out of stock', 'woocommerce'), 'class' => 'out-of-stock');
                     }
                     $availability_html = !empty($availability['availability']) ? apply_filters('woocommerce_stock_html', '<p class="stock ' . $availability['class'] . '">' . $availability['availability'] . '</p>', $availability['availability']) : '';
                     if (has_post_thumbnail($variation->get_variation_id())) {
                         $attachment_id = get_post_thumbnail_id($variation->get_variation_id());
                         $attachment = wp_get_attachment_image_src($attachment_id, apply_filters('bundled_product_large_thumbnail_size', 'shop_single'));
                         $image = $attachment ? current($attachment) : '';
                         $attachment = wp_get_attachment_image_src($attachment_id, 'full');
                         $image_link = $attachment ? current($attachment) : '';
                         $image_title = get_the_title($attachment_id);
                     } else {
                         $image = $image_link = $image_title = '';
                     }
                     $this->available_bundle_variations[$bundled_item_id][] = apply_filters('woocommerce_available_variation', array('variation_id' => $variation->get_variation_id(), 'product_id' => $bundled_item_id, 'attributes' => $variation_attributes, 'image_src' => $image, 'image_link' => $image_link, 'image_title' => $image_title, 'price' => (double) $variation->get_price(), 'regular_price' => (double) $variation->regular_price, 'price_html' => $this->per_product_pricing_active ? '<span class="price">' . $variation->get_price_html() . '</span>' : '', 'availability_html' => $availability_html), $bundled_product, $variation);
                 }
             }
             $add = $min_variation_sale_price === '' || $min_variation_regular_price < $min_variation_sale_price ? $min_variation_regular_price : $min_variation_sale_price;
             $this->min_bundle_price = $this->min_bundle_price + $this->bundled_item_quantities[$bundled_item_id] * $add;
             $this->min_bundle_regular_price = $this->min_bundle_regular_price + $this->bundled_item_quantities[$bundled_item_id] * $min_variation_regular_price;
             $add = $max_variation_sale_price === '' || $max_variation_regular_price < $max_variation_sale_price ? $max_variation_regular_price : $max_variation_sale_price;
             $this->max_bundle_price = $this->max_bundle_price + $this->bundled_item_quantities[$bundled_item_id] * $add;
             $this->max_bundle_regular_price = $this->max_bundle_regular_price + $this->bundled_item_quantities[$bundled_item_id] * $max_variation_regular_price;
         }
     }
 }
 /**
  * Adjust variation price
  *
  * @since 1.3.0
  * @param int $price
  * @param WC_Product $product
  * @param string $min_or_max
  * @param bool $display
  * @return int
  */
 public function on_get_variation_price($price, $product, $min_or_max, $display)
 {
     $min_price = $price;
     $max_price = $price;
     $tax_display_mode = get_option('woocommerce_tax_display_shop');
     $children = $product->get_children();
     if (isset($children) && !empty($children)) {
         foreach ($children as $variation_id) {
             if ($display) {
                 $variation = $product->get_child($variation_id);
                 if ($variation) {
                     $this->disable_price_adjustments();
                     // In display mode, we need to account for taxes
                     $base_price = $tax_display_mode == 'incl' ? $variation->get_price_including_tax() : $variation->get_price_excluding_tax();
                     $calc_price = $base_price;
                     $discounted_price = $this->get_discounted_price($base_price, $variation->id);
                     if ($discounted_price && $base_price != $discounted_price) {
                         $calc_price = $discounted_price;
                     }
                     $this->enable_price_adjustments();
                 } else {
                     $calc_price = '';
                 }
             } else {
                 $calc_price = get_post_meta($variation_id, '_price', true);
             }
             if ($min_price == null || $calc_price < $min_price) {
                 $min_price = $calc_price;
             }
             if ($max_price == null || $calc_price > $max_price) {
                 $max_price = $calc_price;
             }
         }
     }
     if ($min_or_max == 'min') {
         return $min_price;
     } elseif ($min_or_max == 'max') {
         return $max_price;
     } else {
         return $price;
     }
 }