/** * Output widget. * * @see WP_Widget * * @param array $args * @param array $instance */ public function widget($args, $instance) { global $wp, $wp_the_query; if (!is_post_type_archive('product') && !is_tax(get_object_taxonomies('product'))) { return; } if (!$wp_the_query->post_count) { return; } $min_price = isset($_GET['min_price']) ? esc_attr($_GET['min_price']) : ''; $max_price = isset($_GET['max_price']) ? esc_attr($_GET['max_price']) : ''; wp_enqueue_script('wc-price-slider'); // Find min and max price in current result set $prices = $this->get_filtered_price(); $min = floor($prices->min_price); $max = ceil($prices->max_price); if ($min === $max) { return; } $this->widget_start($args, $instance); if ('' === get_option('permalink_structure')) { $form_action = remove_query_arg(array('page', 'paged'), add_query_arg($wp->query_string, '', home_url($wp->request))); } else { $form_action = preg_replace('%\\/page/[0-9]+%', '', home_url(trailingslashit($wp->request))); } /** * Adjust max if the store taxes are not displayed how they are stored. * Min is left alone because the product may not be taxable. * Kicks in when prices excluding tax are displayed including tax. */ if (wc_tax_enabled() && 'incl' === get_option('woocommerce_tax_display_shop') && !wc_prices_include_tax()) { $tax_classes = array_merge(array(''), WC_Tax::get_tax_classes()); $class_max = $max; foreach ($tax_classes as $tax_class) { if ($tax_rates = WC_Tax::get_rates($tax_class)) { $class_max = $max + WC_Tax::get_tax_total(WC_Tax::calc_exclusive_tax($max, $tax_rates)); } } $max = $class_max; } echo '<form method="get" action="' . esc_url($form_action) . '"> <div class="price_slider_wrapper"> <div class="price_slider" style="display:none;"></div> <div class="price_slider_amount"> <input type="text" id="min_price" name="min_price" value="' . esc_attr($min_price) . '" data-min="' . esc_attr(apply_filters('woocommerce_price_filter_widget_min_amount', $min)) . '" placeholder="' . esc_attr__('Min price', 'woocommerce') . '" /> <input type="text" id="max_price" name="max_price" value="' . esc_attr($max_price) . '" data-max="' . esc_attr(apply_filters('woocommerce_price_filter_widget_max_amount', $max)) . '" placeholder="' . esc_attr__('Max price', 'woocommerce') . '" /> <button type="submit" class="button">' . __('Filter', 'woocommerce') . '</button> <div class="price_label" style="display:none;"> ' . __('Price:', 'woocommerce') . ' <span class="from"></span> — <span class="to"></span> </div> ' . wc_query_string_form_fields(null, array('min_price', 'max_price'), '', true) . ' <div class="clear"></div> </div> </div> </form>'; $this->widget_end($args); }
/** * Uses the shipping class to calculate shipping then gets the totals when its finished. * * @access public * @return void */ function calculate_shipping() { global $woocommerce; if ($this->needs_shipping() && $this->show_shipping()) { $woocommerce->shipping->calculate_shipping($this->get_shipping_packages()); } else { $woocommerce->shipping->reset_shipping(); } // Get totals for the chosen shipping method $this->shipping_total = $woocommerce->shipping->shipping_total; // Shipping Total $this->shipping_label = $woocommerce->shipping->shipping_label; // Shipping Label $this->shipping_taxes = $woocommerce->shipping->shipping_taxes; // Shipping Taxes $this->shipping_tax_total = $this->tax->get_tax_total($this->shipping_taxes); // Shipping tax amount }
/** * Calculate totals for the items in the cart. * * @access public */ public function calculate_totals() { global $woocommerce; $this->reset(); do_action('woocommerce_before_calculate_totals', $this); // Get count of all items + weights + subtotal (we may need this for discounts) if (sizeof($this->cart_contents) > 0) { foreach ($this->cart_contents as $cart_item_key => $values) { $_product = $values['data']; $this->cart_contents_weight = $this->cart_contents_weight + $_product->get_weight() * $values['quantity']; $this->cart_contents_count = $this->cart_contents_count + $values['quantity']; // Base Price (inclusive of tax for now) $row_base_price = $_product->get_price() * $values['quantity']; $base_tax_rates = $this->tax->get_shop_base_rate($_product->tax_class); $tax_amount = 0; if ($this->prices_include_tax) { if ($_product->is_taxable()) { $tax_rates = $this->tax->get_rates($_product->get_tax_class()); // ADJUST BASE if tax rate is different (different region or modified tax class) if ($tax_rates !== $base_tax_rates) { $base_taxes = $this->tax->calc_tax($row_base_price, $base_tax_rates, true, true); $modded_taxes = $this->tax->calc_tax($row_base_price - array_sum($base_taxes), $tax_rates, false); $row_base_price = $row_base_price - array_sum($base_taxes) + array_sum($modded_taxes); } $taxes = $this->tax->calc_tax($row_base_price, $tax_rates, true); $tax_amount = get_option('woocommerce_tax_round_at_subtotal') == 'no' ? $this->tax->get_tax_total($taxes) : array_sum($taxes); } // Sub total is based on base prices (without discounts) $this->subtotal = $this->subtotal + $row_base_price; $this->subtotal_ex_tax = $this->subtotal_ex_tax + ($row_base_price - $tax_amount); } else { if ($_product->is_taxable()) { $tax_rates = $this->tax->get_rates($_product->get_tax_class()); $taxes = $this->tax->calc_tax($row_base_price, $tax_rates, false); $tax_amount = get_option('woocommerce_tax_round_at_subtotal') == 'no' ? $this->tax->get_tax_total($taxes) : array_sum($taxes); } // Sub total is based on base prices (without discounts) $this->subtotal = $this->subtotal + $row_base_price + $tax_amount; $this->subtotal_ex_tax = $this->subtotal_ex_tax + $row_base_price; } } } // Now calc the main totals, including discounts if ($this->prices_include_tax) { /** * Calculate totals for items */ if (sizeof($this->cart_contents) > 0) { foreach ($this->cart_contents as $cart_item_key => $values) { /** * Prices include tax * * To prevent rounding issues we need to work with the inclusive price where possible * otherwise we'll see errors such as when working with a 9.99 inc price, 20% VAT which would * be 8.325 leading to totals being 1p off * * Pre tax coupons come off the price the customer thinks they are paying - tax is calculated * afterwards. * * e.g. $100 bike with $10 coupon = customer pays $90 and tax worked backwards from that * * Used this excellent article for reference: * http://developer.practicalecommerce.com/articles/1473-Coding-for-Tax-Calculations-Everything-You-Never-Wanted-to-Know-Part-2 */ $_product = $values['data']; // Base Price (inclusive of tax for now) $base_price = $_product->get_price(); // Base Price Adjustment if ($_product->is_taxable()) { // Get rates $tax_rates = $this->tax->get_rates($_product->get_tax_class()); $base_tax_rates = $this->tax->get_shop_base_rate($_product->tax_class); /** * ADJUST TAX - Calculations when base tax is not equal to the item tax */ if ($tax_rates !== $base_tax_rates) { $row_base_price = $base_price * $values['quantity']; // Work out a new base price without the shop's base tax $line_tax = array_sum($this->tax->calc_tax($row_base_price, $base_tax_rates, true)); // Now we have a new item price (excluding TAX) $line_subtotal = $this->tax->round($row_base_price - $line_tax); // Now add taxes for the users location $line_subtotal_tax = array_sum($this->tax->calc_tax($line_subtotal, $tax_rates, false)); $line_subtotal_tax = get_option('woocommerce_tax_round_at_subtotal') == 'yes' ? $line_subtotal_tax : $this->tax->round($line_subtotal_tax); // Adjusted price (this is the price including the new tax rate) $adjusted_price = ($line_subtotal + $line_subtotal_tax) / $values['quantity']; // Apply discounts $discounted_price = $this->get_discounted_price($values, $adjusted_price, true); $discounted_taxes = $this->tax->calc_tax($discounted_price * $values['quantity'], $tax_rates, true); $discounted_tax_amount = array_sum($discounted_taxes); // Sum taxes /** * Regular tax calculation (customer inside base and the tax class is unmodified */ } else { // Base tax for line before discount - we will store this in the order data $tax_amount = array_sum($this->tax->calc_tax($base_price * $values['quantity'], $tax_rates, true)); // Line subtotal + tax $line_subtotal_tax = get_option('woocommerce_tax_round_at_subtotal') == 'no' ? $this->tax->round($tax_amount) : $tax_amount; $line_subtotal = $base_price * $values['quantity'] - $this->tax->round($line_subtotal_tax); // Calc prices and tax (discounted) $discounted_price = $this->get_discounted_price($values, $base_price, true); $discounted_taxes = $this->tax->calc_tax($discounted_price * $values['quantity'], $tax_rates, true); $discounted_tax_amount = array_sum($discounted_taxes); // Sum taxes } // Tax rows - merge the totals we just got foreach (array_keys($this->taxes + $discounted_taxes) as $key) { $this->taxes[$key] = (isset($discounted_taxes[$key]) ? $discounted_taxes[$key] : 0) + (isset($this->taxes[$key]) ? $this->taxes[$key] : 0); } } else { // Discounted Price (price with any pre-tax discounts applied) $discounted_price = $this->get_discounted_price($values, $base_price, true); $discounted_tax_amount = 0; $tax_amount = 0; $line_subtotal_tax = 0; $line_subtotal = $base_price * $values['quantity']; } // Line prices $line_tax = get_option('woocommerce_tax_round_at_subtotal') == 'no' ? $this->tax->round($discounted_tax_amount) : $discounted_tax_amount; $line_total = $discounted_price * $values['quantity'] - $this->tax->round($line_tax); // Add any product discounts (after tax) $this->apply_product_discounts_after_tax($values, $line_total + $discounted_tax_amount); // Cart contents total is based on discounted prices and is used for the final total calculation $this->cart_contents_total = $this->cart_contents_total + $line_total; // Store costs + taxes for lines $this->cart_contents[$cart_item_key]['line_total'] = $line_total; $this->cart_contents[$cart_item_key]['line_tax'] = $line_tax; $this->cart_contents[$cart_item_key]['line_subtotal'] = $line_subtotal; $this->cart_contents[$cart_item_key]['line_subtotal_tax'] = $line_subtotal_tax; } } } else { if (sizeof($this->cart_contents) > 0) { foreach ($this->cart_contents as $cart_item_key => $values) { /** * Prices exclude tax * * This calculation is simpler - work with the base, untaxed price. */ $_product = $values['data']; // Base Price (i.e. no tax, regardless of region) $base_price = $_product->get_price(); // Discounted Price (base price with any pre-tax discounts applied $discounted_price = $this->get_discounted_price($values, $base_price, true); // Tax Amount (For the line, based on discounted, ex.tax price) if ($_product->is_taxable()) { // Get tax rates $tax_rates = $this->tax->get_rates($_product->get_tax_class()); // Base tax for line before discount - we will store this in the order data $tax_amount = array_sum($this->tax->calc_tax($base_price * $values['quantity'], $tax_rates, false)); // Now calc product rates $discounted_taxes = $this->tax->calc_tax($discounted_price * $values['quantity'], $tax_rates, false); $discounted_tax_amount = array_sum($discounted_taxes); // Tax rows - merge the totals we just got foreach (array_keys($this->taxes + $discounted_taxes) as $key) { $this->taxes[$key] = (isset($discounted_taxes[$key]) ? $discounted_taxes[$key] : 0) + (isset($this->taxes[$key]) ? $this->taxes[$key] : 0); } } else { $discounted_tax_amount = 0; $tax_amount = 0; } // Line prices $line_subtotal_tax = $tax_amount; $line_tax = $discounted_tax_amount; $line_subtotal = $base_price * $values['quantity']; $line_total = $discounted_price * $values['quantity']; // Add any product discounts (after tax) $this->apply_product_discounts_after_tax($values, $line_total + $line_tax); // Cart contents total is based on discounted prices and is used for the final total calculation $this->cart_contents_total = $this->cart_contents_total + $line_total; // Store costs + taxes for lines $this->cart_contents[$cart_item_key]['line_total'] = $line_total; $this->cart_contents[$cart_item_key]['line_tax'] = $line_tax; $this->cart_contents[$cart_item_key]['line_subtotal'] = $line_subtotal; $this->cart_contents[$cart_item_key]['line_subtotal_tax'] = $line_subtotal_tax; } } } // Only calculate the grand total + shipping if on the cart/checkout if (is_checkout() || is_cart() || defined('WOOCOMMERCE_CHECKOUT') || defined('WOOCOMMERCE_CART')) { // Calculate the Shipping $this->calculate_shipping(); // Trigger the fees API where developers can add fees to the cart $this->calculate_fees(); // Total up/round taxes if (get_option('woocommerce_tax_round_at_subtotal') == 'no') { $this->tax_total = $this->tax->get_tax_total($this->taxes); $this->taxes = array_map(array($this->tax, 'round'), $this->taxes); } else { $this->tax_total = array_sum($this->taxes); } // Total up/round taxes for shipping if (get_option('woocommerce_tax_round_at_subtotal') == 'no') { $this->shipping_tax_total = $this->tax->get_tax_total($this->shipping_taxes); $this->shipping_taxes = array_map(array($this->tax, 'round'), $this->shipping_taxes); } else { $this->shipping_tax_total = array_sum($this->shipping_taxes); } // VAT exemption done at this point - so all totals are correct before exemption if ($woocommerce->customer->is_vat_exempt()) { $this->remove_taxes(); } // Cart Discounts (after tax) $this->apply_cart_discounts_after_tax(); // Allow plugins to hook and alter totals before final total is calculated do_action('woocommerce_calculate_totals', $this); // Grand Total - Discounted product prices, discounted tax, shipping cost + tax, and any discounts to be added after tax (e.g. store credit) $this->total = max(0, apply_filters('woocommerce_calculated_total', number_format($this->cart_contents_total + $this->tax_total + $this->shipping_tax_total + $this->shipping_total - $this->discount_total + $this->fee_total, $this->dp, '.', ''), $this)); } else { // Set tax total to sum of all tax rows $this->tax_total = $this->tax->get_tax_total($this->taxes); // VAT exemption done at this point - so all totals are correct before exemption if ($woocommerce->customer->is_vat_exempt()) { $this->remove_taxes(); } // Cart Discounts (after tax) $this->apply_cart_discounts_after_tax(); } $this->set_session(); }
/** * Output widget. * * @see WP_Widget * * @param array $args * @param array $instance */ public function widget($args, $instance) { global $wp, $wp_the_query; if (!is_post_type_archive('product') && !is_tax(get_object_taxonomies('product'))) { return; } if (!$wp_the_query->post_count) { return; } // Remember current filters/search if ('' == get_option('permalink_structure')) { $link_url = remove_query_arg(array('page', 'paged'), add_query_arg($wp->query_string, '', home_url($wp->request))); } else { $link_url = preg_replace('%\\/page/[0-9]+%', '', home_url(trailingslashit($wp->request))); } if (get_search_query()) { $link_url = add_query_arg('s', get_search_query(), $link_url); } if (!empty($_GET['post_type'])) { $link_url = add_query_arg('post_type', urlencode($_GET['post_type']), $link_url); } if (!empty($_GET['product_cat'])) { $link_url = add_query_arg('product_cat', urlencode($_GET['product_cat']), $link_url); } if (!empty($_GET['product_tag'])) { $link_url = add_query_arg('product_tag', urlencode($_GET['product_tag']), $link_url); } if (!empty($_GET['orderby'])) { $link_url = add_query_arg('orderby', urlencode($_GET['orderby']), $link_url); } if ($_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes()) { foreach ($_chosen_attributes as $attribute => $data) { $taxonomy_filter = 'filter_' . str_replace('pa_', '', $attribute); $link_url = add_query_arg($taxonomy_filter, urlencode(implode(',', $data['terms'])), $link_url); if ('or' == $data['query_type']) { $link_url = add_query_arg(str_replace('pa_', 'query_type_', $attribute), 'or', $link_url); } } } // Find min and max price in current result set $prices = $this->get_filtered_price(); $min = floor($prices->min_price); $max = ceil($prices->max_price); if ($min === $max) { return; } $this->widget_start($args, $instance); /** * Adjust max if the store taxes are not displayed how they are stored. * Min is left alone because the product may not be taxable. * Kicks in when prices excluding tax are displayed including tax. */ if (wc_tax_enabled() && 'incl' === get_option('woocommerce_tax_display_shop') && !wc_prices_include_tax()) { $tax_classes = array_merge(array(''), WC_Tax::get_tax_classes()); $class_max = $max; foreach ($tax_classes as $tax_class) { if ($tax_rates = WC_Tax::get_rates($tax_class)) { $class_max = $max + WC_Tax::get_tax_total(WC_Tax::calc_exclusive_tax($max, $tax_rates)); } } $max = $class_max; } $minprice = isset($_GET['min_price']) ? esc_attr($_GET['min_price']) : ''; $maxprice = isset($_GET['max_price']) ? esc_attr($_GET['max_price']) : ''; $output = ''; $min_price = 0; $range_size = intval($instance['range_size']); $max_ranges = intval($instance['max_ranges']) - 1; $count = 0; if (strlen($minprice) > 0) { $output .= '<li><a href="' . esc_url($link_url) . '">' . esc_html__('All', 'cruxstore') . '</a></li>'; } else { $output .= '<li class="selected">' . esc_html__('All', 'cruxstore') . '</li>'; } while ($count <= $max_ranges) { $step = $min_price; $min_price += $range_size; if ($count != $max_ranges) { if ($min_price > $max) { $min_price = $max; } $link = add_query_arg(array('min_price' => $step, 'max_price' => $min_price), $link_url); $price_text = wc_price($step) . ' - ' . wc_price($min_price); } else { $link = add_query_arg(array('min_price' => $step, 'max_price' => $max), $link_url); $price_text = wc_price($step) . '+'; } if ($step == $minprice && $min_price == $maxprice) { $output .= '<li class="selected">' . $price_text . '</li>'; } else { $output .= '<li><a href="' . esc_url($link) . '">' . $price_text . '</a></li>'; } $count++; if ($min_price == $max) { break; } } printf('<ul>%s</ul>', $output); $this->widget_end($args); }
function override_calculate_totals_limitations() { global $woocommerce; // Calculate the Shipping WC()->cart->calculate_shipping(); // Trigger the fees API where developers can add fees to the cart WC()->cart->calculate_fees(); // Total up/round taxes and shipping taxes if (WC()->cart->round_at_subtotal) { WC()->cart->tax_total = WC_Tax::get_tax_total(WC()->cart->taxes); WC()->cart->shipping_tax_total = WC_Tax::get_tax_total(WC()->cart->shipping_taxes); WC()->cart->taxes = array_map(array('WC_Tax', 'round'), WC()->cart->taxes); WC()->cart->shipping_taxes = array_map(array('WC_Tax', 'round'), WC()->cart->shipping_taxes); } else { WC()->cart->tax_total = array_sum(WC()->cart->taxes); WC()->cart->shipping_tax_total = array_sum(WC()->cart->shipping_taxes); } // VAT exemption done at this point - so all totals are correct before exemption if (WC()->customer->is_vat_exempt()) { WC()->cart->remove_taxes(); } }
/** * Return a meta query for filtering by price. * @return array */ private function price_filter_meta_query() { if (isset($_GET['max_price']) || isset($_GET['min_price'])) { $min = isset($_GET['min_price']) ? floatval($_GET['min_price']) : 0; $max = isset($_GET['max_price']) ? floatval($_GET['max_price']) : 9999999999.0; /** * Adjust if the store taxes are not displayed how they are stored. * Max is left alone because the filter was already increased. * Kicks in when prices excluding tax are displayed including tax. */ if (wc_tax_enabled() && 'incl' === get_option('woocommerce_tax_display_shop') && !wc_prices_include_tax()) { $tax_classes = array_merge(array(''), WC_Tax::get_tax_classes()); $class_min = $min; foreach ($tax_classes as $tax_class) { if ($tax_rates = WC_Tax::get_rates($tax_class)) { $class_min = $min - WC_Tax::get_tax_total(WC_Tax::calc_exclusive_tax($min, $tax_rates)); } } $min = $class_min; } return array('key' => '_price', 'value' => array($min, $max), 'compare' => 'BETWEEN', 'type' => 'DECIMAL', 'price_filter' => true); } return array(); }
/** * Calculates a price (could be per period price or sign-up fee) for a subscription less tax * if the subscription is taxable and the prices in the store include tax. * * Based on the WC_Product::get_price_excluding_tax() function. * * @param float $price The price to adjust based on taxes * @param WC_Product $product The product the price belongs too (needed to determine tax class) * @since 1.0 */ public static function calculate_tax_for_subscription($price, $product, $deduct_base_taxes = false) { _deprecated_function(__METHOD__, '1.5.8', 'WC_Product::get_price_including_tax()'); if ($product->is_taxable()) { $tax = new WC_Tax(); $base_tax_rates = $tax->get_shop_base_rate($product->tax_class); $tax_rates = $tax->get_rates($product->get_tax_class()); // This will get the base rate unless we're on the checkout page if ($deduct_base_taxes && get_option('woocommerce_prices_include_tax') == 'yes') { $base_taxes = $tax->calc_tax($price, $base_tax_rates, true); $taxes = $tax->calc_tax($price - array_sum($base_taxes), $tax_rates, false); } elseif (get_option('woocommerce_prices_include_tax') == 'yes') { $taxes = $tax->calc_tax($price, $base_tax_rates, true); } else { $taxes = $tax->calc_tax($price, $base_tax_rates, false); } $tax_amount = $tax->get_tax_total($taxes); } else { $tax_amount = 0; } return $tax_amount; }
/** * Get Price Range for given product ids. * If filtered is true then return price range for filtered products, * otherwise return price range for all products. * * @param boolean $filtered * @return array */ public function getPriceRange($filtered = true) { if ($filtered === true) { $price_range = $this->filteredProductsPriceRange(); } else { $price_range = $this->unfilteredProductsPriceRange(); } if (sizeof($price_range) > 2) { $min = $max = false; foreach ($price_range as $price) { if ($min === false || $min > (int) $price) { $min = floor($price); } if ($max === false || $max < (int) $price) { $max = ceil($price); } } // if tax enabled and shop page shows price including tax if (wc_tax_enabled() && 'incl' === get_option('woocommerce_tax_display_shop') && !wc_prices_include_tax()) { $tax_classes = array_merge(array(''), WC_Tax::get_tax_classes()); foreach ($tax_classes as $tax_class) { $tax_rates = WC_Tax::get_rates($tax_class); $class_min = $min + WC_Tax::get_tax_total(WC_Tax::calc_exclusive_tax($min, $tax_rates)); $class_max = $max + WC_Tax::get_tax_total(WC_Tax::calc_exclusive_tax($max, $tax_rates)); $min = $max = false; if ($min === false || $min > (int) $class_min) { $min = floor($class_min); } if ($max === false || $max < (int) $class_max) { $max = ceil($class_max); } } } // if WooCommerce Currency Switcher plugin is activated if (class_exists('WOOCS')) { $woocs = new WOOCS(); $chosen_currency = $woocs->get_woocommerce_currency(); $currencies = $woocs->get_currencies(); if (sizeof($currencies) > 0) { foreach ($currencies as $currency) { if ($currency['name'] == $chosen_currency) { $rate = $currency['rate']; } } $min = floor($min * $rate); $max = ceil($max * $rate); } } if ($min == $max) { // empty array return array(); } else { // array with min and max values return array($min, $max); } } else { // empty array return array(); } }
/** * Price Filter post filter. * * @param array $filtered_posts * @return array */ public function price_filter($filtered_posts = array()) { global $wpdb; if (isset($_GET['max_price']) || isset($_GET['min_price'])) { $matched_products = array(); $min = isset($_GET['min_price']) ? floatval($_GET['min_price']) : 0; $max = isset($_GET['max_price']) ? floatval($_GET['max_price']) : 9999999999; // If displaying prices in the shop including taxes, but prices don't include taxes.. if (wc_tax_enabled() && 'incl' === get_option('woocommerce_tax_display_shop') && !wc_prices_include_tax()) { $tax_classes = array_merge(array(''), WC_Tax::get_tax_classes()); foreach ($tax_classes as $tax_class) { $tax_rates = WC_Tax::get_rates($tax_class); $min_class = $min - WC_Tax::get_tax_total(WC_Tax::calc_inclusive_tax($min, $tax_rates)); $max_class = $max - WC_Tax::get_tax_total(WC_Tax::calc_inclusive_tax($max, $tax_rates)); $matched_products_query = apply_filters('woocommerce_price_filter_results', $wpdb->get_results($wpdb->prepare("\n\t\t\t\t\t\tSELECT DISTINCT ID, post_parent, post_type FROM {$wpdb->posts}\n\t\t\t\t\t\tINNER JOIN {$wpdb->postmeta} pm1 ON ID = pm1.post_id\n\t\t\t\t\t\tINNER JOIN {$wpdb->postmeta} pm2 ON ID = pm2.post_id\n\t\t\t\t\t\tWHERE post_type IN ( 'product', 'product_variation' )\n\t\t\t\t\t\tAND post_status = 'publish'\n\t\t\t\t\t\tAND pm1.meta_key IN ('" . implode("','", array_map('esc_sql', apply_filters('woocommerce_price_filter_meta_keys', array('_price')))) . "')\n\t\t\t\t\t\tAND pm1.meta_value BETWEEN %f AND %f\n\t\t\t\t\t\tAND pm2.meta_key = '_tax_class'\n\t\t\t\t\t\tAND pm2.meta_value = %s\n\t\t\t\t\t", $min_class, $max_class, sanitize_title($tax_class)), OBJECT_K), $min_class, $max_class); if ($matched_products_query) { foreach ($matched_products_query as $product) { if ($product->post_type == 'product') { $matched_products[] = $product->ID; } if ($product->post_parent > 0) { $matched_products[] = $product->post_parent; } } } } } else { $matched_products_query = apply_filters('woocommerce_price_filter_results', $wpdb->get_results($wpdb->prepare("\n\t\t\t\t\tSELECT DISTINCT ID, post_parent, post_type FROM {$wpdb->posts}\n\t\t\t\t\tINNER JOIN {$wpdb->postmeta} pm1 ON ID = pm1.post_id\n\t\t\t\t\tWHERE post_type IN ( 'product', 'product_variation' )\n\t\t\t\t\tAND post_status = 'publish'\n\t\t\t\t\tAND pm1.meta_key IN ('" . implode("','", array_map('esc_sql', apply_filters('woocommerce_price_filter_meta_keys', array('_price')))) . "')\n\t\t\t\t\tAND pm1.meta_value BETWEEN %d AND %d\n\t\t\t\t", $min, $max), OBJECT_K), $min, $max); if ($matched_products_query) { foreach ($matched_products_query as $product) { if ($product->post_type == 'product') { $matched_products[] = $product->ID; } if ($product->post_parent > 0) { $matched_products[] = $product->post_parent; } } } } $matched_products = array_unique($matched_products); // Filter the id's if (0 === sizeof($filtered_posts)) { $filtered_posts = $matched_products; } else { $filtered_posts = array_intersect($filtered_posts, $matched_products); } $filtered_posts[] = 0; } return (array) $filtered_posts; }
function vtmin_load_vtmin_cart_for_processing() { global $wpdb, $woocommerce, $vtmin_cart, $vtmin_cart_item, $vtmin_info; // from Woocommerce/templates/cart/mini-cart.php and Woocommerce/templates/checkout/review-order.php if (sizeof($woocommerce->cart->get_cart()) > 0) { $woocommerce->cart->calculate_totals(); //v1.09.3 calculation includes generating line subtotals, used below $vtmin_cart = new VTMIN_Cart(); foreach ($woocommerce->cart->get_cart() as $cart_item_key => $cart_item) { $_product = $cart_item['data']; if ($_product->exists() && $cart_item['quantity'] > 0) { $vtmin_cart_item = new VTMIN_Cart_Item(); //the product id does not change in woo if variation purchased. // Load expected variation id, if there, along with constructed product title. $varLabels = ' '; if ($cart_item['variation_id'] > ' ') { // get parent title $parent_post = get_post($cart_item['product_id']); // get variation names to string onto parent title foreach ($cart_item['variation'] as $key => $value) { $varLabels .= $value . ' '; } $vtmin_cart_item->product_id = $cart_item['variation_id']; $vtmin_cart_item->product_name = $parent_post->post_title . ' ' . $varLabels; } else { $vtmin_cart_item->product_id = $cart_item['product_id']; $vtmin_cart_item->product_name = $_product->get_title() . $woocommerce->cart->get_item_data($cart_item); } $vtmin_cart_item->quantity = $cart_item['quantity']; //v1.09.3 commented unit price //$vtmin_cart_item->unit_price = get_option( 'woocommerce_display_cart_prices_excluding_tax' ) == 'yes' || $woocommerce->customer->is_vat_exempt() ? $_product->get_price_excluding_tax() : $_product->get_price(); /* $quantity = 1; //v1.08 vat fix $vtmin_cart_item->unit_price = get_option( 'woocommerce_display_cart_prices_excluding_tax' ) == 'yes' || $woocommerce->customer->is_vat_exempt() ? $_product->get_price_excluding_tax() : $_product->get_price_including_tax( $quantity ); //$_product->get_price(); //v1.08 vat fix */ //v1.09.3 begin // pick up unit price from line subtotal only - // will include all taxation and price adjustments from other plugins //$vtmin_cart_item->total_price = $vtmin_cart_item->quantity * $vtmin_cart_item->unit_price; // $vtmin_cart_item->total_price = $cart_item['line_subtotal']; // $vtmin_cart_item->unit_price = $cart_item['line_subtotal'] / $cart_item['quantity']; if (get_option('woocommerce_calc_taxes') == 'no' || get_option('woocommerce_prices_include_tax') == 'no') { //NO VAT included in price $vtmin_cart_item->unit_price = $cart_item['line_subtotal'] / $cart_item['quantity']; $vtmin_cart_item->total_price = $cart_item['line_subtotal']; } else { //v1.0.7.4 begin //TAX included in price in DB, and Woo $cart_item pricing **has already subtracted out the TAX **, so restore the TAX // this price reflects the tax situation of the ORIGINAL price - so if the price was originally entered with tax, this will reflect tax $price = $cart_item['line_subtotal'] / $cart_item['quantity']; $qty = 1; $_tax = new WC_Tax(); // $product = get_product( $product_id ); $product = get_product($vtmin_cart_item->product_id); $tax_rates = $_tax->get_rates($product->get_tax_class()); $taxes = $_tax->calc_tax($price * $qty, $tax_rates, false); $tax_amount = $_tax->get_tax_total($taxes); $vtmin_cart_item->unit_price = round($price * $qty + $tax_amount, absint(get_option('woocommerce_price_num_decimals'))); $vtmin_cart_item->total_price = $vtmin_cart_item->unit_price * $cart_item['quantity']; } //v1.09.3 end /* ********************************* *** JUST the cat *ids* please... ************************************ */ $vtmin_cart_item->prod_cat_list = wp_get_object_terms($cart_item['product_id'], $vtmin_info['parent_plugin_taxonomy'], $args = array('fields' => 'ids')); $vtmin_cart_item->rule_cat_list = wp_get_object_terms($cart_item['product_id'], $vtmin_info['rulecat_taxonomy'], $args = array('fields' => 'ids')); //add cart_item to cart array $vtmin_cart->cart_items[] = $vtmin_cart_item; } } // endforeach; } }
/** * Output widget. * * @see WP_Widget * * @param array $args * @param array $instance */ public function widget($args, $instance) { global $wp, $wp_the_query; if (!is_post_type_archive('product') && !is_tax(get_object_taxonomies('product'))) { return; } if (!$wp_the_query->post_count) { return; } $min_price = isset($_GET['min_price']) ? esc_attr($_GET['min_price']) : ''; $max_price = isset($_GET['max_price']) ? esc_attr($_GET['max_price']) : ''; wp_enqueue_script('wc-price-slider'); // Remember current filters/search $fields = ''; if (get_search_query()) { $fields .= '<input type="hidden" name="s" value="' . get_search_query() . '" />'; } if (!empty($_GET['post_type'])) { $fields .= '<input type="hidden" name="post_type" value="' . esc_attr($_GET['post_type']) . '" />'; } if (!empty($_GET['product_cat'])) { $fields .= '<input type="hidden" name="product_cat" value="' . esc_attr($_GET['product_cat']) . '" />'; } if (!empty($_GET['product_tag'])) { $fields .= '<input type="hidden" name="product_tag" value="' . esc_attr($_GET['product_tag']) . '" />'; } if (!empty($_GET['orderby'])) { $fields .= '<input type="hidden" name="orderby" value="' . esc_attr($_GET['orderby']) . '" />'; } if (!empty($_GET['min_rating'])) { $fields .= '<input type="hidden" name="min_rating" value="' . esc_attr($_GET['min_rating']) . '" />'; } if ($_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes()) { foreach ($_chosen_attributes as $attribute => $data) { $taxonomy_filter = 'filter_' . str_replace('pa_', '', $attribute); $fields .= '<input type="hidden" name="' . esc_attr($taxonomy_filter) . '" value="' . esc_attr(implode(',', $data['terms'])) . '" />'; if ('or' == $data['query_type']) { $fields .= '<input type="hidden" name="' . esc_attr(str_replace('pa_', 'query_type_', $attribute)) . '" value="or" />'; } } } // Find min and max price in current result set $prices = $this->get_filtered_price(); $min = floor($prices->min_price); $max = ceil($prices->max_price); if ($min === $max) { return; } $this->widget_start($args, $instance); if ('' == get_option('permalink_structure')) { $form_action = remove_query_arg(array('page', 'paged'), add_query_arg($wp->query_string, '', home_url($wp->request))); } else { $form_action = preg_replace('%\\/page/[0-9]+%', '', home_url(trailingslashit($wp->request))); } // Adjust min and max if the store taxes are not displayed how they are stored if (wc_tax_enabled() && 'incl' === get_option('woocommerce_tax_display_shop') && !wc_prices_include_tax()) { $tax_classes = array_merge(array(''), WC_Tax::get_tax_classes()); foreach ($tax_classes as $tax_class) { $tax_rates = WC_Tax::get_rates($tax_class); $class_min = $min + WC_Tax::get_tax_total(WC_Tax::calc_exclusive_tax($min, $tax_rates)); $class_max = $max + WC_Tax::get_tax_total(WC_Tax::calc_exclusive_tax($max, $tax_rates)); if ($class_min < $min) { $min = $class_min; } if ($class_max > $max) { $max = $class_max; } } } echo '<form method="get" action="' . esc_url($form_action) . '"> <div class="price_slider_wrapper"> <div class="price_slider" style="display:none;"></div> <div class="price_slider_amount"> <input type="text" id="min_price" name="min_price" value="' . esc_attr($min_price) . '" data-min="' . esc_attr(apply_filters('woocommerce_price_filter_widget_min_amount', $min)) . '" placeholder="' . esc_attr__('Min price', 'woocommerce') . '" /> <input type="text" id="max_price" name="max_price" value="' . esc_attr($max_price) . '" data-max="' . esc_attr(apply_filters('woocommerce_price_filter_widget_max_amount', $max)) . '" placeholder="' . esc_attr__('Max price', 'woocommerce') . '" /> <button type="submit" class="button">' . __('Filter', 'woocommerce') . '</button> <div class="price_label" style="display:none;"> ' . __('Price:', 'woocommerce') . ' <span class="from"></span> — <span class="to"></span> </div> ' . $fields . ' <div class="clear"></div> </div> </div> </form>'; $this->widget_end($args); }
/** * * Gets custom price on the order page * * @param WC_Product $product * @param int $item_id * @param str $start - Start date * @param str $end - End date * @param array $order_item * @param array $coupons * @return array $item_prices - Item prices (subtotal, total, tax subtotal and tax total) * **/ public function easy_booking_get_booking_price($product, $item_id, $start, $end, $order_item, $coupons) { if (!$product) { return false; } $calc_mode = $this->options['easy_booking_calc_mode']; // Calculation mode (Days or Nights) // Get booking duration $start_diff = strtotime($start); $end_diff = strtotime($end); $diff = absint($start_diff - $end_diff) * 1000; $days = $diff / 86400000; if ($days === 0) { $days = 1; } // If calculation mode is set to "Days", add one day if ($calc_mode === 'days' && $start != $end) { $duration = absint($days + 1); } elseif ($calc_mode === 'days' && $start === $end) { $duration = absint($days); } else { $duration = absint($days); } if ($product->is_taxable()) { $price = $product->get_price_excluding_tax(); // Product price excluding tax } else { $price = $product->get_price(); // Product price } // Price for x days $new_price = apply_filters('easy_booking_get_order_item_price', $price * $duration, $product, $item_id, $duration); if ($product->is_taxable()) { $item_tax_class = $order_item['tax_class']; $product_taxes = $this->easy_booking_get_product_taxes($new_price, $item_tax_class); // Product taxes without potential discounts foreach ($product_taxes as $_tax_id => $_tax_value) { $tax_subtotal[$_tax_id] = $_tax_value; } $tax_amount = WC_Tax::get_tax_total($product_taxes); } if ($coupons) { foreach ($coupons as $code) { $coupon = new WC_Coupon($code); if ($coupon->is_valid_for_product($product)) { $coupon_amount = $coupon->get_discount_amount($new_price, $order_item, true); // Discounted amount for item price $total = $new_price - $coupon_amount; // New price with discount if (!empty($product_taxes)) { foreach ($product_taxes as $_tax_id => $_tax_value) { $tax_discount[$_tax_id] = $coupon->get_discount_amount($_tax_value, $order_item, true); // Discounted amount for item taxes $tax_total[$_tax_id] = $_tax_value - $tax_discount[$_tax_id]; // Product taxes with discount } } } else { if (!empty($product_taxes)) { foreach ($product_taxes as $_tax_id => $_tax_value) { $tax_total[$_tax_id] = $_tax_value; // No valid coupon - Product taxes unchanged } } $total = $new_price; // No valid coupon - Product price unchanged } } } else { if (!empty($product_taxes)) { foreach ($product_taxes as $_tax_id => $_tax_value) { $tax_total[$_tax_id] = $_tax_value; // No coupon - Product taxes unchanged } } $total = $new_price; // No coupon - Product price unchanged } $new_price = $new_price * $order_item['quantity']; // Multiply subtotal by item quantity $total = $total * $order_item['quantity']; // Multiply total by item quantity if (!empty($product_taxes)) { foreach ($tax_subtotal as $tax_subtotal_id => $tax_subtotal_amount) { $tax_subtotal[$tax_subtotal_id] = $tax_subtotal_amount * $order_item['quantity']; } // Multiply tax subtotal by item quantity foreach ($tax_total as $tax_total_id => $tax_total_amount) { $tax_total[$tax_total_id] = $tax_total_amount * $order_item['quantity']; } // Multiply tax total by item quantity // Format taxes $line_taxes = array_map('wc_format_decimal', $tax_total); $line_subtotal_taxes = array_map('wc_format_decimal', $tax_subtotal); $item_prices['tax_subtotal'] = $line_subtotal_taxes; $item_prices['tax_total'] = $line_taxes; } $item_prices['subtotal'] = floatval(wc_format_decimal($new_price, 0)); $item_prices['total'] = floatval(wc_format_decimal($total, 0)); return $item_prices; }
/** * Update order shipping/cart tax total * * @since 4.4 * @param (string) $type "shipping" to update shipping tax total; "cart" to update cart tax total * @param (float) $new_tax new value for tax */ private function update_tax_total($type, $new_tax) { if ($type == 'shipping') { $tax_key = 'shipping_taxes'; $total_key = 'shipping_tax_total'; } else { $tax_key = 'taxes'; $total_key = 'tax_total'; } $this->cart->{$tax_key}[WT_RATE_ID] = $new_tax; if (!WT_SUBS_ACTIVE || !WC_Subscriptions_Cart::cart_contains_subscription()) { // Removing zero tax row causes display issues for subscription orders if (WC_WooTax::get_option('show_zero_tax') != 'true' && $new_tax == 0) { unset($this->cart->{$tax_key}[WT_RATE_ID]); } } // Use get_tax_total to set new tax total so we don't override other rates $this->cart->{$total_key} = version_compare(WOOCOMMERCE_VERSION, '2.2', '>=') ? WC_Tax::get_tax_total($this->cart->{$tax_key}) : $this->cart->tax->get_tax_total($this->cart->{$tax_key}); $this->{$total_key} = $new_tax; }
/** * * @param object $_this * @return number */ function this_get_tax($_this) { $cart = $_this->get_cart(); $tax = $tax_rates = array(); foreach ($cart as $cart_item_key => $values) { $_product = $values['data']; // Prices $base_price = $_product->get_price(); $line_price = $_product->get_price() * $values['quantity']; // Tax data $taxes = array(); $discounted_taxes = array(); /** * No tax to calculate */ if (!$_product->is_taxable()) { // Discounted Price (price with any pre-tax discounts applied) $discounted_price = 0; $line_subtotal_tax = 0; $line_subtotal = $line_price; $line_tax = 0; $line_total = WC_Tax::round($discounted_price * $values['quantity']); /** * Prices include tax */ } elseif ($_this->prices_include_tax) { $base_tax_rates = $shop_tax_rates[$_product->tax_class]; $item_tax_rates = $tax_rates[$_product->get_tax_class()]; /** * ADJUST TAX - Calculations when base tax is not equal to the item tax * * The woocommerce_adjust_non_base_location_prices filter can stop base taxes being taken off when dealing with out of base locations. * e.g. If a product costs 10 including tax, all users will pay 10 regardless of location and taxes. * This feature is experimental @since 2.4.7 and may change in the future. Use at your risk. */ if ($item_tax_rates !== $base_tax_rates && apply_filters('woocommerce_adjust_non_base_location_prices', true)) { // Work out a new base price without the shop's base tax $taxes = WC_Tax::calc_tax($line_price, $base_tax_rates, true, true); // Now we have a new item price (excluding TAX) $line_subtotal = round($line_price - array_sum($taxes), WC_ROUNDING_PRECISION); $taxes = WC_Tax::calc_tax($line_subtotal, $item_tax_rates); $line_subtotal_tax = array_sum($taxes); // Adjusted price (this is the price including the new tax rate) $adjusted_price = ($line_subtotal + $line_subtotal_tax) / $values['quantity']; // Apply discounts $discounted_price = $_this->get_discounted_price($values, $adjusted_price, true); $discounted_taxes = WC_Tax::calc_tax($discounted_price * $values['quantity'], $item_tax_rates, true); $line_tax = array_sum($discounted_taxes); $line_total = $discounted_price * $values['quantity'] - $line_tax; /** * Regular tax calculation (customer inside base and the tax class is unmodified */ } else { // Work out a new base price without the item tax $taxes = WC_Tax::calc_tax($line_price, $item_tax_rates, true); // Now we have a new item price (excluding TAX) $line_subtotal = $line_price - array_sum($taxes); $line_subtotal_tax = array_sum($taxes); // Calc prices and tax (discounted) $discounted_price = 0; $discounted_taxes = WC_Tax::calc_tax($discounted_price * $values['quantity'], $item_tax_rates, true); $line_tax = array_sum($discounted_taxes); $line_total = $discounted_price * $values['quantity'] - $line_tax; } // Tax rows - merge the totals we just got foreach (array_keys($_this->taxes + $discounted_taxes) as $key) { $tax[$key] = (isset($discounted_taxes[$key]) ? $discounted_taxes[$key] : 0) + (isset($_this->taxes[$key]) ? $_this->taxes[$key] : 0); } /** * Prices exclude tax */ } else { $item_tax_rates = $tax_rates[$_product->get_tax_class()]; // Work out a new base price without the shop's base tax $taxes = WC_Tax::calc_tax($line_price, $item_tax_rates); // Now we have the item price (excluding TAX) $line_subtotal = $line_price; $line_subtotal_tax = array_sum($taxes); // Now calc product rates $discounted_price = 0; $discounted_taxes = WC_Tax::calc_tax($discounted_price * $values['quantity'], $item_tax_rates); $discounted_tax_amount = array_sum($discounted_taxes); $line_tax = $discounted_tax_amount; $line_total = $discounted_price * $values['quantity']; // Tax rows - merge the totals we just got foreach (array_keys($_this->taxes + $discounted_taxes) as $key) { $tax[$key] = (isset($discounted_taxes[$key]) ? $discounted_taxes[$key] : 0) + (isset($_this->taxes[$key]) ? $_this->taxes[$key] : 0); } } $tax = array_map(array('WC_Tax', 'round'), $tax); $tax = array_sum($tax); $shipping_total = WC()->shipping->shipping_total; $shipping_taxes = WC()->shipping->shipping_taxes; if ($_this->round_at_subtotal) { $shipping_tax_total = WC_Tax::get_tax_total($shipping_taxes); $shipping_taxes = array_map(array('WC_Tax', 'round'), $shipping_taxes); } else { $shipping_tax_total = array_sum($shipping_taxes); } $array = array('tax' => $tax, 'shipping' => $shipping_total, 'shipping_tax' => $shipping_tax_total); } return $array; }
/** * Calculate totals for cart. Implements vat exception for digital products. */ public function calculate_totals() { $this->reset(); $this->coupons = $this->get_coupons(); do_action('woocommerce_before_calculate_totals', $this); if (sizeof($this->get_cart()) == 0) { $this->set_session(); return; } $tax_rates = array(); $shop_tax_rates = array(); /** * Calculate subtotals for items. This is done first so that discount logic can use the values. */ foreach ($this->get_cart() as $cart_item_key => $values) { $_product = $values['data']; // Count items + weight $this->cart_contents_weight += $_product->get_weight() * $values['quantity']; $this->cart_contents_count += $values['quantity']; // Prices $line_price = $_product->get_price() * $values['quantity']; $line_subtotal = 0; $line_subtotal_tax = 0; /** * No tax to calculate */ if (!$_product->is_taxable()) { // Subtotal is the undiscounted price $this->subtotal += $line_price; $this->subtotal_ex_tax += $line_price; /** * Prices include tax * * To prevent rounding issues we need to work with the inclusive price where possible * otherwise we'll see errors such as when working with a 9.99 inc price, 20% VAT which would * be 8.325 leading to totals being 1p off * * Pre tax coupons come off the price the customer thinks they are paying - tax is calculated * afterwards. * * e.g. $100 bike with $10 coupon = customer pays $90 and tax worked backwards from that */ } elseif ($this->prices_include_tax) { // Get base tax rates if (empty($shop_tax_rates[$_product->tax_class])) { $shop_tax_rates[$_product->tax_class] = WC_Tax::get_base_tax_rates($_product->tax_class); } // Get item tax rates if (empty($tax_rates[$_product->get_tax_class()])) { $tax_rates[$_product->get_tax_class()] = WC_Tax::get_rates($_product->get_tax_class()); } $base_tax_rates = $shop_tax_rates[$_product->tax_class]; $item_tax_rates = $tax_rates[$_product->get_tax_class()]; /** * ADJUST TAX - Calculations when base tax is not equal to the item tax */ if ($item_tax_rates !== $base_tax_rates) { // Work out a new base price without the shop's base tax $taxes = WC_Tax::calc_tax($line_price, $base_tax_rates, true, true); // Digital VAT exception if ($this->is_virtual_taxable() && $_product->gzd_product->is_virtual_vat_exception()) { $taxes = WC_Tax::calc_tax($line_price, $item_tax_rates, true, true); } // Now we have a new item price (excluding TAX) $line_subtotal = $line_price - array_sum($taxes); // Now add modified taxes $tax_result = WC_Tax::calc_tax($line_subtotal, $item_tax_rates); $line_subtotal_tax = array_sum($tax_result); /** * Regular tax calculation (customer inside base and the tax class is unmodified */ } else { // Calc tax normally $taxes = WC_Tax::calc_tax($line_price, $item_tax_rates, true); $line_subtotal_tax = array_sum($taxes); $line_subtotal = $line_price - array_sum($taxes); } /** * Prices exclude tax * * This calculation is simpler - work with the base, untaxed price. */ } else { // Get item tax rates if (empty($tax_rates[$_product->get_tax_class()])) { $tax_rates[$_product->get_tax_class()] = WC_Tax::get_rates($_product->get_tax_class()); } $item_tax_rates = $tax_rates[$_product->get_tax_class()]; // Base tax for line before discount - we will store this in the order data $taxes = WC_Tax::calc_tax($line_price, $item_tax_rates); $line_subtotal_tax = array_sum($taxes); $line_subtotal = $line_price; } // Add to main subtotal $this->subtotal += $line_subtotal + $line_subtotal_tax; $this->subtotal_ex_tax += $line_subtotal; } /** * Calculate totals for items */ foreach ($this->get_cart() as $cart_item_key => $values) { $_product = $values['data']; // Prices $base_price = $_product->get_price(); $line_price = $_product->get_price() * $values['quantity']; // Tax data $taxes = array(); $discounted_taxes = array(); /** * No tax to calculate */ if (!$_product->is_taxable()) { // Discounted Price (price with any pre-tax discounts applied) $discounted_price = $this->get_discounted_price($values, $base_price, true); $line_subtotal_tax = 0; $line_subtotal = $line_price; $line_tax = 0; $line_total = WC_Tax::round($discounted_price * $values['quantity']); /** * Prices include tax */ } elseif ($this->prices_include_tax) { $base_tax_rates = $shop_tax_rates[$_product->tax_class]; $item_tax_rates = $tax_rates[$_product->get_tax_class()]; /** * ADJUST TAX - Calculations when base tax is not equal to the item tax */ if ($item_tax_rates !== $base_tax_rates) { // Work out a new base price without the shop's base tax $taxes = WC_Tax::calc_tax($line_price, $base_tax_rates, true, true); // Digital tax exception if ($this->is_virtual_taxable() && $_product->gzd_product->is_virtual_vat_exception()) { $taxes = WC_Tax::calc_tax($line_price, $item_tax_rates, true, true); } // Now we have a new item price (excluding TAX) $line_subtotal = round($line_price - array_sum($taxes), WC_ROUNDING_PRECISION); $taxes = WC_Tax::calc_tax($line_subtotal, $item_tax_rates); $line_subtotal_tax = array_sum($taxes); // Adjusted price (this is the price including the new tax rate) $adjusted_price = ($line_subtotal + $line_subtotal_tax) / $values['quantity']; // Apply discounts $discounted_price = $this->get_discounted_price($values, $adjusted_price, true); $discounted_taxes = WC_Tax::calc_tax($discounted_price * $values['quantity'], $item_tax_rates, true); $line_tax = array_sum($discounted_taxes); $line_total = $discounted_price * $values['quantity'] - $line_tax; /** * Regular tax calculation (customer inside base and the tax class is unmodified */ } else { // Work out a new base price without the item tax $taxes = WC_Tax::calc_tax($line_price, $item_tax_rates, true); // Now we have a new item price (excluding TAX) $line_subtotal = $line_price - array_sum($taxes); $line_subtotal_tax = array_sum($taxes); // Calc prices and tax (discounted) $discounted_price = $this->get_discounted_price($values, $base_price, true); $discounted_taxes = WC_Tax::calc_tax($discounted_price * $values['quantity'], $item_tax_rates, true); $line_tax = array_sum($discounted_taxes); $line_total = $discounted_price * $values['quantity'] - $line_tax; } // Tax rows - merge the totals we just got foreach (array_keys($this->taxes + $discounted_taxes) as $key) { $this->taxes[$key] = (isset($discounted_taxes[$key]) ? $discounted_taxes[$key] : 0) + (isset($this->taxes[$key]) ? $this->taxes[$key] : 0); } /** * Prices exclude tax */ } else { $item_tax_rates = $tax_rates[$_product->get_tax_class()]; // Work out a new base price without the shop's base tax $taxes = WC_Tax::calc_tax($line_price, $item_tax_rates); // Now we have the item price (excluding TAX) $line_subtotal = $line_price; $line_subtotal_tax = array_sum($taxes); // Now calc product rates $discounted_price = $this->get_discounted_price($values, $base_price, true); $discounted_taxes = WC_Tax::calc_tax($discounted_price * $values['quantity'], $item_tax_rates); $discounted_tax_amount = array_sum($discounted_taxes); $line_tax = $discounted_tax_amount; $line_total = $discounted_price * $values['quantity']; // Tax rows - merge the totals we just got foreach (array_keys($this->taxes + $discounted_taxes) as $key) { $this->taxes[$key] = (isset($discounted_taxes[$key]) ? $discounted_taxes[$key] : 0) + (isset($this->taxes[$key]) ? $this->taxes[$key] : 0); } } // Cart contents total is based on discounted prices and is used for the final total calculation $this->cart_contents_total += $line_total; // Store costs + taxes for lines $this->cart_contents[$cart_item_key]['line_total'] = $line_total; $this->cart_contents[$cart_item_key]['line_tax'] = $line_tax; $this->cart_contents[$cart_item_key]['line_subtotal'] = $line_subtotal; $this->cart_contents[$cart_item_key]['line_subtotal_tax'] = $line_subtotal_tax; // Store rates ID and costs - Since 2.2 $this->cart_contents[$cart_item_key]['line_tax_data'] = array('total' => $discounted_taxes, 'subtotal' => $taxes); } // Only calculate the grand total + shipping if on the cart/checkout if (is_checkout() || is_cart() || defined('WOOCOMMERCE_CHECKOUT') || defined('WOOCOMMERCE_CART')) { // Calculate the Shipping $this->calculate_shipping(); // Trigger the fees API where developers can add fees to the cart $this->calculate_fees(); // Total up/round taxes and shipping taxes if ($this->round_at_subtotal) { $this->tax_total = WC_Tax::get_tax_total($this->taxes); $this->shipping_tax_total = WC_Tax::get_tax_total($this->shipping_taxes); $this->taxes = array_map(array('WC_Tax', 'round'), $this->taxes); $this->shipping_taxes = array_map(array('WC_Tax', 'round'), $this->shipping_taxes); } else { $this->tax_total = array_sum($this->taxes); $this->shipping_tax_total = array_sum($this->shipping_taxes); } // VAT exemption done at this point - so all totals are correct before exemption if (WC()->customer->is_vat_exempt()) { $this->remove_taxes(); } // Allow plugins to hook and alter totals before final total is calculated do_action('woocommerce_calculate_totals', $this); // Grand Total - Discounted product prices, discounted tax, shipping cost + tax $this->total = max(0, apply_filters('woocommerce_calculated_total', round($this->cart_contents_total + $this->tax_total + $this->shipping_tax_total + $this->shipping_total + $this->fee_total, $this->dp), $this)); } else { // Set tax total to sum of all tax rows $this->tax_total = WC_Tax::get_tax_total($this->taxes); // VAT exemption done at this point - so all totals are correct before exemption if (WC()->customer->is_vat_exempt()) { $this->remove_taxes(); } } do_action('woocommerce_after_calculate_totals', $this); //print_r($this->taxes); $this->set_session(); }
/** * Function to apply discounts to a product and get the discounted price (before tax is applied). * * @param mixed $values * @param mixed $price * @param bool $add_totals (default: false) * @return float price */ public function get_discounted_price($values, $price, $add_totals = false) { if (!$price) { return $price; } if (!empty($this->coupons)) { $product = $values['data']; foreach ($this->coupons as $code => $coupon) { if ($coupon->is_valid() && ($coupon->is_valid_for_product($product, $values) || $coupon->is_valid_for_cart())) { $discount_amount = $coupon->get_discount_amount($price, $values, $single = true); $price = max($price - $discount_amount, 0); // Store the totals for DISPLAY in the cart if ($add_totals) { $total_discount = $discount_amount * $values['quantity']; $total_discount_tax = 0; // Calc discounted tax $tax_rates = WC_Tax::get_rates($product->get_tax_class()); $taxes = WC_Tax::calc_tax($discount_amount, $tax_rates, $this->prices_include_tax); $total_discount_tax = WC_Tax::get_tax_total($taxes) * $values['quantity']; $total_discount = $this->prices_include_tax ? $total_discount - $total_discount_tax : $total_discount; $this->discount_cart += $total_discount; $this->discount_cart_tax += $total_discount_tax; $this->increase_coupon_discount_amount($code, $total_discount, $total_discount_tax); $this->increase_coupon_applied_count($code, $values['quantity']); } } } } return apply_filters('woocommerce_get_discounted_price', $price, $values, $this); }
/** * widget function. * * @see WP_Widget * * @param array $args * @param array $instance */ public function widget($args, $instance) { global $_chosen_attributes, $wpdb, $wp; if (!is_post_type_archive('product') && !is_tax(get_object_taxonomies('product'))) { return; } if (sizeof(WC()->query->unfiltered_product_ids) == 0) { return; // None shown - return } $min_price = isset($_GET['min_price']) ? esc_attr($_GET['min_price']) : ''; $max_price = isset($_GET['max_price']) ? esc_attr($_GET['max_price']) : ''; wp_enqueue_script('wc-price-slider'); // Remember current filters/search $fields = ''; if (get_search_query()) { $fields .= '<input type="hidden" name="s" value="' . get_search_query() . '" />'; } if (!empty($_GET['post_type'])) { $fields .= '<input type="hidden" name="post_type" value="' . esc_attr($_GET['post_type']) . '" />'; } if (!empty($_GET['product_cat'])) { $fields .= '<input type="hidden" name="product_cat" value="' . esc_attr($_GET['product_cat']) . '" />'; } if (!empty($_GET['product_tag'])) { $fields .= '<input type="hidden" name="product_tag" value="' . esc_attr($_GET['product_tag']) . '" />'; } if (!empty($_GET['orderby'])) { $fields .= '<input type="hidden" name="orderby" value="' . esc_attr($_GET['orderby']) . '" />'; } if ($_chosen_attributes) { foreach ($_chosen_attributes as $attribute => $data) { $taxonomy_filter = 'filter_' . str_replace('pa_', '', $attribute); $fields .= '<input type="hidden" name="' . esc_attr($taxonomy_filter) . '" value="' . esc_attr(implode(',', $data['terms'])) . '" />'; if ('or' == $data['query_type']) { $fields .= '<input type="hidden" name="' . esc_attr(str_replace('pa_', 'query_type_', $attribute)) . '" value="or" />'; } } } if (0 === sizeof(WC()->query->layered_nav_product_ids)) { $min = floor($wpdb->get_var("\n\t\t\t\tSELECT min(meta_value + 0)\n\t\t\t\tFROM {$wpdb->posts} as posts\n\t\t\t\tLEFT JOIN {$wpdb->postmeta} as postmeta ON posts.ID = postmeta.post_id\n\t\t\t\tWHERE meta_key IN ('" . implode("','", array_map('esc_sql', apply_filters('woocommerce_price_filter_meta_keys', array('_price', '_min_variation_price')))) . "')\n\t\t\t\tAND meta_value != ''\n\t\t\t")); $max = ceil($wpdb->get_var("\n\t\t\t\tSELECT max(meta_value + 0)\n\t\t\t\tFROM {$wpdb->posts} as posts\n\t\t\t\tLEFT JOIN {$wpdb->postmeta} as postmeta ON posts.ID = postmeta.post_id\n\t\t\t\tWHERE meta_key IN ('" . implode("','", array_map('esc_sql', apply_filters('woocommerce_price_filter_meta_keys', array('_price')))) . "')\n\t\t\t")); } else { $min = floor($wpdb->get_var("\n\t\t\t\tSELECT min(meta_value + 0)\n\t\t\t\tFROM {$wpdb->posts} as posts\n\t\t\t\tLEFT JOIN {$wpdb->postmeta} as postmeta ON posts.ID = postmeta.post_id\n\t\t\t\tWHERE meta_key IN ('" . implode("','", array_map('esc_sql', apply_filters('woocommerce_price_filter_meta_keys', array('_price', '_min_variation_price')))) . "')\n\t\t\t\tAND meta_value != ''\n\t\t\t\tAND (\n\t\t\t\t\tposts.ID IN (" . implode(',', array_map('absint', WC()->query->layered_nav_product_ids)) . ")\n\t\t\t\t\tOR (\n\t\t\t\t\t\tposts.post_parent IN (" . implode(',', array_map('absint', WC()->query->layered_nav_product_ids)) . ")\n\t\t\t\t\t\tAND posts.post_parent != 0\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t")); $max = ceil($wpdb->get_var("\n\t\t\t\tSELECT max(meta_value + 0)\n\t\t\t\tFROM {$wpdb->posts} as posts\n\t\t\t\tLEFT JOIN {$wpdb->postmeta} as postmeta ON posts.ID = postmeta.post_id\n\t\t\t\tWHERE meta_key IN ('" . implode("','", array_map('esc_sql', apply_filters('woocommerce_price_filter_meta_keys', array('_price')))) . "')\n\t\t\t\tAND (\n\t\t\t\t\tposts.ID IN (" . implode(',', array_map('absint', WC()->query->layered_nav_product_ids)) . ")\n\t\t\t\t\tOR (\n\t\t\t\t\t\tposts.post_parent IN (" . implode(',', array_map('absint', WC()->query->layered_nav_product_ids)) . ")\n\t\t\t\t\t\tAND posts.post_parent != 0\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t")); } if ($min == $max) { return; } $this->widget_start($args, $instance); if ('' == get_option('permalink_structure')) { $form_action = remove_query_arg(array('page', 'paged'), add_query_arg($wp->query_string, '', home_url($wp->request))); } else { $form_action = preg_replace('%\\/page/[0-9]+%', '', home_url(trailingslashit($wp->request))); } if (wc_tax_enabled() && 'incl' === get_option('woocommerce_tax_display_shop') && !wc_prices_include_tax()) { $tax_classes = array_merge(array(''), WC_Tax::get_tax_classes()); $min = 0; foreach ($tax_classes as $tax_class) { $tax_rates = WC_Tax::get_rates($tax_class); $class_min = $min + WC_Tax::get_tax_total(WC_Tax::calc_exclusive_tax($min, $tax_rates)); $class_max = $max + WC_Tax::get_tax_total(WC_Tax::calc_exclusive_tax($max, $tax_rates)); if ($min === 0 || $class_min < $min) { $min = $class_min; } if ($class_max > $max) { $max = $class_max; } } } echo '<form method="get" action="' . esc_url($form_action) . '"> <div class="price_slider_wrapper"> <div class="price_slider" style="display:none;"></div> <div class="price_slider_amount"> <input type="text" id="min_price" name="min_price" value="' . esc_attr($min_price) . '" data-min="' . esc_attr(apply_filters('woocommerce_price_filter_widget_min_amount', $min)) . '" placeholder="' . esc_attr__('Min price', 'woocommerce') . '" /> <input type="text" id="max_price" name="max_price" value="' . esc_attr($max_price) . '" data-max="' . esc_attr(apply_filters('woocommerce_price_filter_widget_max_amount', $max)) . '" placeholder="' . esc_attr__('Max price', 'woocommerce') . '" /> <button type="submit" class=" filter">' . __('Filter', 'woocommerce') . '</button> <div class="price_label price-input" style="display:none;"> ' . __('Price:', 'woocommerce') . ' <span class="from"></span> — <span class="to"></span> </div> ' . $fields . ' <div class="clear"></div> </div> </div> </form>'; $this->widget_end($args); }
/** * Returns the price (including tax). Uses customer tax rates. Can work for a specific $qty for more accurate taxes. * * @param string $price to calculate, left blank to just use get_price() * @return string */ public function get_price_including_tax($qty = 1, $price = '') { if ($price === '') { $price = $this->get_price(); } if ($this->is_taxable()) { if (get_option('woocommerce_prices_include_tax') === 'no') { $tax_rates = WC_Tax::get_rates($this->get_tax_class()); $taxes = WC_Tax::calc_tax($price * $qty, $tax_rates, false); $tax_amount = WC_Tax::get_tax_total($taxes); $price = round($price * $qty + $tax_amount, wc_get_price_decimals()); } else { $tax_rates = WC_Tax::get_rates($this->get_tax_class()); $base_tax_rates = WC_Tax::get_base_tax_rates($this->tax_class); if (!empty(WC()->customer) && WC()->customer->is_vat_exempt()) { $base_taxes = WC_Tax::calc_tax($price * $qty, $base_tax_rates, true); $base_tax_amount = array_sum($base_taxes); $price = round($price * $qty - $base_tax_amount, wc_get_price_decimals()); /** * The woocommerce_adjust_non_base_location_prices filter can stop base taxes being taken off when dealing with out of base locations. * e.g. If a product costs 10 including tax, all users will pay 10 regardless of location and taxes. * This feature is experimental @since 2.4.7 and may change in the future. Use at your risk. */ } elseif ($tax_rates !== $base_tax_rates && apply_filters('woocommerce_adjust_non_base_location_prices', true)) { $base_taxes = WC_Tax::calc_tax($price * $qty, $base_tax_rates, true); $modded_taxes = WC_Tax::calc_tax($price * $qty - array_sum($base_taxes), $tax_rates, false); $price = round($price * $qty - array_sum($base_taxes) + array_sum($modded_taxes), wc_get_price_decimals()); } else { $price = $price * $qty; } } } else { $price = $price * $qty; } return apply_filters('woocommerce_get_price_including_tax', $price, $qty, $this); }
/** * Return a meta query for filtering by price. * @return array */ private function price_filter_meta_query() { if (isset($_GET['max_price']) || isset($_GET['min_price'])) { $min = isset($_GET['min_price']) ? floatval($_GET['min_price']) : 0; $max = isset($_GET['max_price']) ? floatval($_GET['max_price']) : 9999999999.0; // If displaying prices in the shop including taxes, but prices don't include taxes.. if (wc_tax_enabled() && 'incl' === get_option('woocommerce_tax_display_shop') && !wc_prices_include_tax()) { $tax_classes = array_merge(array(''), WC_Tax::get_tax_classes()); foreach ($tax_classes as $tax_class) { $tax_rates = WC_Tax::get_rates($tax_class); $class_min = $min - WC_Tax::get_tax_total(WC_Tax::calc_inclusive_tax($min, $tax_rates)); $class_max = $max - WC_Tax::get_tax_total(WC_Tax::calc_inclusive_tax($max, $tax_rates)); if ($class_min < $min) { $min = $class_min; } if ($class_max > $max) { $max = $class_max; } } } return array('key' => '_price', 'value' => array($min, $max), 'compare' => 'BETWEEN', 'type' => 'DECIMAL', 'price_filter' => true); } return array(); }
/** * Returns the price (excluding tax) - ignores tax_class filters since the price may *include* tax and thus needs subtracting. * * @access public * @return string */ function get_price_excluding_tax() { $price = $this->get_price(); if ($this->is_taxable() && get_option('woocommerce_prices_include_tax') == 'yes') { $_tax = new WC_Tax(); $tax_rates = $_tax->get_shop_base_rate($this->tax_class); $taxes = $_tax->calc_tax($price, $tax_rates, true); $tax_amount = $_tax->get_tax_total($taxes); $price = round($price - $tax_amount, 2); } return apply_filters('woocommerce_get_price_excluding_tax', $price, $this); }
/** * Get tax totals. */ public function test_get_tax_total() { $to_total = array('1' => '1.665', '2' => '2'); $this->assertEquals(WC_Tax::get_tax_total($to_total), '3.665'); }
/** * Function to apply discounts to a product and get the discounted price (before tax is applied). * * @param mixed $values * @param mixed $price * @param bool $add_totals (default: false) * @return float price */ public function get_discounted_price($values, $price, $add_totals = false) { if (!$price) { return $price; } $undiscounted_price = $price; if (!empty($this->coupons)) { $product = $values['data']; foreach ($this->coupons as $code => $coupon) { if ($coupon->is_valid() && ($coupon->is_valid_for_product($product, $values) || $coupon->is_valid_for_cart())) { $discount_amount = $coupon->get_discount_amount('yes' === get_option('woocommerce_calc_discounts_sequentially', 'no') ? $price : $undiscounted_price, $values, true); $discount_amount = min($price, $discount_amount); $price = max($price - $discount_amount, 0); // Store the totals for DISPLAY in the cart if ($add_totals) { $total_discount = $discount_amount * $values['quantity']; $total_discount_tax = 0; if (wc_tax_enabled()) { $tax_rates = WC_Tax::get_rates($product->get_tax_class()); $taxes = WC_Tax::calc_tax($discount_amount, $tax_rates, $this->prices_include_tax); $total_discount_tax = WC_Tax::get_tax_total($taxes) * $values['quantity']; $total_discount = $this->prices_include_tax ? $total_discount - $total_discount_tax : $total_discount; $this->discount_cart_tax += $total_discount_tax; } $this->discount_cart += $total_discount; $this->increase_coupon_discount_amount($code, $total_discount, $total_discount_tax); $this->increase_coupon_applied_count($code, $values['quantity']); } } // If the price is 0, we can stop going through coupons because there is nothing more to discount for this product. if (0 >= $price) { break; } } } return apply_filters('woocommerce_get_discounted_price', $price, $values, $this); }
function vtprd_get_price_including_tax_forced($product_id, $price, $product) { global $post, $wpdb, $woocommerce, $vtprd_cart, $vtprd_cart_item, $vtprd_setup_options, $vtprd_info; //error_log( print_r( 'vtprd_get_price_including_tax_forced, Begin price= ' .$price .' Product= ' .$product_id , true ) ); //changed $this-> to $product-> //use $discount_price as basi $qty = 1; $_tax = new WC_Tax(); if ($product->is_taxable()) { if (get_option('woocommerce_prices_include_tax') === 'no') { $tax_rates = $_tax->get_rates($product->get_tax_class()); $taxes = $_tax->calc_tax($price * $qty, $tax_rates, false); $tax_amount = $_tax->get_tax_total($taxes); $price = round($price * $qty + $tax_amount, absint(get_option('woocommerce_price_num_decimals'))); } else { $tax_rates = $_tax->get_rates($product->get_tax_class()); $base_tax_rates = $_tax->get_shop_base_rate($product->tax_class); // if ( ! empty( $woocommerce->customer ) && $woocommerce->customer->is_vat_exempt() ) { //v1.0.7.5 if (vtprd_maybe_customer_tax_exempt()) { //v1.0.7.9 $base_taxes = $_tax->calc_tax($price * $qty, $base_tax_rates, true); $base_tax_amount = array_sum($base_taxes); $price = round($price * $qty - $base_tax_amount, absint(get_option('woocommerce_price_num_decimals'))); } elseif ($tax_rates !== $base_tax_rates) { $base_taxes = $_tax->calc_tax($price * $qty, $base_tax_rates, true); $modded_taxes = $_tax->calc_tax($price * $qty - array_sum($base_taxes), $tax_rates, false); $price = round($price * $qty - array_sum($base_taxes) + array_sum($modded_taxes), absint(get_option('woocommerce_price_num_decimals'))); } else { $taxes = $_tax->calc_tax($price * $qty, $tax_rates, false); $tax_amount = $_tax->get_tax_total($taxes); $price = round($price * $qty + $tax_amount, absint(get_option('woocommerce_price_num_decimals'))); } } } else { $price = $price * $qty; } return $price; }
/** * Returns the price (including tax). Uses customer tax rates. Can work for a specific $qty for more accurate taxes. * * @param string $price to calculate, left blank to just use get_price() * @return string */ public function get_price_including_tax($qty = 1, $price = '') { if ($price === '') { $price = $this->get_price(); } if ($this->is_taxable()) { if (get_option('woocommerce_prices_include_tax') === 'no') { $tax_rates = WC_Tax::get_rates($this->get_tax_class()); $taxes = WC_Tax::calc_tax($price * $qty, $tax_rates, false); $tax_amount = WC_Tax::get_tax_total($taxes); $price = round($price * $qty + $tax_amount, wc_get_price_decimals()); } else { $tax_rates = WC_Tax::get_rates($this->get_tax_class()); $base_tax_rates = WC_Tax::get_base_tax_rates($this->tax_class); if (!empty(WC()->customer) && WC()->customer->is_vat_exempt()) { $base_taxes = WC_Tax::calc_tax($price * $qty, $base_tax_rates, true); $base_tax_amount = array_sum($base_taxes); $price = round($price * $qty - $base_tax_amount, wc_get_price_decimals()); } elseif ($tax_rates !== $base_tax_rates) { $base_taxes = WC_Tax::calc_tax($price * $qty, $base_tax_rates, true); $modded_taxes = WC_Tax::calc_tax($price * $qty - array_sum($base_taxes), $tax_rates, false); $price = round($price * $qty - array_sum($base_taxes) + array_sum($modded_taxes), wc_get_price_decimals()); } else { $price = $price * $qty; } } } else { $price = $price * $qty; } return apply_filters('woocommerce_get_price_including_tax', $price, $qty, $this); }
/** * Calculate the total tax amount * @param array $taxes * @return float */ public static function get_tax_total($taxes) { if (self::is_wc_version_gte_2_2()) { return WC_Tax::get_tax_total($taxes); } else { return WC()->cart->tax->get_tax_total($taxes); } }