/** * Bulk edit * @param integer $post_id * @param WC_Product $product */ public function bulk_edit_save($post_id, $product) { $old_regular_price = $product->regular_price; $old_sale_price = $product->sale_price; // Save fields if (!empty($_REQUEST['change_weight']) && isset($_REQUEST['_weight'])) { update_post_meta($post_id, '_weight', wc_clean(stripslashes($_REQUEST['_weight']))); } if (!empty($_REQUEST['change_dimensions'])) { if (isset($_REQUEST['_length'])) { update_post_meta($post_id, '_length', wc_clean(stripslashes($_REQUEST['_length']))); } if (isset($_REQUEST['_width'])) { update_post_meta($post_id, '_width', wc_clean(stripslashes($_REQUEST['_width']))); } if (isset($_REQUEST['_height'])) { update_post_meta($post_id, '_height', wc_clean(stripslashes($_REQUEST['_height']))); } } if (!empty($_REQUEST['_tax_status'])) { update_post_meta($post_id, '_tax_status', wc_clean($_REQUEST['_tax_status'])); } if (!empty($_REQUEST['_tax_class'])) { $tax_class = wc_clean($_REQUEST['_tax_class']); if ('standard' == $tax_class) { $tax_class = ''; } update_post_meta($post_id, '_tax_class', $tax_class); } if (!empty($_REQUEST['_stock_status'])) { $stock_status = wc_clean($_REQUEST['_stock_status']); if ($product->is_type('variable')) { foreach ($product->get_children() as $child_id) { if ('yes' !== get_post_meta($child_id, '_manage_stock', true)) { wc_update_product_stock_status($child_id, $stock_status); } } WC_Product_Variable::sync_stock_status($post_id); } else { wc_update_product_stock_status($post_id, $stock_status); } } if (!empty($_REQUEST['_shipping_class'])) { $shipping_class = '_no_shipping_class' == $_REQUEST['_shipping_class'] ? '' : wc_clean($_REQUEST['_shipping_class']); wp_set_object_terms($post_id, $shipping_class, 'product_shipping_class'); } if (!empty($_REQUEST['_visibility'])) { if (update_post_meta($post_id, '_visibility', wc_clean($_REQUEST['_visibility']))) { do_action('woocommerce_product_set_visibility', $post_id, wc_clean($_REQUEST['_visibility'])); } } if (!empty($_REQUEST['_featured'])) { if (update_post_meta($post_id, '_featured', stripslashes($_REQUEST['_featured']))) { delete_transient('wc_featured_products'); } } // Sold Individually if (!empty($_REQUEST['_sold_individually'])) { if ($_REQUEST['_sold_individually'] == 'yes') { update_post_meta($post_id, '_sold_individually', 'yes'); } else { update_post_meta($post_id, '_sold_individually', ''); } } // Handle price - remove dates and set to lowest if ($product->is_type('simple') || $product->is_type('external')) { $price_changed = false; if (!empty($_REQUEST['change_regular_price'])) { $change_regular_price = absint($_REQUEST['change_regular_price']); $regular_price = esc_attr(stripslashes($_REQUEST['_regular_price'])); switch ($change_regular_price) { case 1: $new_price = $regular_price; break; case 2: if (strstr($regular_price, '%')) { $percent = str_replace('%', '', $regular_price) / 100; $new_price = $old_regular_price + round($old_regular_price * $percent, wc_get_price_decimals()); } else { $new_price = $old_regular_price + $regular_price; } break; case 3: if (strstr($regular_price, '%')) { $percent = str_replace('%', '', $regular_price) / 100; $new_price = max(0, $old_regular_price - round($old_regular_price * $percent, wc_get_price_decimals())); } else { $new_price = max(0, $old_regular_price - $regular_price); } break; default: break; } if (isset($new_price) && $new_price != $old_regular_price) { $price_changed = true; $new_price = round($new_price, wc_get_price_decimals()); update_post_meta($post_id, '_regular_price', $new_price); $product->regular_price = $new_price; } } if (!empty($_REQUEST['change_sale_price'])) { $change_sale_price = absint($_REQUEST['change_sale_price']); $sale_price = esc_attr(stripslashes($_REQUEST['_sale_price'])); switch ($change_sale_price) { case 1: $new_price = $sale_price; break; case 2: if (strstr($sale_price, '%')) { $percent = str_replace('%', '', $sale_price) / 100; $new_price = $old_sale_price + $old_sale_price * $percent; } else { $new_price = $old_sale_price + $sale_price; } break; case 3: if (strstr($sale_price, '%')) { $percent = str_replace('%', '', $sale_price) / 100; $new_price = max(0, $old_sale_price - $old_sale_price * $percent); } else { $new_price = max(0, $old_sale_price - $sale_price); } break; case 4: if (strstr($sale_price, '%')) { $percent = str_replace('%', '', $sale_price) / 100; $new_price = max(0, $product->regular_price - $product->regular_price * $percent); } else { $new_price = max(0, $product->regular_price - $sale_price); } break; default: break; } if (isset($new_price) && $new_price != $old_sale_price) { $price_changed = true; $new_price = !empty($new_price) || '0' === $new_price ? round($new_price, wc_get_price_decimals()) : ''; update_post_meta($post_id, '_sale_price', $new_price); $product->sale_price = $new_price; } } if ($price_changed) { update_post_meta($post_id, '_sale_price_dates_from', ''); update_post_meta($post_id, '_sale_price_dates_to', ''); if ($product->regular_price < $product->sale_price) { $product->sale_price = ''; update_post_meta($post_id, '_sale_price', ''); } if ($product->sale_price) { update_post_meta($post_id, '_price', $product->sale_price); } else { update_post_meta($post_id, '_price', $product->regular_price); } } } // Handle stock if (!$product->is_type('grouped')) { if (!empty($_REQUEST['change_stock'])) { update_post_meta($post_id, '_manage_stock', 'yes'); wc_update_product_stock($post_id, wc_stock_amount($_REQUEST['_stock'])); } if (!empty($_REQUEST['_manage_stock'])) { if ($_REQUEST['_manage_stock'] == 'yes') { update_post_meta($post_id, '_manage_stock', 'yes'); } else { update_post_meta($post_id, '_manage_stock', 'no'); wc_update_product_stock($post_id, 0); } } if (!empty($_REQUEST['_backorders'])) { update_post_meta($post_id, '_backorders', wc_clean($_REQUEST['_backorders'])); } } do_action('woocommerce_product_bulk_edit_save', $product); }
/** * Pluggable function to render the frontend product page voucher fields * * @since 1.2 * @param WC_Product $product the voucher product */ function wc_pdf_product_vouchers_render_product_voucher_fields($product) { if ($product->is_type('variable')) { foreach ($product->get_children() as $variation_product_id) { $products[] = wc_get_product($variation_product_id); } } else { $products[] = $product; } foreach ($products as $product) { $voucher = WC_PDF_Product_Vouchers_Product::get_voucher($product); if ($voucher) { $fields = $voucher->get_user_input_voucher_fields(); $images = $voucher->get_image_urls(); if ($fields || $images) { // load the template file wc_get_template('single-product/product-voucher.php', array('product' => $product, 'product_id' => isset($product->variation_id) ? $product->variation_id : $product->id, 'voucher' => $voucher, 'fields' => $fields, 'images' => $images), '', wc_pdf_product_vouchers()->get_plugin_path() . '/templates/'); } } } }
/** * 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; }
/** * Given a product ID & variations, find the correct variation ID to use for * calculation. We can't just trust input from the CLI to pass a variation_id * manually, otherwise you could pass the cheapest variation ID but provide * other information so we have to look up the variation ID. * * @since 2.5.0 * @param WC_Product $product Product instance * @return int Returns an ID if a valid variation was found for this product */ protected function get_variation_id($product, $variations = array()) { $variation_id = null; $variations_normalized = array(); if ($product->is_type('variable') && $product->has_child()) { if (isset($variations) && is_array($variations)) { // start by normalizing the passed variations foreach ($variations as $key => $value) { $key = str_replace('attribute_', '', str_replace('pa_', '', $key)); // from get_attributes in class-wc-api-products.php $variations_normalized[$key] = strtolower($value); } // now search through each product child and see if our passed variations match anything foreach ($product->get_children() as $variation) { $meta = array(); foreach (get_post_meta($variation) as $key => $value) { $value = $value[0]; $key = str_replace('attribute_', '', str_replace('pa_', '', $key)); $meta[$key] = strtolower($value); } // if the variation array is a part of the $meta array, we found our match if ($this->array_contains($variations_normalized, $meta)) { $variation_id = $variation; break; } } } } return $variation_id; }
/** * Get an individual variation's data. * * @todo Remove in future version of the API. We have variations endpoints now. * * @param WC_Product $product Product instance. * @return array */ protected function get_variation_data($product) { $variations = array(); foreach ($product->get_children() as $child_id) { $variation = wc_get_product($child_id); if (!$variation->exists()) { continue; } $variations[] = array('id' => $variation->get_id(), 'date_created' => wc_rest_prepare_date_response($variation->get_date_created()), 'date_modified' => wc_rest_prepare_date_response($variation->get_date_modified()), 'permalink' => $variation->get_permalink(), 'description' => $variation->get_description(), '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->get_date_on_sale_from() ? date('Y-m-d', $variation->get_date_on_sale_from()) : '', 'date_on_sale_to' => $variation->get_date_on_sale_to() ? date('Y-m-d', $variation->get_date_on_sale_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->get_download_limit() ? (int) $variation->get_download_limit() : -1, 'download_expiry' => '' !== $variation->get_download_expiry() ? (int) $variation->get_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->get_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; }
private function create_variation_selector($condition, $name) { global $post; $post_id = isset($_POST['post']) ? intval($_POST['post']) : $post->ID; if (!$post_id) { return; } $product = null; if (function_exists('get_product')) { $product = get_product($post_id); } else { $product = new WC_Product($post_id); } if (!$product->has_child()) { return; } $all_variations = $product->get_children(); $div_style = $condition['args']['type'] != 'variations' ? 'display:none;' : ''; ?> <div> <label for="pricing_rule_variations_<?php echo $name; ?> "><?php _e('Product / Variations:', 'wc_pricing'); ?> </label> <select title="<?php _e('Choose what you would like to apply this pricing rule set to', 'wc_pricing'); ?> " class="pricing_rule_variations" id="pricing_rule_variations_<?php echo $name; ?> " name="pricing_rules[<?php echo $name; ?> ][variation_rules][args][type]"> <option <?php selected('product', $condition['args']['type']); ?> value="product"><?php _e('All Variations', 'wc_pricing'); ?> </option> <option <?php selected('variations', $condition['args']['type']); ?> value="variations"><?php _e('Specific Variations', 'wc_pricing'); ?> </option> </select> <div class="variations" style="<?php echo $div_style; ?> "> <?php sort($all_variations); ?> <?php $chunks = array_chunk($all_variations, ceil(count($all_variations) / 3), true); ?> <?php foreach ($chunks as $chunk) { ?> <ul class="list-column"> <?php foreach ($chunk as $variation_id) { ?> <?php $variation_object = new WC_Product_Variation($variation_id); ?> <?php $variation_checked = isset($condition['args']['variations']) && is_array($condition['args']['variations']) && in_array($variation_id, $condition['args']['variations']) ? 'checked="checked"' : ''; ?> <li> <label for="variation_<?php echo $variation_id; ?> _<?php echo $name; ?> " class="selectit"> <input <?php echo $variation_checked; ?> type="checkbox" id="variation_<?php echo $variation_id; ?> _<?php echo $name; ?> " name="pricing_rules[<?php echo $name; ?> ][variation_rules][args][variations][]" value="<?php echo $variation_id; ?> " /><?php _e('Variation ID:', 'wc_pricing'); ?> <?php echo $variation_id; ?> </label> </li> <?php } ?> </ul> <?php } ?> </div> <div class="clear"></div> </div> <?php }
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; } }
/** * For WooCommerce 1.6 only. * Converts the prices of a product into the selected currency. This method * is implemented because WC 1.6 used WC_Product class for both simple and * variable products. * * @param WC_Product product A product. * @param string currency A currency code. * @return WC_Product */ public function convert_legacy_product_prices(WC_Product $product, $currency) { $product_children = $product->get_children(); if (empty($product_children)) { $product = $this->convert_to_currency($product, $currency, $this->get_product_regular_prices($product->id), $this->get_product_sale_prices($product->id)); } else { $product = $this->convert_variable_product_prices($product, $currency); } return $product; }
/** * Bulk edit. * * @param integer $post_id * @param WC_Product $product */ public function bulk_edit_save($post_id, $product) { $old_regular_price = $product->get_regular_price(); $old_sale_price = $product->get_sale_price(); // Save fields if (!empty($_REQUEST['change_weight']) && isset($_REQUEST['_weight'])) { $product->set_weight(wc_clean(stripslashes($_REQUEST['_weight']))); } if (!empty($_REQUEST['change_dimensions'])) { if (isset($_REQUEST['_length'])) { $product->set_length(wc_clean(stripslashes($_REQUEST['_length']))); } if (isset($_REQUEST['_width'])) { $product->set_width(wc_clean(stripslashes($_REQUEST['_width']))); } if (isset($_REQUEST['_height'])) { $product->set_height(wc_clean(stripslashes($_REQUEST['_height']))); } } if (!empty($_REQUEST['_tax_status'])) { $product->set_tax_status(wc_clean($_REQUEST['_tax_status'])); } if (!empty($_REQUEST['_tax_class'])) { $tax_class = wc_clean($_REQUEST['_tax_class']); if ('standard' == $tax_class) { $tax_class = ''; } $product->set_tax_class($tax_class); } if (!empty($_REQUEST['_shipping_class'])) { $shipping_class = '_no_shipping_class' == $_REQUEST['_shipping_class'] ? '' : wc_clean($_REQUEST['_shipping_class']); $shipping_class_id = $data_store->get_shipping_class_id_by_slug($shipping_class); if ($shipping_class_id) { $product->set_shipping_class_id($shipping_class_id); } } if (!empty($_REQUEST['_visibility'])) { $product->set_catalog_visibility(wc_clean($_REQUEST['_visibility'])); } if (!empty($_REQUEST['_featured'])) { $product->set_featured(stripslashes($_REQUEST['_featured'])); } // Sold Individually if (!empty($_REQUEST['_sold_individually'])) { if ('yes' === $_REQUEST['_sold_individually']) { $product->set_sold_individually('yes'); } else { $product->set_sold_individually(''); } } // Handle price - remove dates and set to lowest $change_price_product_types = apply_filters('woocommerce_bulk_edit_save_price_product_types', array('simple', 'external')); $can_product_type_change_price = false; foreach ($change_price_product_types as $product_type) { if ($product->is_type($product_type)) { $can_product_type_change_price = true; break; } } if ($can_product_type_change_price) { $price_changed = false; if (!empty($_REQUEST['change_regular_price'])) { $change_regular_price = absint($_REQUEST['change_regular_price']); $regular_price = esc_attr(stripslashes($_REQUEST['_regular_price'])); switch ($change_regular_price) { case 1: $new_price = $regular_price; break; case 2: if (strstr($regular_price, '%')) { $percent = str_replace('%', '', $regular_price) / 100; $new_price = $old_regular_price + round($old_regular_price * $percent, wc_get_price_decimals()); } else { $new_price = $old_regular_price + $regular_price; } break; case 3: if (strstr($regular_price, '%')) { $percent = str_replace('%', '', $regular_price) / 100; $new_price = max(0, $old_regular_price - round($old_regular_price * $percent, wc_get_price_decimals())); } else { $new_price = max(0, $old_regular_price - $regular_price); } break; default: break; } if (isset($new_price) && $new_price != $old_regular_price) { $price_changed = true; $new_price = round($new_price, wc_get_price_decimals()); $product->set_regular_price($new_price); } } if (!empty($_REQUEST['change_sale_price'])) { $change_sale_price = absint($_REQUEST['change_sale_price']); $sale_price = esc_attr(stripslashes($_REQUEST['_sale_price'])); switch ($change_sale_price) { case 1: $new_price = $sale_price; break; case 2: if (strstr($sale_price, '%')) { $percent = str_replace('%', '', $sale_price) / 100; $new_price = $old_sale_price + $old_sale_price * $percent; } else { $new_price = $old_sale_price + $sale_price; } break; case 3: if (strstr($sale_price, '%')) { $percent = str_replace('%', '', $sale_price) / 100; $new_price = max(0, $old_sale_price - $old_sale_price * $percent); } else { $new_price = max(0, $old_sale_price - $sale_price); } break; case 4: if (strstr($sale_price, '%')) { $percent = str_replace('%', '', $sale_price) / 100; $new_price = max(0, $product->regular_price - $product->regular_price * $percent); } else { $new_price = max(0, $product->regular_price - $sale_price); } break; default: break; } if (isset($new_price) && $new_price != $old_sale_price) { $price_changed = true; $new_price = !empty($new_price) || '0' === $new_price ? round($new_price, wc_get_price_decimals()) : ''; $product->set_sale_price($new_price); } } if ($price_changed) { $product->set_date_on_sale_to(''); $product->set_date_on_sale_from(''); if ($product->get_regular_price() < $product->get_sale_price()) { $product->set_sale_price(''); } } } // Handle Stock Data $was_managing_stock = $product->get_manage_stock() ? 'yes' : 'no'; $stock_status = $product->get_stock_status(); $backorders = $product->get_backorders(); $backorders = !empty($_REQUEST['_backorders']) ? wc_clean($_REQUEST['_backorders']) : $backorders; $stock_status = !empty($_REQUEST['_stock_status']) ? wc_clean($_REQUEST['_stock_status']) : $stock_status; if (!empty($_REQUEST['_manage_stock'])) { $manage_stock = 'yes' === wc_clean($_REQUEST['_manage_stock']) && 'grouped' !== $product->product_type ? 'yes' : 'no'; } else { $manage_stock = $was_managing_stock; } $stock_amount = 'yes' === $manage_stock && isset($_REQUEST['_change_stock']) ? wc_stock_amount($_REQUEST['_change_stock']) : ''; if ('yes' === get_option('woocommerce_manage_stock')) { // Apply product type constraints to stock status if ($product->is_type('external')) { // External always in stock $stock_status = 'instock'; } elseif ($product->is_type('variable')) { // Stock status is always determined by children foreach ($product->get_children() as $child_id) { $child = wc_get_product($child_id); if (!$product->get_manage_stock()) { $child->set_stock_status($stock_status); $child->save(); } } $product = WC_Product_Variable::sync($product, false); } $product->set_manage_stock($manage_stock); $product->set_backorders($backorders); $product->save(); if (!$product->is_type('variable')) { wc_update_product_stock_status($post_id, $stock_status); } wc_update_product_stock($post_id, $stock_amount); } else { $product->save(); wc_update_product_stock_status($post_id, $stock_status); } do_action('woocommerce_product_bulk_edit_save', $product); }
/** * Individual product sales chart */ function woocommerce_product_sales() { global $start_date, $end_date, $woocommerce; $chosen_product_id = isset($_POST['product_id']) ? $_POST['product_id'] : ''; if ($chosen_product_id) { $start_date = date('Ym', strtotime('-12 MONTHS', current_time('timestamp'))) . '01'; $end_date = date('Ymd', current_time('timestamp')); $start_date = strtotime($start_date); $end_date = strtotime($end_date); // Get orders to display in widget add_filter('posts_where', 'orders_within_range'); $args = array('numberposts' => -1, 'orderby' => 'post_date', 'order' => 'ASC', 'post_type' => 'shop_order', 'post_status' => 'publish', 'suppress_filters' => 0, 'tax_query' => array(array('taxonomy' => 'shop_order_status', 'terms' => array('completed', 'processing', 'on-hold'), 'field' => 'slug', 'operator' => 'IN'))); $orders = get_posts($args); $max_sales = 0; $max_totals = 0; $product_sales = array(); $product_totals = array(); // Get ID's related to product $chosen_product = new WC_Product($chosen_product_id); $child_ids = $chosen_product->get_children(); if ($orders) { foreach ($orders as $order) { $date = date('Ym', strtotime($order->post_date)); $order_items = (array) get_post_meta($order->ID, '_order_items', true); foreach ($order_items as $item) { if ($item['id'] != $chosen_product_id && !in_array($item['id'], $child_ids)) { continue; } $product_sales[$date] = isset($product_sales[$date]) ? $product_sales[$date] + $item['qty'] : $item['qty']; if (isset($item['line_total'])) { $row_cost = $item['line_total']; } else { $row_cost = $item['cost'] * $item['qty']; } $product_totals[$date] = isset($product_totals[$date]) ? $product_totals[$date] + $row_cost : $row_cost; if ($product_sales[$date] > $max_sales) { $max_sales = $product_sales[$date]; } if ($product_totals[$date] > $max_totals) { $max_totals = $product_totals[$date]; } } } } remove_filter('posts_where', 'orders_within_range'); } ?> <form method="post" action=""> <p><label for="from"><?php _e('Product:', 'woocommerce'); ?> </label> <select name="product_id" id="product_id"> <?php echo '<option value="">' . __('Choose an product…', 'woocommerce') . '</option>'; $args = array('post_type' => 'product', 'posts_per_page' => -1, 'post_status' => 'publish', 'post_parent' => 0, 'order' => 'ASC', 'orderby' => 'title'); $products = get_posts($args); if ($products) { foreach ($products as $product) { $sku = get_post_meta($product->ID, '_sku', true); if ($sku) { $sku = ' SKU: ' . $sku; } echo '<option value="' . $product->ID . '" ' . selected($chosen_product_id, $product->ID, false) . '>' . $product->post_title . $sku . ' (#' . $product->ID . '' . $sku . ')</option>'; } } ?> </select> <input type="submit" class="button" value="<?php _e('Show', 'woocommerce'); ?> " /></p> </form> <?php if ($chosen_product_id) { ?> <table class="bar_chart"> <thead> <tr> <th><?php _e('Month', 'woocommerce'); ?> </th> <th colspan="2"><?php _e('Sales', 'woocommerce'); ?> </th> </tr> </thead> <tbody> <?php if (sizeof($product_sales) > 0) { foreach ($product_sales as $date => $sales) { $width = $sales > 0 ? round($sales) / round($max_sales) * 100 : 0; $width2 = $product_totals[$date] > 0 ? round($product_totals[$date]) / round($max_totals) * 100 : 0; $orders_link = admin_url('edit.php?s&post_status=all&post_type=shop_order&action=-1&s=' . urlencode(get_the_title($chosen_product_id)) . '&m=' . date('Ym', strtotime($date . '01')) . '&shop_order_status=completed,processing,on-hold'); echo '<tr><th><a href="' . $orders_link . '">' . date('F', strtotime($date . '01')) . '</a></th> <td width="1%"><span>' . $sales . '</span><span class="alt">' . woocommerce_price($product_totals[$date]) . '</span></td> <td class="bars"> <span style="width:' . $width . '%"> </span> <span class="alt" style="width:' . $width2 . '%"> </span> </td></tr>'; } } else { echo '<tr><td colspan="3">' . __('No sales :(', 'woocommerce') . '</td></tr>'; } ?> </tbody> </table> <?php } }
/** * Returns the voucher attached to $product * * @since 1.2 * @param WC_Product $product the voucher product * @return WC_Voucher the voucher attached to $product */ public static function get_voucher($product) { if ($product->is_type('variable')) { foreach ($product->get_children() as $variation_product_id) { $variation_product = wc_get_product($variation_product_id); if ($variation_product->is_downloadable() && $variation_product->voucher_id) { // Note: this assumes that there is only one voucher attached to any variations for a product, which probably isn't a great assumption, but simplifies the frontend for now return new WC_Voucher($variation_product->voucher_id); } } } elseif ($product->is_downloadable() && $product->voucher_id) { // simple product or product variation return new WC_Voucher($product->voucher_id); } // aw, no voucher return null; }