Merge remote-tracking branch 'upstream/master' into order-factory-refactor

Conflicts:
	includes/class-wc-order.php
This commit is contained in:
Coen Jacobs 2014-07-03 13:38:55 +02:00
commit 86a4add087
69 changed files with 5613 additions and 3427 deletions

File diff suppressed because one or more lines are too long

View File

@ -517,7 +517,7 @@ ul.wc_coupon_list_block {
._shipping_last_name_field, ._shipping_address_2_field, ._shipping_postcode_field, ._shipping_state_field {
float: right;
}
._billing_company_field, ._shipping_company_field {
._billing_company_field, ._shipping_company_field, ._transaction_id_field {
clear: both;
width: 100%;
}

File diff suppressed because one or more lines are too long

View File

@ -1224,7 +1224,7 @@ p.demo_store {
dt, dd {
display: inline-block;
float: left;
margin-botom:1em;
margin-bottom:1em;
}
dt {
font-weight:bold;

View File

@ -50,7 +50,7 @@ jQuery( function ( $ ) {
'fadeOut': 50
});
$( 'input.variable_is_downloadable, input.variable_is_virtual' ).change();
$( 'input.variable_is_downloadable, input.variable_is_virtual, input.variable_manage_stock' ).change();
$( '.woocommerce_variations' ).unblock();
$( '#variable_product_options' ).trigger( 'woocommerce_variations_added' );
@ -178,6 +178,11 @@ jQuery( function ( $ ) {
checkbox.attr( 'checked', ! checkbox.attr( 'checked' ) );
$( 'input.variable_is_virtual' ).change();
break;
case 'toggle_manage_stock' :
checkbox = $('input[name^="variable_manage_stock"]');
checkbox.attr( 'checked', ! checkbox.attr( 'checked' ) );
$( 'input.variable_manage_stock' ).change();
break;
case 'delete_all' :
answer = window.confirm( woocommerce_admin_meta_boxes_variations.i18n_delete_all_variations );
@ -271,26 +276,30 @@ jQuery( function ( $ ) {
});
$( '#variable_product_options' ).on( 'change', 'input.variable_is_downloadable', function () {
$( this ).closest( '.woocommerce_variation' ).find( '.show_if_variation_downloadable' ).hide();
if ( $( this ).is( ':checked' ) ) {
$( this ).closest( '.woocommerce_variation' ).find( '.show_if_variation_downloadable' ).show();
}
});
$( '#variable_product_options' ).on( 'change', 'input.variable_is_virtual', function () {
$( this ).closest( '.woocommerce_variation' ).find( '.hide_if_variation_virtual' ).show();
if ( $( this ).is( ':checked' ) ) {
$( this ).closest( '.woocommerce_variation' ).find( '.hide_if_variation_virtual' ).hide();
}
});
$( 'input.variable_is_downloadable, input.variable_is_virtual' ).change();
$( '#variable_product_options' ).on( 'change', 'input.variable_manage_stock', function () {
$( this ).closest( '.woocommerce_variation' ).find( '.show_if_variation_manage_stock' ).hide();
if ( $( this ).is( ':checked' ) ) {
$( this ).closest( '.woocommerce_variation' ).find( '.show_if_variation_manage_stock' ).show();
}
});
$( 'input.variable_is_downloadable, input.variable_is_virtual, input.variable_manage_stock' ).change();
// Ordering
$( '#variable_product_options' ).on( 'woocommerce_variations_added', function () {

File diff suppressed because one or more lines are too long

View File

@ -451,7 +451,6 @@ jQuery( function($){
};
$.post( woocommerce_admin_meta_boxes.ajax_url, data, function( response ) {
if ( response ) {
$items.each( function() {
var $row = $(this);
@ -1148,8 +1147,11 @@ jQuery( function($){
// STOCK OPTIONS
$('input#_manage_stock').change(function(){
if ($(this).is(':checked')) $('div.stock_fields').show();
else $('div.stock_fields').hide();
if ( $(this).is(':checked') ) {
$('div.stock_fields').show();
} else {
$('div.stock_fields').hide();
}
}).change();

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -52,6 +52,360 @@ abstract class WC_Abstract_Order {
}
}
/**
* Remove all line items (products, coupons, shipping, taxes) from the order.
*/
public function remove_order_items( $type = null ) {
global $wpdb;
if ( $type ) {
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s )", $this->id, $type ) );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s", $this->id, $type ) );
} else {
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d )", $this->id ) );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $this->id ) );
}
}
/**
* Set the payment method for the order
* @param WC_Payment_Gateway
*/
public function set_payment_method( $payment_method ) {
if ( is_object( $payment_method ) ) {
update_post_meta( $this->id, '_payment_method', $payment_method->id );
update_post_meta( $this->id, '_payment_method_title', $payment_method->get_title() );
}
}
/**
* Set the customer address
* @param array $address Address data
* @param string $type billing or shipping
*/
public function set_address( $address, $type = 'billing' ) {
foreach( $address as $key => $value ) {
update_post_meta( $this->id, "_{$type}_" . $key, $value );
}
}
/**
* Add a product line item to the order
* @param WC_Product $item
* @param int $qty Line item quantity
* @param array args
* @return int|bool Item ID or false
*/
public function add_product( $product, $qty = 1, $args = array() ) {
$default_args = array(
'variation' => array(),
'totals' => array()
);
$args = wp_parse_args( $args, $default_args );
$item_id = wc_add_order_item( $this->id, array(
'order_item_name' => $product->get_title(),
'order_item_type' => 'line_item'
) );
if ( ! $item_id ) {
return false;
}
wc_add_order_item_meta( $item_id, '_qty', wc_stock_amount( $qty ) );
wc_add_order_item_meta( $item_id, '_tax_class', $product->get_tax_class() );
wc_add_order_item_meta( $item_id, '_product_id', $product->id );
wc_add_order_item_meta( $item_id, '_variation_id', isset( $product->variation_id ) ? $product->variation_id : 0 );
// Set line item totals, either passed in or from the product
wc_add_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( isset( $args['totals']['subtotal'] ) ? $args['totals']['subtotal'] : $product->get_price_excluding_tax( $qty ) ) );
wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( isset( $args['totals']['total'] ) ? $args['totals']['total'] : $product->get_price_excluding_tax( $qty ) ) );
wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( isset( $args['totals']['subtotal_tax'] ) ? $args['totals']['subtotal_tax'] : 0 ) );
wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( isset( $args['totals']['tax'] ) ? $args['totals']['tax'] : 0 ) );
// Add variation meta
foreach ( $args['variation'] as $key => $value ) {
wc_add_order_item_meta( $item_id, str_replace( 'attribute_', '', $key ), $value );
}
// Backorders
if ( $product->backorders_require_notification() && $product->is_on_backorder( $qty ) ) {
wc_add_order_item_meta( $item_id, apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ) ), $qty - max( 0, $product->get_total_stock() ) );
}
do_action( 'woocommerce_order_add_product', $this->id, $item_id, $product, $qty, $args );
return $item_id;
}
/**
* Add coupon code to the order
* @param string $code
* @param float $discount_amount
* @return int|bool Item ID or false
*/
public function add_coupon( $code, $discount_amount = 0 ) {
$item_id = wc_add_order_item( $this->id, array(
'order_item_name' => $code,
'order_item_type' => 'coupon'
) );
if ( ! $item_id ) {
return false;
}
wc_add_order_item_meta( $item_id, 'discount_amount', $discount_amount );
do_action( 'woocommerce_order_add_coupon', $this->id, $item_id, $code, $discount_amount );
return $item_id;
}
/**
* Add a tax row to the order
* @param int tax_rate_id
* @return int|bool Item ID or false
*/
public function add_tax( $tax_rate_id, $tax_amount = 0, $shipping_tax_amount = 0 ) {
$code = WC_Tax::get_rate_code( $tax_rate_id );
if ( ! $code ) {
return false;
}
$item_id = wc_add_order_item( $this->id, array(
'order_item_name' => $code,
'order_item_type' => 'tax'
) );
if ( ! $item_id ) {
return false;
}
wc_add_order_item_meta( $item_id, 'rate_id', $tax_rate_id );
wc_add_order_item_meta( $item_id, 'label', WC_Tax::get_rate_label( $tax_rate_id ) );
wc_add_order_item_meta( $item_id, 'compound', WC_Tax::is_compound( $tax_rate_id ) ? 1 : 0 );
wc_add_order_item_meta( $item_id, 'tax_amount', wc_format_decimal( $tax_amount ) );
wc_add_order_item_meta( $item_id, 'shipping_tax_amount', wc_format_decimal( $shipping_tax_amount ) );
do_action( 'woocommerce_order_add_tax', $this->id, $item_id, $tax_rate_id, $tax_amount, $shipping_tax_amount );
return $item_id;
}
/**
* Add a shipping row to the order
* @param WC_Shipping_Rate shipping_rate
* @return int|bool Item ID or false
*/
public function add_shipping( $shipping_rate ) {
$item_id = wc_add_order_item( $this->id, array(
'order_item_name' => $shipping_rate->label,
'order_item_type' => 'shipping'
) );
if ( ! $item_id ) {
return false;
}
wc_add_order_item_meta( $item_id, 'method_id', $shipping_rate->id );
wc_add_order_item_meta( $item_id, 'cost', wc_format_decimal( $shipping_rate->cost ) );
do_action( 'woocommerce_order_add_shipping', $this->id, $item_id, $shipping_rate );
// Update total
$this->set_total( $this->order_shipping + wc_format_decimal( $shipping_rate->cost ), 'shipping' );
return $item_id;
}
/**
* Add a fee to the order
* @param object $fee
* @return int|bool Item ID or false
*/
public function add_fee( $fee ) {
$item_id = wc_add_order_item( $this->id, array(
'order_item_name' => $fee->name,
'order_item_type' => 'fee'
) );
if ( ! $item_id ) {
return false;
}
if ( $fee->taxable ) {
wc_add_order_item_meta( $item_id, '_tax_class', $fee->tax_class );
} else {
wc_add_order_item_meta( $item_id, '_tax_class', '0' );
}
wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $fee->amount ) );
wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $fee->tax ) );
do_action( 'woocommerce_order_add_fee', $this->id, $item_id, $fee );
return $item_id;
}
/**
* Set an order total
* @param float $amount
* @param string $total_type
*/
public function set_total( $amount, $total_type = 'total' ) {
if ( ! in_array( $total_type, array( 'shipping', 'order_discount', 'tax', 'shipping_tax', 'total', 'cart_discount' ) ) ) {
return false;
}
switch ( $total_type ) {
case 'total' :
$key = '_order_total';
$amount = wc_format_decimal( $amount, get_option( 'woocommerce_price_num_decimals' ) );
break;
case 'order_discount' :
case 'cart_discount' :
$key = '_' . $total_type;
$amount = wc_format_decimal( $amount );
break;
default :
$key = '_order_' . $total_type;
$amount = wc_format_decimal( $amount );
break;
}
update_post_meta( $this->id, $key, $amount );
}
/**
* Calculate taxes for all line items and shipping, and store the totals and tax rows.
*
* Will use the base country unless customer addresses are set.
*
* @return bool success or fail
*/
public function calculate_taxes() {
$shipping_tax_total = 0;
$tax_total = 0;
$taxes = array();
$tax_based_on = get_option( 'woocommerce_tax_based_on' );
if ( 'base' === $tax_based_on ) {
$default = get_option( 'woocommerce_default_country' );
$postcode = '';
$city = '';
if ( strstr( $default, ':' ) ) {
list( $country, $state ) = explode( ':', $default );
} else {
$country = $default;
$state = '';
}
} elseif ( 'billing' === $tax_based_on ) {
$country = $this->billing_country;
$state = $this->billing_state;
$postcode = $this->billing_postcode;
$city = $this->billing_city;
} else {
$country = $this->shipping_country;
$state = $this->shipping_state;
$postcode = $this->shipping_postcode;
$city = $this->shipping_city;
}
// Get items
foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) {
$product = $this->get_product_from_item( $item );
$line_total = isset( $item['line_total'] ) ? $item['line_total'] : 0;
$line_subtotal = isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0;
$tax_class = $item['tax_class'];
$item_tax_status = $product ? $product->get_tax_status() : 'taxable';
if ( '0' !== $tax_class && 'taxable' === $item_tax_status ) {
$tax_rates = WC_Tax::find_rates( array(
'country' => $country,
'state' => $state,
'postcode' => $postcode,
'city' => $city,
'tax_class' => $tax_class
) );
$line_subtotal_taxes = WC_Tax::calc_tax( $line_subtotal, $tax_rates, false );
$line_taxes = WC_Tax::calc_tax( $line_total, $tax_rates, false );
$line_subtotal_tax = max( 0, array_sum( $line_subtotal_taxes ) );
$line_tax = max( 0, array_sum( $line_taxes ) );
$tax_total += $line_tax;
wc_update_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( $line_subtotal_tax ) );
wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $line_tax ) );
// Sum the item taxes
foreach ( array_keys( $taxes + $line_taxes ) as $key ) {
$taxes[ $key ] = ( isset( $line_taxes[ $key ] ) ? $line_taxes[ $key ] : 0 ) + ( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 );
}
}
}
// Now calculate shipping tax
$matched_tax_rates = array();
$tax_rates = WC_Tax::find_rates( array(
'country' => $country,
'state' => $state,
'postcode' => $postcode,
'city' => $city,
'tax_class' => ''
) );
if ( $tax_rates ) {
foreach ( $tax_rates as $key => $rate ) {
if ( isset( $rate['shipping'] ) && 'yes' === $rate['shipping'] ) {
$matched_tax_rates[ $key ] = $rate;
}
}
}
$shipping_taxes = WC_Tax::calc_shipping_tax( $this->order_shipping, $matched_tax_rates );
$shipping_tax_total = WC_Tax::round( array_sum( $shipping_taxes ) );
// Save tax totals
$this->set_total( $shipping_tax_total, 'shipping_tax' );
$this->set_total( $tax_total, 'tax' );
// Tax rows
$this->remove_order_items( 'tax' );
// Now merge to keep tax rows
foreach ( array_keys( $taxes + $shipping_taxes ) as $tax_rate_id ) {
$this->add_tax( $tax_rate_id, isset( $taxes[ $tax_rate_id ] ) ? $taxes[ $tax_rate_id ] : 0, isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] : 0 );
}
return true;
}
/**
* Calculate totals by looking at the contents of the order. Stores the totals and returns the orders final total.
*
* @return $total calculated grand total
*/
public function calculate_totals() {
$cart_subtotal = 0;
$cart_total = 0;
$fee_total = 0;
$this->calculate_taxes();
foreach ( $this->get_items() as $item ) {
$cart_subtotal += wc_format_decimal( isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0 );
$cart_total += wc_format_decimal( isset( $item['line_total'] ) ? $item['line_total'] : 0 );
}
foreach ( $this->get_fees() as $item ) {
$fee_total += $item['line_total'];
}
$grand_total = round( $cart_total + $fee_total + $this->get_total_shipping() - $this->get_order_discount() + $this->get_cart_tax() + $this->get_shipping_tax(), absint( get_option( 'woocommerce_price_num_decimals' ) ) );
$this->set_total( $cart_subtotal - $cart_total, 'cart_discount' );
$this->set_total( $grand_total, 'total' );
return $grand_total;
}
/**
* Gets an order from the database.
@ -71,7 +425,6 @@ abstract class WC_Abstract_Order {
return false;
}
/**
* Populates an order from the loaded post data.
*
@ -178,7 +531,6 @@ abstract class WC_Abstract_Order {
if ( $key == $this->order_key ) {
return true;
}
return false;
}
@ -278,7 +630,6 @@ abstract class WC_Abstract_Order {
return $this->formatted_shipping_address;
}
/**
* Get the shipping address in an array.
*
@ -606,7 +957,7 @@ abstract class WC_Abstract_Order {
*/
public function get_item_subtotal( $item, $inc_tax = false, $round = true ) {
if ( $inc_tax ) {
$price = ( $item['line_subtotal'] + $item['line_subtotal_tax'] ) / $item['qty'];
$price = ( $item['line_subtotal'] + $item['line_subtotal_tax'] ) / max( 1, $item['qty'] );
} else {
$price = ( $item['line_subtotal'] / $item['qty'] );
}
@ -648,7 +999,7 @@ abstract class WC_Abstract_Order {
*/
public function get_item_total( $item, $inc_tax = false, $round = true ) {
if ( $inc_tax ) {
$price = ( $item['line_total'] + $item['line_tax'] ) / $item['qty'];
$price = ( $item['line_total'] + $item['line_tax'] ) / max( 1, $item['qty'] );
} else {
$price = $item['line_total'] / $item['qty'];
}
@ -680,7 +1031,7 @@ abstract class WC_Abstract_Order {
* @return float
*/
public function get_item_tax( $item, $round = true ) {
$price = $item['line_tax'] / $item['qty'];
$price = $item['line_tax'] / max( 1, $item['qty'] );
$price = $round ? wc_round_tax_total( $price ) : $price;
return apply_filters( 'woocommerce_order_amount_item_tax', $price, $item, $round, $this );
}
@ -948,8 +1299,11 @@ abstract class WC_Abstract_Order {
* @return WC_Product
*/
public function get_product_from_item( $item ) {
$_product = get_product( $item['variation_id'] ? $item['variation_id'] : $item['product_id'] );
if ( ! empty( $item['variation_id'] ) && 'product_variation' === get_post_type( $item['variation_id'] ) ) {
$_product = get_product( $item['variation_id'] );
} else {
$_product = get_product( $item['product_id'] );
}
return apply_filters( 'woocommerce_get_product_from_item', $_product, $item, $this );
}
@ -990,7 +1344,7 @@ abstract class WC_Abstract_Order {
if ( $fees = $this->get_fees() )
foreach( $fees as $id => $fee ) {
if ( $fee['line_total'] + $fee['line_tax'] == 0 ) {
if ( apply_filters( 'woocommerce_get_order_item_totals_excl_free_fees', $fee['line_total'] + $fee['line_tax'] == 0, $id ) ) {
continue;
}
@ -1370,6 +1724,9 @@ abstract class WC_Abstract_Order {
// Record the completed date of the order
update_post_meta( $this->id, '_completed_date', current_time('mysql') );
// Update reports
wc_delete_shop_order_transients( $this->id );
break;
case 'processing' :
case 'on-hold' :
@ -1378,15 +1735,19 @@ abstract class WC_Abstract_Order {
// Increase coupon usage counts
$this->increase_coupon_usage_counts();
// Update reports
wc_delete_shop_order_transients( $this->id );
break;
case 'cancelled' :
// If the order is cancelled, restore used coupons
$this->decrease_coupon_usage_counts();
// Update reports
wc_delete_shop_order_transients( $this->id );
break;
}
}
wc_delete_shop_order_transients( $this->id );
}
@ -1628,10 +1989,8 @@ abstract class WC_Abstract_Order {
$this->add_order_note( __( 'Order item stock reduced successfully.', 'woocommerce' ) );
}
}
/**
* send_stock_notifications function.
*
@ -1731,7 +2090,5 @@ abstract class WC_Abstract_Order {
break;
}
}
return apply_filters( 'woocommerce_order_needs_shipping_address', $needs, $this, $hide );
}
}

View File

@ -17,41 +17,44 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
abstract class WC_Payment_Gateway extends WC_Settings_API {
/** @var string Payment method ID. */
var $id;
public $id;
/** @var string Set if the place order button should be renamed on selection. */
var $order_button_text;
public $order_button_text;
/** @var string Payment method title. */
var $title;
public $title;
/** @var string Chosen payment method id. */
var $chosen;
public $chosen;
/** @var bool True if the gateway shows fields on the checkout. */
var $has_fields;
public $has_fields;
/** @var array Array of countries this gateway is allowed for. */
var $countries;
public $countries;
/** @var string Available for all counties or specific. */
var $availability;
public $availability;
/** @var string 'yes' if the method is enabled. */
var $enabled;
public $enabled;
/** @var string Icon for the gateway. */
var $icon;
public $icon;
/** @var string Description for the gateway. */
var $description;
public $description;
/** @var array Array of supported features such as 'default_credit_card_form' */
var $supports = array( 'products' );
public $supports = array( 'products' );
/** @var int Maximum transaction amount, zero does not define a maximum */
public $max_amount = 0;
/** @var string Optional URL to view a transaction */
public $view_transaction_url = '';
/**
* Get the return url (thank you page)
*
@ -73,6 +76,19 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
return apply_filters( 'woocommerce_get_return_url', $return_url );
}
/**
* Get a link to the transaction on the 3rd party gateway size (if applicable)
* @param string $transaction_id
* @return string
*/
public function get_transaction_url( $transaction_id ) {
$return_url = '';
if ( ! empty( $this->view_transaction_url ) && ! empty( $transaction_id ) ) {
$return_url = sprintf( $this->view_transaction_url, $transaction_id );
}
return apply_filters( 'woocommerce_get_transaction_url', $return_url, $transaction_id, $this );
}
/**
* Get the order total in checkout and pay_for_order.
*

View File

@ -106,9 +106,10 @@ class WC_Product {
if ( ! isset( $this->product_image_gallery ) ) {
// Backwards compat
$attachment_ids = get_posts( 'post_parent=' . $this->id . '&numberposts=-1&post_type=attachment&orderby=menu_order&order=ASC&post_mime_type=image&fields=ids&meta_key=_woocommerce_exclude_image&meta_value=0' );
$attachment_ids = array_diff( $attachment_ids, array( get_post_thumbnail_id() ) );
$attachment_ids = array_diff( $attachment_ids, array( get_post_thumbnail_id( $this->id ) ) );
$this->product_image_gallery = implode( ',', $attachment_ids );
}
return apply_filters( 'woocommerce_product_gallery_attachment_ids', array_filter( (array) explode( ',', $this->product_image_gallery ) ), $this );
}
@ -126,7 +127,7 @@ class WC_Product {
* @return string
*/
public function get_sku() {
return $this->sku;
return apply_filters( 'woocommerce_get_sku', $this->sku, $this );
}
/**
@ -136,7 +137,7 @@ class WC_Product {
* @return int
*/
public function get_stock_quantity() {
return $this->managing_stock() ? apply_filters( 'woocommerce_stock_amount', $this->stock ) : '';
return $this->managing_stock() ? wc_stock_amount( $this->stock ) : '';
}
/**
@ -152,7 +153,7 @@ class WC_Product {
/**
* Check if the stock status needs changing
*/
private function check_stock_status() {
protected function check_stock_status() {
// Update stock status
if ( ! $this->backorders_allowed() && $this->get_total_stock() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
$this->set_stock_status( 'outofstock' );
@ -165,7 +166,7 @@ class WC_Product {
/**
* Set stock level of the product.
*
* Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues).
* Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues).
* We cannot rely on the original loaded value in case another order was made since then.
*
* @param int $amount (default: null)
@ -193,9 +194,6 @@ class WC_Product {
// Clear caches
wp_cache_delete( $this->id, 'post_meta' );
// Clear total stock transient
delete_transient( 'wc_product_total_stock_' . $this->id );
// Stock status
$this->check_stock_status();
@ -207,7 +205,7 @@ class WC_Product {
}
/**
* Reduce stock level of the product.
* Reduce stock level of the product.
*
* @param int $amount (default: 1) Amount to reduce by.
* @return int new stock level
@ -223,7 +221,7 @@ class WC_Product {
* @return int new stock level
*/
public function increase_stock( $amount = 1 ) {
return $this->set_stock( $amount, 'add' );
return $this->set_stock( $amount, 'add' );
}
/**
@ -235,6 +233,13 @@ class WC_Product {
public function set_stock_status( $status ) {
$status = ( 'outofstock' === $status ) ? 'outofstock' : 'instock';
// Sanity check
if ( $this->managing_stock() ) {
if ( ! $this->backorders_allowed() && $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
$status = 'outofstock';
}
}
if ( update_post_meta( $this->id, '_stock_status', $status ) ) {
do_action( 'woocommerce_product_set_stock_status', $this->id, $status );
}
@ -452,7 +457,7 @@ class WC_Product {
* @return int
*/
public function get_parent() {
return apply_filters('woocommerce_product_parent', $this->post->post_parent, $this);
return apply_filters( 'woocommerce_product_parent', absint( $this->post->post_parent ), $this );
}
/**
@ -502,30 +507,12 @@ class WC_Product {
* @return bool
*/
public function is_in_stock() {
if ( $this->managing_stock() ) {
if ( $this->backorders_allowed() ) {
return true;
} else {
if ( $this->get_total_stock() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
return false;
} else {
if ( $this->stock_status === 'instock' ) {
return true;
} else {
return false;
}
}
}
if ( $this->managing_stock() && $this->backorders_allowed() ) {
return true;
} elseif ( $this->managing_stock() && $this->get_total_stock() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
return false;
} else {
if ( $this->stock_status === 'instock' ) {
return true;
} else {
return false;
}
return $this->stock_status === 'instock';
}
}
@ -578,50 +565,39 @@ class WC_Product {
* @return string
*/
public function get_availability() {
$availability = $class = "";
if ( $this->managing_stock() ) {
if ( $this->is_in_stock() ) {
if ( $this->get_total_stock() > get_option( 'woocommerce_notify_no_stock_amount' ) ) {
$format_option = get_option( 'woocommerce_stock_format' );
switch ( $format_option ) {
switch ( get_option( 'woocommerce_stock_format' ) ) {
case 'no_amount' :
$format = __( 'In stock', 'woocommerce' );
$availability = __( 'In stock', 'woocommerce' );
break;
case 'low_amount' :
$low_amount = get_option( 'woocommerce_notify_low_stock_amount' );
$format = ( $this->get_total_stock() <= $low_amount ) ? __( 'Only %s left in stock', 'woocommerce' ) : __( 'In stock', 'woocommerce' );
$low_amount = get_option( 'woocommerce_notify_low_stock_amount' );
$availability = $this->get_total_stock() <= $low_amount ? sprintf( __( 'Only %s left in stock', 'woocommerce' ), $this->get_total_stock() ) : __( 'In stock', 'woocommerce' );
break;
default :
$format = __( '%s in stock', 'woocommerce' );
$availability = sprintf( __( '%s in stock', 'woocommerce' ), $this->get_total_stock() );
break;
}
$availability = sprintf( $format, $this->stock );
if ( $this->backorders_allowed() && $this->backorders_require_notification() ) {
$availability .= ' ' . __( '(backorders allowed)', 'woocommerce' );
}
} else {
if ( $this->backorders_allowed() ) {
if ( $this->backorders_require_notification() ) {
$availability = __( 'Available on backorder', 'woocommerce' );
$class = 'available-on-backorder';
} else {
$availability = __( 'In stock', 'woocommerce' );
}
} elseif ( $this->backorders_allowed() ) {
if ( $this->backorders_require_notification() ) {
$availability = __( 'Available on backorder', 'woocommerce' );
$class = 'available-on-backorder';
} else {
$availability = __( 'Out of stock', 'woocommerce' );
$class = 'out-of-stock';
$availability = __( 'In stock', 'woocommerce' );
}
} else {
$availability = __( 'Out of stock', 'woocommerce' );
$class = 'out-of-stock';
}
} elseif ( $this->backorders_allowed() ) {
@ -786,8 +762,6 @@ class WC_Product {
* @return string
*/
public function get_price_including_tax( $qty = 1, $price = '' ) {
$_tax = new WC_Tax();
if ( ! $price ) {
$price = $this->get_price();
}
@ -796,26 +770,26 @@ class WC_Product {
if ( get_option('woocommerce_prices_include_tax') === 'no' ) {
$tax_rates = $_tax->get_rates( $this->get_tax_class() );
$taxes = $_tax->calc_tax( $price * $qty, $tax_rates, false );
$tax_amount = $_tax->get_tax_total( $taxes );
$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, absint( get_option( 'woocommerce_price_num_decimals' ) ) );
} else {
$tax_rates = $_tax->get_rates( $this->get_tax_class() );
$base_tax_rates = $_tax->get_shop_base_rate( $this->tax_class );
$tax_rates = WC_Tax::get_rates( $this->get_tax_class() );
$base_tax_rates = WC_Tax::get_shop_base_rate( $this->tax_class );
if ( ! empty( WC()->customer ) && WC()->customer->is_vat_exempt() ) {
$base_taxes = $_tax->calc_tax( $price * $qty, $base_tax_rates, true );
$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, 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 );
$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 ), absint( get_option( 'woocommerce_price_num_decimals' ) ) );
} else {
@ -848,12 +822,9 @@ class WC_Product {
}
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 * $qty, $tax_rates, true );
$price = $_tax->round( $price * $qty - array_sum( $taxes ) );
$tax_rates = WC_Tax::get_shop_base_rate( $this->tax_class );
$taxes = WC_Tax::calc_tax( $price * $qty, $tax_rates, true );
$price = WC_Tax::round( $price * $qty - array_sum( $taxes ) );
} else {
$price = $price * $qty;
}
@ -1222,8 +1193,8 @@ class WC_Product {
// when query is OR - need to check against excluded ids again
if ( apply_filters( 'woocommerce_product_related_posts_relate_by_tag', true, $this->id ) ) {
$query['where'] .= " {$andor} ( tt.taxonomy = 'product_tag' AND t.term_id IN ( " . implode( ',', $tags_array ) . " ) )";
$query['where'] .= " AND p.ID NOT IN ( " . implode( ',', $exclude_ids ) . " )";
$query['where'] .= " {$andor} ( ( tt.taxonomy = 'product_tag' AND t.term_id IN ( " . implode( ',', $tags_array ) . " ) )";
$query['where'] .= " AND p.ID NOT IN ( " . implode( ',', $exclude_ids ) . " ) )";
}
$query['orderby'] = " ORDER BY RAND()";

View File

@ -95,7 +95,6 @@ abstract class WC_Shipping_Method extends WC_Settings_API {
// This saves shipping methods having to do complex tax calculations
if ( ! is_array( $taxes ) && $taxes !== false && $total_cost > 0 && $this->is_taxable() ) {
$_tax = new WC_Tax();
$taxes = array();
switch ( $calc_tax ) {
@ -114,8 +113,8 @@ abstract class WC_Shipping_Method extends WC_Settings_API {
$_product = $cart[ $cost_key ]['data'];
$rates = $_tax->get_shipping_tax_rates( $_product->get_tax_class() );
$item_taxes = $_tax->calc_shipping_tax( $amount, $rates );
$rates = WC_Tax::get_shipping_tax_rates( $_product->get_tax_class() );
$item_taxes = WC_Tax::calc_shipping_tax( $amount, $rates );
// Sum the item taxes
foreach ( array_keys( $taxes + $item_taxes ) as $key )
@ -126,8 +125,8 @@ abstract class WC_Shipping_Method extends WC_Settings_API {
// Add any cost for the order - order costs are in the key 'order'
if ( isset( $cost['order'] ) ) {
$rates = $_tax->get_shipping_tax_rates();
$item_taxes = $_tax->calc_shipping_tax( $cost['order'], $rates );
$rates = WC_Tax::get_shipping_tax_rates();
$item_taxes = WC_Tax::calc_shipping_tax( $cost['order'], $rates );
// Sum the item taxes
foreach ( array_keys( $taxes + $item_taxes ) as $key )
@ -140,8 +139,8 @@ abstract class WC_Shipping_Method extends WC_Settings_API {
default :
$rates = $_tax->get_shipping_tax_rates();
$taxes = $_tax->calc_shipping_tax( $total_cost, $rates );
$rates = WC_Tax::get_shipping_tax_rates();
$taxes = WC_Tax::calc_shipping_tax( $total_cost, $rates );
break;

View File

@ -57,7 +57,7 @@ class WC_Admin_Notices {
if ( in_array( 'theme_support', $notices ) && ! current_theme_supports( 'woocommerce' ) ) {
$template = get_option( 'template' );
if ( ! in_array( $template, array( 'twentyfourteen', 'twentythirteen', 'twentyeleven', 'twentytwelve', 'twentyten' ) ) ) {
if ( ! in_array( $template, wc_get_core_supported_themes() ) ) {
wp_enqueue_style( 'woocommerce-activation', plugins_url( '/assets/css/activation.css', WC_PLUGIN_FILE ) );
add_action( 'admin_notices', array( $this, 'theme_check_notice' ) );
}
@ -130,8 +130,8 @@ class WC_Admin_Notices {
}
if ( $theme_file ) {
$core_version = $status->get_file_version( WC()->plugin_path() . '/templates/' . $file );
$theme_version = $status->get_file_version( $theme_file );
$core_version = WC_Admin_Status::get_file_version( WC()->plugin_path() . '/templates/' . $file );
$theme_version = WC_Admin_Status::get_file_version( $theme_file );
if ( $core_version && $theme_version && version_compare( $theme_version, $core_version, '<' ) ) {
$outdated = true;

View File

@ -30,7 +30,7 @@ class WC_Admin_Post_Types {
add_filter( 'manage_edit-product_columns', array( $this, 'product_columns' ) );
add_filter( 'manage_edit-shop_coupon_columns', array( $this, 'shop_coupon_columns' ) );
add_filter( 'manage_edit-shop_order_columns', array( $this, 'shop_order_columns' ) );
add_action( 'manage_product_posts_custom_column', array( $this, 'render_product_columns' ), 2 );
add_action( 'manage_shop_coupon_posts_custom_column', array( $this, 'render_shop_coupon_columns' ), 2 );
add_action( 'manage_shop_order_posts_custom_column', array( $this, 'render_shop_order_columns' ), 2 );
@ -51,7 +51,7 @@ class WC_Admin_Post_Types {
add_action( 'load-edit.php', array( $this, 'bulk_action' ) );
add_action( 'admin_notices', array( $this, 'bulk_admin_notices' ) );
// Order Search
// Order Search
add_filter( 'get_search_query', array( $this, 'shop_order_search_label' ) );
add_filter( 'query_vars', array( $this, 'add_custom_query_var' ) );
add_action( 'parse_query', array( $this, 'shop_order_search_custom_fields' ) );
@ -472,7 +472,7 @@ class WC_Admin_Post_Types {
break;
case 'order_items' :
printf( '<a href="#" class="show_order_items">' . _n( '%d item', '%d items', sizeof( $the_order->get_items() ), 'woocommerce' ) . '</a>', sizeof( $the_order->get_items() ) );
echo '<a href="#" class="show_order_items">' . apply_filters( 'woocommerce_admin_order_item_count', sprintf( _n( '%d item', '%d items', $the_order->get_item_count(), 'woocommerce' ), $the_order->get_item_count() ), $the_order ) . '</a>';
if ( sizeof( $the_order->get_items() ) > 0 ) {
@ -483,7 +483,7 @@ class WC_Admin_Post_Types {
$item_meta = new WC_Order_Item_Meta( $item['item_meta'] );
$item_meta_html = $item_meta->display( true, true );
?>
<tr>
<tr class="<?php echo apply_filters( 'woocommerce_admin_order_item_class', '', $item ); ?>">
<td class="qty"><?php echo absint( $item['qty'] ); ?></td>
<td class="name">
<?php if ( wc_product_sku_enabled() && $_product && $_product->get_sku() ) echo $_product->get_sku() . ' - '; ?><?php echo apply_filters( 'woocommerce_order_item_name', $item['name'], $item ); ?>
@ -676,7 +676,7 @@ class WC_Admin_Post_Types {
unset( $columns['comments'] );
return wp_parse_args( $custom, $columns );
}
}
/**
* Remove edit from the bulk actions.
@ -817,16 +817,8 @@ class WC_Admin_Post_Types {
if ( $new_sku !== $sku ) {
if ( ! empty( $new_sku ) ) {
$sku_exists = $wpdb->get_var( $wpdb->prepare("
SELECT $wpdb->posts.ID
FROM $wpdb->posts
LEFT JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id)
WHERE $wpdb->posts.post_type = 'product'
AND $wpdb->posts.post_status = 'publish'
AND $wpdb->postmeta.meta_key = '_sku' AND $wpdb->postmeta.meta_value = '%s'
", $new_sku ) );
if ( ! $sku_exists ) {
$unique_sku = wc_product_has_unique_sku( $post_id, $new_sku );
if ( $unique_sku ) {
update_post_meta( $post_id, '_sku', $new_sku );
}
} else {
@ -852,13 +844,15 @@ class WC_Admin_Post_Types {
}
if ( isset( $_REQUEST['_visibility'] ) ) {
update_post_meta( $post_id, '_visibility', wc_clean( $_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 ( isset( $_REQUEST['_featured'] ) ) {
update_post_meta( $post_id, '_featured', 'yes' );
} else {
update_post_meta( $post_id, '_featured', 'no' );
if ( update_post_meta( $post_id, '_featured', isset( $_REQUEST['_featured'] ) ? 'yes' : 'no' ) ) {
delete_transient( 'wc_featured_products' );
}
}
if ( isset( $_REQUEST['_tax_status'] ) ) {
@ -914,7 +908,7 @@ class WC_Admin_Post_Types {
if ( ! $product->is_type('grouped') ) {
if ( isset( $_REQUEST['_manage_stock'] ) ) {
update_post_meta( $post_id, '_manage_stock', 'yes' );
wc_update_product_stock( $post_id, intval( $_REQUEST['_stock'] ) );
wc_update_product_stock( $post_id, wc_stock_amount( $_REQUEST['_stock'] ) );
} else {
update_post_meta( $post_id, '_manage_stock', 'no' );
wc_update_product_stock( $post_id, 0 );
@ -970,11 +964,15 @@ class WC_Admin_Post_Types {
}
if ( ! empty( $_REQUEST['_visibility'] ) ) {
update_post_meta( $post_id, '_visibility', stripslashes( $_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'] ) ) {
update_post_meta( $post_id, '_featured', stripslashes( $_REQUEST['_featured'] ) );
if ( update_post_meta( $post_id, '_featured', stripslashes( $_REQUEST['_featured'] ) ) ) {
delete_transient( 'wc_featured_products' );
}
}
// Sold Individually
@ -1098,7 +1096,7 @@ class WC_Admin_Post_Types {
if ( ! empty( $_REQUEST['change_stock'] ) ) {
update_post_meta( $post_id, '_manage_stock', 'yes' );
wc_update_product_stock( $post_id, intval( $_REQUEST['_stock'] ) );
wc_update_product_stock( $post_id, wc_stock_amount( $_REQUEST['_stock'] ) );
}
if ( ! empty( $_REQUEST['_manage_stock'] ) ) {
@ -1762,7 +1760,6 @@ class WC_Admin_Post_Types {
}
delete_transient( 'woocommerce_processing_order_count' );
delete_transient( 'wc_term_counts' );
}
}
@ -1791,7 +1788,6 @@ class WC_Admin_Post_Types {
}
delete_transient( 'woocommerce_processing_order_count' );
delete_transient( 'wc_term_counts' );
}
}
@ -2044,9 +2040,9 @@ class WC_Admin_Post_Types {
}
}
}
}
}
}
endif;
new WC_Admin_Post_Types();
new WC_Admin_Post_Types();

View File

@ -59,7 +59,6 @@ class WC_Admin_Settings {
do_action( 'woocommerce_update_options' );
// Clear any unwanted data
wc_delete_product_transients();
delete_transient( 'woocommerce_cache_excluded_uris' );
self::add_message( __( 'Your settings have been saved.', 'woocommerce' ) );
@ -598,46 +597,41 @@ class WC_Admin_Settings {
* @return bool
*/
public static function save_fields( $options ) {
if ( empty( $_POST ) )
if ( empty( $_POST ) ) {
return false;
}
// Options to update will be stored here
$update_options = array();
// Loop options and get values to save
foreach ( $options as $value ) {
if ( ! isset( $value['id'] ) )
if ( ! isset( $value['id'] ) || ! isset( $value['type'] ) ) {
continue;
}
$type = isset( $value['type'] ) ? sanitize_title( $value['type'] ) : '';
// Get posted value
if ( strstr( $value['id'], '[' ) ) {
parse_str( $value['id'], $option_name_array );
// Get the option name
$option_value = null;
$option_name = current( array_keys( $option_name_array ) );
$setting_name = key( $option_name_array[ $option_name ] );
switch ( $type ) {
$option_value = isset( $_POST[ $option_name ][ $setting_name ] ) ? stripslashes_deep( $_POST[ $option_name ][ $setting_name ] ) : null;
} else {
$option_name = $value['id'];
$setting_name = '';
$option_value = isset( $_POST[ $value['id'] ] ) ? stripslashes_deep( $_POST[ $value['id'] ] ) : null;
}
// Standard types
// Format value
switch ( sanitize_title( $value['type'] ) ) {
case "checkbox" :
if ( isset( $_POST[ $value['id'] ] ) ) {
$option_value = 'yes';
} else {
$option_value = 'no';
}
$option_value = is_null( $option_value ) ? 'no' : 'yes';
break;
case "textarea" :
if ( isset( $_POST[$value['id']] ) ) {
$option_value = wp_kses_post( trim( stripslashes( $_POST[ $value['id'] ] ) ) );
} else {
$option_value = '';
}
$option_value = wp_kses_post( trim( $option_value ) );
break;
case "text" :
case 'email':
case 'number':
@ -647,119 +641,63 @@ class WC_Admin_Settings {
case "single_select_page" :
case "single_select_country" :
case 'radio' :
if ( $value['id'] == 'woocommerce_price_thousand_sep' || $value['id'] == 'woocommerce_price_decimal_sep' ) {
// price separators get a special treatment as they should allow a spaces (don't trim)
if ( isset( $_POST[ $value['id'] ] ) ) {
$option_value = wp_kses_post( stripslashes( $_POST[ $value['id'] ] ) );
} else {
$option_value = '';
}
if ( in_array( $value['id'], array( 'woocommerce_price_thousand_sep', 'woocommerce_price_decimal_sep' ) ) ) {
$option_value = wp_kses_post( $option_value );
} elseif ( $value['id'] == 'woocommerce_price_num_decimals' ) {
// price separators get a special treatment as they should allow a spaces (don't trim)
if ( isset( $_POST[ $value['id'] ] ) ) {
$option_value = absint( $_POST[ $value['id'] ] );
} else {
$option_value = 2;
}
$option_value = is_null( $option_value ) ? 2 : absint( $option_value );
} elseif ( $value['id'] == 'woocommerce_hold_stock_minutes' ) {
// Allow > 0 or set to ''
if ( ! empty( $_POST[ $value['id'] ] ) ) {
$option_value = absint( $_POST[ $value['id'] ] );
} else {
$option_value = '';
}
$option_value = ! empty( $option_value ) ? absint( $option_value ) : ''; // Allow > 0 or set to ''
wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' );
if ( $option_value != '' )
if ( $option_value !== '' ) {
wp_schedule_single_event( time() + ( absint( $option_value ) * 60 ), 'woocommerce_cancel_unpaid_orders' );
} else {
if ( isset( $_POST[$value['id']] ) ) {
$option_value = wc_clean( stripslashes( $_POST[ $value['id'] ] ) );
} else {
$option_value = '';
}
} else {
$option_value = wc_clean( $option_value );
}
break;
// Special types
case "multiselect" :
case "multi_select_countries" :
// Get countries array
if ( isset( $_POST[ $value['id'] ] ) )
$selected_countries = array_map( 'wc_clean', array_map( 'stripslashes', (array) $_POST[ $value['id'] ] ) );
else
$selected_countries = array();
$option_value = $selected_countries;
$option_value = array_filter( array_map( 'wc_clean', (array) $option_value ) );
break;
case "image_width" :
if ( isset( $_POST[$value['id'] ]['width'] ) ) {
$update_options[ $value['id'] ]['width'] = wc_clean( stripslashes( $_POST[ $value['id'] ]['width'] ) );
$update_options[ $value['id'] ]['height'] = wc_clean( stripslashes( $_POST[ $value['id'] ]['height'] ) );
if ( isset( $_POST[ $value['id'] ]['crop'] ) )
$update_options[ $value['id'] ]['crop'] = 1;
else
$update_options[ $value['id'] ]['crop'] = 0;
if ( isset( $option_value['width'] ) ) {
$update_options[ $value['id'] ]['width'] = wc_clean( $option_value['width'] );
$update_options[ $value['id'] ]['height'] = wc_clean( $option_value['height'] );
$update_options[ $value['id'] ]['crop'] = isset( $option_value['crop'] ) ? 1 : 0;
} else {
$update_options[ $value['id'] ]['width'] = $value['default']['width'];
$update_options[ $value['id'] ]['height'] = $value['default']['height'];
$update_options[ $value['id'] ]['crop'] = $value['default']['crop'];
$update_options[ $value['id'] ]['width'] = $value['default']['width'];
$update_options[ $value['id'] ]['height'] = $value['default']['height'];
$update_options[ $value['id'] ]['crop'] = $value['default']['crop'];
}
break;
// Custom handling
default :
do_action( 'woocommerce_update_option_' . $type, $value );
do_action( 'woocommerce_update_option_' . sanitize_title( $value['type'] ), $value );
break;
}
if ( ! is_null( $option_value ) ) {
// Check if option is an array
if ( strstr( $value['id'], '[' ) ) {
parse_str( $value['id'], $option_array );
// Option name is first key
$option_name = current( array_keys( $option_array ) );
if ( $option_name && $setting_name ) {
// Get old option value
if ( ! isset( $update_options[ $option_name ] ) )
$update_options[ $option_name ] = get_option( $option_name, array() );
if ( ! isset( $update_options[ $option_name ] ) ) {
$update_options[ $option_name ] = get_option( $option_name, array() );
}
if ( ! is_array( $update_options[ $option_name ] ) )
if ( ! is_array( $update_options[ $option_name ] ) ) {
$update_options[ $option_name ] = array();
}
// Set keys and value
$key = key( $option_array[ $option_name ] );
$update_options[ $option_name ][ $key ] = $option_value;
// Single value
} else {
$update_options[ $value['id'] ] = $option_value;
}
$update_options[ $option_name ][ $setting_name ] = $option_value;
// Single value
} else {
$update_options[ $option_name ] = $option_value;
}
}
// Custom handling
@ -767,8 +705,9 @@ class WC_Admin_Settings {
}
// Now save the options
foreach( $update_options as $name => $value )
foreach( $update_options as $name => $value ) {
update_option( $name, $value );
}
return true;
}

View File

@ -107,8 +107,6 @@ class WC_Admin_Status {
_wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), true, false );
delete_transient( 'wc_term_counts' );
echo '<div class="updated"><p>' . __( 'Terms successfully recounted', 'woocommerce' ) . '</p></div>';
break;
case 'clear_sessions' :

View File

@ -254,13 +254,13 @@ class WC_Admin_Taxonomies {
* @return void
*/
public function save_category_fields( $term_id, $tt_id, $taxonomy ) {
if ( isset( $_POST['display_type'] ) )
if ( isset( $_POST['display_type'] ) ) {
update_woocommerce_term_meta( $term_id, 'display_type', esc_attr( $_POST['display_type'] ) );
}
if ( isset( $_POST['product_cat_thumbnail_id'] ) )
if ( isset( $_POST['product_cat_thumbnail_id'] ) ) {
update_woocommerce_term_meta( $term_id, 'thumbnail_id', absint( $_POST['product_cat_thumbnail_id'] ) );
delete_transient( 'wc_term_counts' );
}
}
/**

View File

@ -6,7 +6,7 @@ if ( ! defined( 'ABSPATH' ) ) {
/**
* WooCommerce Admin.
*
* @class WC_Admin
* @class WC_Admin
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin
@ -102,8 +102,9 @@ class WC_Admin {
*/
public function preview_emails() {
if ( isset( $_GET['preview_woocommerce_mail'] ) ) {
if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'preview-mail') )
if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'preview-mail') ) {
die( 'Security check' );
}
global $email_heading;
@ -121,4 +122,4 @@ class WC_Admin {
}
}
return new WC_Admin();
return new WC_Admin();

View File

@ -140,6 +140,12 @@ class WC_Meta_Box_Order_Data {
self::init_address_fields();
if ( WC()->payment_gateways() ) {
$payment_gateways = WC()->payment_gateways->payment_gateways();
}
$payment_method = ! empty( $order->payment_method ) ? $order->payment_method : '';
wp_nonce_field( 'woocommerce_save_data', 'woocommerce_meta_nonce' );
?>
<style type="text/css">
@ -150,13 +156,24 @@ class WC_Meta_Box_Order_Data {
<input name="post_status" type="hidden" value="publish" />
<div id="order_data" class="panel">
<h2><?php _e( 'Order Details', 'woocommerce' ); ?></h2>
<h2><?php printf( __( 'Order %s details', 'woocommerce' ), esc_html( $order->get_order_number() ) ); ?></h2>
<p class="order_number"><?php
echo __( 'Order number', 'woocommerce' ) . ' ' . esc_html( $order->get_order_number() ) . '. ';
if ( $payment_method ) {
printf( __( 'Payment via %s', 'woocommerce' ), ( isset( $payment_gateways[ $payment_method ] ) ? esc_html( $payment_gateways[ $payment_method ]->get_title() ) : esc_html( $payment_method ) ) );
if ( $transaction_id = get_post_meta( $order->id, '_transaction_id', true ) ) {
if ( isset( $payment_gateways[ $payment_method ] ) && ( $url = $payment_gateways[ $payment_method ]->get_transaction_url( $transaction_id ) ) ) {
echo ' (<a href="' . esc_url( $url ) . '" target="_blank">' . esc_html( $transaction_id ) . '</a>)';
} else {
echo ' (' . esc_html( $transaction_id ) . ')';
}
}
echo '. ';
}
if ( $ip_address = get_post_meta( $post->ID, '_customer_ip_address', true ) ) {
echo __( 'Customer IP:', 'woocommerce' ) . ' ' . esc_html( $ip_address );
echo __( 'Customer IP', 'woocommerce' ) . ': ' . esc_html( $ip_address );
}
?></p>
@ -217,20 +234,6 @@ class WC_Meta_Box_Order_Data {
}
}
if ( WC()->payment_gateways() ) {
$payment_gateways = WC()->payment_gateways->payment_gateways();
}
$payment_method = ! empty( $order->payment_method ) ? $order->payment_method : '';
if ( $payment_method ) {
echo '<p><strong>' . __( 'Payment Method', 'woocommerce' ) . ':</strong> ' . ( isset( $payment_gateways[ $payment_method ] ) ? esc_html( $payment_gateways[ $payment_method ]->get_title() ) : esc_html( $payment_method ) ) . '</p>';
}
if ( $transaction_id = get_post_meta( $order->id, '_transaction_id', true ) ) {
echo '<p><strong>' . __( 'Payment Transaction ID', 'woocommerce' ) . ':</strong> ' . esc_html( $transaction_id ) . '</p>';
}
echo '</div>';
// Display form
@ -278,6 +281,8 @@ class WC_Meta_Box_Order_Data {
</p>
<?php
woocommerce_wp_text_input( array( 'id' => '_transaction_id', 'label' => __( 'Transaction ID', 'woocommerce' ) ) );
echo '</div>';
do_action( 'woocommerce_admin_order_data_after_billing_address', $order );
@ -405,6 +410,10 @@ class WC_Meta_Box_Order_Data {
}
}
if ( isset( $_POST['_transaction_id'] ) ) {
update_post_meta( $post_id, '_transaction_id', wc_clean( $_POST[ '_transaction_id' ] ) );
}
// Payment method handling
if ( get_post_meta( $post_id, '_payment_method', true ) !== stripslashes( $_POST['_payment_method'] ) ) {

View File

@ -132,7 +132,7 @@ class WC_Meta_Box_Order_Items {
);
if ( isset( $order_item_qty[ $item_id ] ) )
wc_update_order_item_meta( $item_id, '_qty', apply_filters( 'woocommerce_stock_amount', $order_item_qty[ $item_id ] ) );
wc_update_order_item_meta( $item_id, '_qty', wc_stock_amount( $order_item_qty[ $item_id ] ) );
if ( isset( $order_item_tax_class[ $item_id ] ) )
wc_update_order_item_meta( $item_id, '_tax_class', wc_clean( $order_item_tax_class[ $item_id ] ) );

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
?>
<tr class="item <?php echo ( ! empty( $class ) ) ? $class : ''; ?>" data-order_item_id="<?php echo $item_id; ?>">
<tr class="item <?php echo apply_filters( 'woocommerce_admin_html_order_item_class', ( ! empty( $class ) ? $class : '' ), $item ); ?>" data-order_item_id="<?php echo $item_id; ?>">
<td class="check-column"><input type="checkbox" /></td>
<td class="thumb">
<?php if ( $_product ) : ?>
@ -12,8 +12,10 @@ if ( ! defined( 'ABSPATH' ) ) {
echo '<strong>' . __( 'Product ID:', 'woocommerce' ) . '</strong> ' . absint( $item['product_id'] );
if ( $item['variation_id'] ) {
if ( $item['variation_id'] && 'product_variation' === get_post_type( $item['variation_id'] ) ) {
echo '<br/><strong>' . __( 'Variation ID:', 'woocommerce' ) . '</strong> ' . absint( $item['variation_id'] );
} elseif ( $item['variation_id'] ) {
echo '<br/><strong>' . __( 'Variation ID:', 'woocommerce' ) . '</strong> ' . absint( $item['variation_id'] ) . ' (' . __( 'No longer exists', 'woocommerce' ) . ')';
}
if ( $_product && $_product->get_sku() ) {

View File

@ -58,24 +58,6 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
</td>
<td class="data" rowspan="2">
<table cellspacing="0" cellpadding="0" class="data_table">
<?php if ( get_option( 'woocommerce_manage_stock' ) == 'yes' ) : ?>
<tr>
<td>
<label><?php _e( 'Stock Qty:', 'woocommerce' ); ?> <a class="tips" data-tip="<?php _e( 'Enter a quantity to enable stock management at variation level, or leave blank to use the parent product\'s options.', 'woocommerce' ); ?>" href="#">[?]</a></label>
<input type="number" size="5" name="variable_stock[<?php echo $loop; ?>]" value="<?php if ( isset( $_stock ) ) echo esc_attr( $_stock ); ?>" step="any" />
</td>
<td>
<label><?php _e( 'Allow Backorders?', 'woocommerce' ); ?></label>
<select name="variable_backorders[<?php echo $loop; ?>]">
<option value="parent" <?php selected( is_null( $_backorders ), true ); ?>><?php _e( 'Same as parent', 'woocommerce' ); ?></option>
<?php
foreach ( $parent_data['backorder_options'] as $key => $value )
echo '<option value="' . esc_attr( $key ) . '" ' . selected( $key === $_backorders, true, false ) . '>' . esc_html( $value ) . '</option>';
?></select>
</td>
</tr>
<?php endif; ?>
<tr class="variable_pricing">
<td>
<label><?php echo __( 'Regular Price:', 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')'; ?></label>
@ -98,6 +80,36 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
</td>
</tr>
<?php if ( get_option( 'woocommerce_manage_stock' ) == 'yes' ) : ?>
<tr class="show_if_variation_manage_stock">
<td>
<label><?php _e( 'Stock Qty:', 'woocommerce' ); ?> <a class="tips" data-tip="<?php _e( 'Enter a quantity to enable stock management at variation level, or leave blank to use the parent product\'s options.', 'woocommerce' ); ?>" href="#">[?]</a></label>
<input type="number" size="5" name="variable_stock[<?php echo $loop; ?>]" value="<?php if ( isset( $_stock ) ) echo esc_attr( $_stock ); ?>" step="any" />
</td>
<td>
<label><?php _e( 'Allow Backorders?', 'woocommerce' ); ?></label>
<select name="variable_backorders[<?php echo $loop; ?>]">
<option value="parent" <?php selected( is_null( $_backorders ), true ); ?>><?php _e( 'Same as parent', 'woocommerce' ); ?></option>
<?php
foreach ( $parent_data['backorder_options'] as $key => $value )
echo '<option value="' . esc_attr( $key ) . '" ' . selected( $key === $_backorders, true, false ) . '>' . esc_html( $value ) . '</option>';
?></select>
</td>
</tr>
<tr class="">
<td colspan="2">
<label><?php _e( 'Stock status', 'woocommerce' ); ?> <a class="tips" data-tip="<?php esc_attr_e( 'Controls whether or not the product is listed as "in stock" or "out of stock" on the frontend.', 'woocommerce' ); ?>" href="#">[?]</a></label>
<select name="variable_stock_status[<?php echo $loop; ?>]">
<?php
foreach ( $parent_data['stock_status_options'] as $key => $value ) {
echo '<option value="' . esc_attr( $key === $_stock_status ? '' : $key ) . '" ' . selected( $key === $_stock_status, true, false ) . '>' . esc_html( $value ) . '</option>';
}
?>
</select>
</td>
</tr>
<?php endif; ?>
<?php if ( wc_product_weight_enabled() || wc_product_dimensions_enabled() ) : ?>
<tr>
<?php if ( wc_product_weight_enabled() ) : ?>
@ -221,6 +233,12 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
<label><input type="checkbox" class="checkbox variable_is_virtual" name="variable_is_virtual[<?php echo $loop; ?>]" <?php checked( isset( $_virtual ) ? $_virtual : '', 'yes' ); ?> /> <?php _e( 'Virtual', 'woocommerce' ); ?> <a class="tips" data-tip="<?php _e( 'Enable this option if a product is not shipped or there is no shipping cost', 'woocommerce' ); ?>" href="#">[?]</a></label>
<?php if ( get_option( 'woocommerce_manage_stock' ) == 'yes' ) : ?>
<label><input type="checkbox" class="checkbox variable_manage_stock" name="variable_manage_stock[<?php echo $loop; ?>]" <?php checked( isset( $_manage_stock ) ? $_manage_stock : '', 'yes' ); ?> /> <?php _e( 'Manage stock?', 'woocommerce' ); ?> <a class="tips" data-tip="<?php _e( 'Enable this option to enable stock management at variation level', 'woocommerce' ); ?>" href="#">[?]</a></label>
<?php endif; ?>
<?php do_action( 'woocommerce_variation_options', $loop, $variation_data, $variation ); ?>
</td>
</tr>

View File

@ -115,8 +115,8 @@ class WC_Report_Taxes_By_Date extends WC_Admin_Report {
</tr>
</thead>
<?php if ( $tax_rows ) :
$gross = array_sum( wp_list_pluck( (array) $tax_rows, 'total_sales' ) ) - array_sum( wp_list_pluck( (array) $tax_rows, 'total_shipping' ) );
$total_tax = array_sum( wp_list_pluck( (array) $tax_rows, 'tax_amount' ) ) - array_sum( wp_list_pluck( (array) $tax_rows, 'shipping_tax_amount' ) );
$gross = array_sum( wp_list_pluck( (array) $tax_rows, 'total_sales' ) ) - array_sum( wp_list_pluck( (array) $tax_rows, 'total_shipping' ) );
$total_tax = array_sum( wp_list_pluck( (array) $tax_rows, 'tax_amount' ) ) + array_sum( wp_list_pluck( (array) $tax_rows, 'shipping_tax_amount' ) );
?>
<tfoot>
<tr>

View File

@ -1,7 +1,7 @@
<?php if ( $logs ) : ?>
<div id="log-viewer-select">
<div class="alignleft">
<h3><?php printf( __( 'Viewing %s (%s)', 'woocommerce' ), esc_html( $viewed_log ), date_i18n( get_option( 'date_format') . ' ' . get_option( 'time_format'), filemtime( WC_LOG_DIR . $viewed_log ) ) ); ?></h3>
<h3><?php printf( __( 'Log file: %s (%s)', 'woocommerce' ), esc_html( $viewed_log ), date_i18n( get_option( 'date_format') . ' ' . get_option( 'time_format'), filemtime( WC_LOG_DIR . $viewed_log ) ) ); ?></h3>
</div>
<div class="alignright">
<form action="<?php echo admin_url( 'admin.php?page=wc-status&tab=logs' ); ?>" method="post">

View File

@ -382,15 +382,15 @@
</tr>
</thead>
<?php
$active_theme = wp_get_theme();
if ( $active_theme->{'Author URI'} == 'http://www.woothemes.com' ) :
<?php
$active_theme = wp_get_theme();
if ( $active_theme->{'Author URI'} == 'http://www.woothemes.com' ) :
$theme_dir = substr( strtolower( str_replace( ' ','', $active_theme->Name ) ), 0, 45 );
if ( false === ( $theme_version_data = get_transient( $theme_dir . '_version_data' ) ) ) :
$theme_changelog = wp_remote_get( 'http://dzv365zjfbd8v.cloudfront.net/changelogs/' . $theme_dir . '/changelog.txt' );
$theme_changelog = wp_remote_get( 'http://dzv365zjfbd8v.cloudfront.net/changelogs/' . $theme_dir . '/changelog.txt' );
$cl_lines = explode( "\n", wp_remote_retrieve_body( $theme_changelog ) );
if ( ! empty( $cl_lines ) ) :
@ -414,27 +414,37 @@
endif;
?>
<tbody>
<tr>
<td><?php _e( 'Theme Name', 'woocommerce' ); ?>:</td>
<td><?php
<tr>
<td><?php _e( 'Theme Name', 'woocommerce' ); ?>:</td>
<td><?php
echo $active_theme->Name;
?></td>
</tr>
<tr>
<td><?php _e( 'Theme Version', 'woocommerce' ); ?>:</td>
<td><?php
?></td>
</tr>
<tr>
<td><?php _e( 'Theme Version', 'woocommerce' ); ?>:</td>
<td><?php
echo $active_theme->Version;
if ( ! empty( $theme_version_data['version'] ) && version_compare( $theme_version_data['version'], $active_theme->Version, '!=' ) )
echo ' &ndash; <strong style="color:red;">' . $theme_version_data['version'] . ' ' . __( 'is available', 'woocommerce' ) . '</strong>';
?></td>
</tr>
<tr>
<td><?php _e( 'Author URL', 'woocommerce' ); ?>:</td>
<td><?php
?></td>
</tr>
<tr>
<td><?php _e( 'Author URL', 'woocommerce' ); ?>:</td>
<td><?php
echo $active_theme->{'Author URI'};
?></td>
</tr>
?></td>
</tr>
<tr>
<td><?php _e( 'WooCommerce Support', 'woocommerce' ); ?>:</td>
<td><?php
if ( ! current_theme_supports( 'woocommerce' ) && ! in_array( $active_theme->template, wc_get_core_supported_themes() ) ) {
echo '<mark class="error">' . __( 'Not Declared', 'woocommerce' ) . '</mark>';
} else {
echo '<mark class="yes">' . __( 'Yes', 'woocommerce' ) . '</mark>';
}
?></td>
</tr>
</tbody>
<thead>
@ -444,59 +454,61 @@
</thead>
<tbody>
<tr>
<?php
<?php
$template_paths = apply_filters( 'woocommerce_template_overrides_scan_paths', array( 'WooCommerce' => WC()->plugin_path() . '/templates/' ) );
$scanned_files = array();
$found_files = array();
$template_paths = apply_filters( 'woocommerce_template_overrides_scan_paths', array( 'WooCommerce' => WC()->plugin_path() . '/templates/' ) );
$scanned_files = array();
$found_files = array();
foreach ( $template_paths as $plugin_name => $template_path ) {
$scanned_files[ $plugin_name ] = WC_Admin_Status::scan_template_files( $template_path );
}
foreach ( $template_paths as $plugin_name => $template_path ) {
$scanned_files[ $plugin_name ] = WC_Admin_Status::scan_template_files( $template_path );
}
foreach ( $scanned_files as $plugin_name => $files ) {
foreach ( $files as $file ) {
if ( file_exists( get_stylesheet_directory() . '/' . $file ) ) {
$theme_file = get_stylesheet_directory() . '/' . $file;
} elseif ( file_exists( get_stylesheet_directory() . '/woocommerce/' . $file ) ) {
$theme_file = get_stylesheet_directory() . '/woocommerce/' . $file;
} elseif ( file_exists( get_template_directory() . '/' . $file ) ) {
$theme_file = get_template_directory() . '/' . $file;
} elseif( file_exists( get_template_directory() . '/woocommerce/' . $file ) ) {
$theme_file = get_template_directory() . '/woocommerce/' . $file;
foreach ( $scanned_files as $plugin_name => $files ) {
foreach ( $files as $file ) {
if ( file_exists( get_stylesheet_directory() . '/' . $file ) ) {
$theme_file = get_stylesheet_directory() . '/' . $file;
} elseif ( file_exists( get_stylesheet_directory() . '/woocommerce/' . $file ) ) {
$theme_file = get_stylesheet_directory() . '/woocommerce/' . $file;
} elseif ( file_exists( get_template_directory() . '/' . $file ) ) {
$theme_file = get_template_directory() . '/' . $file;
} elseif( file_exists( get_template_directory() . '/woocommerce/' . $file ) ) {
$theme_file = get_template_directory() . '/woocommerce/' . $file;
} else {
$theme_file = false;
}
if ( $theme_file ) {
$core_version = WC_Admin_Status::get_file_version( WC()->plugin_path() . '/templates/' . $file );
$theme_version = WC_Admin_Status::get_file_version( $theme_file );
if ( $core_version && ( empty( $theme_version ) || version_compare( $theme_version, $core_version, '<' ) ) ) {
$found_files[ $plugin_name ][] = sprintf( __( '<code>%s</code> version <strong style="color:red">%s</strong> is out of date. The core version is %s', 'woocommerce' ), basename( $theme_file ), $theme_version ? $theme_version : '-', $core_version );
} else {
$theme_file = false;
}
if ( $theme_file ) {
$core_version = WC_Admin_Status::get_file_version( WC()->plugin_path() . '/templates/' . $file );
$theme_version = WC_Admin_Status::get_file_version( $theme_file );
if ( $core_version && ( empty( $theme_version ) || version_compare( $theme_version, $core_version, '<' ) ) ) {
$found_files[ $plugin_name ][] = sprintf( __( '<code>%s</code> version <strong style="color:red">%s</strong> is out of date. The core version is %s', 'woocommerce' ), basename( $theme_file ), $theme_version ? $theme_version : '-', $core_version );
} else {
$found_files[ $plugin_name ][] = sprintf( '<code>%s</code>', basename( $theme_file ) );
}
$found_files[ $plugin_name ][] = sprintf( '<code>%s</code>', basename( $theme_file ) );
}
}
}
}
if ( $found_files ) {
foreach ( $found_files as $plugin_name => $found_plugin_files ) {
?>
if ( $found_files ) {
foreach ( $found_files as $plugin_name => $found_plugin_files ) {
?>
<tr>
<td><?php _e( 'Template Overrides', 'woocommerce' ); ?> (<?php echo $plugin_name; ?>):</td>
<td><?php echo implode( ', <br/>', $found_plugin_files ); ?></td>
<?php
}
} else {
?>
<td><?php _e( 'Template Overrides', 'woocommerce' ); ?>:</td>
<td><?php _e( 'No overrides present in theme.', 'woocommerce' ); ?></td>
</tr>
<?php
}
?>
</tr>
} else {
?>
<tr>
<td><?php _e( 'Template Overrides', 'woocommerce' ); ?>:</td>
<td><?php _e( 'No overrides present in theme.', 'woocommerce' ); ?></td>
</tr>
<?php
}
?>
</tbody>
</table>

File diff suppressed because it is too large Load Diff

View File

@ -71,21 +71,11 @@ class WC_AJAX {
add_action( 'wp_ajax_page_slurp', array( 'WC_Gateway_Mijireh', 'page_slurp' ) );
}
/**
* Output headers for JSON requests
*/
private static function json_headers() {
header( 'Content-Type: application/json; charset=utf-8' );
}
/**
* Get a refreshed cart fragment
*/
public static function get_refreshed_fragments() {
self::json_headers();
// Get mini cart
ob_start();
@ -102,9 +92,8 @@ class WC_AJAX {
'cart_hash' => WC()->cart->get_cart() ? md5( json_encode( WC()->cart->get_cart() ) ) : ''
);
echo json_encode( $data );
wp_send_json( $data );
die();
}
/**
@ -270,7 +259,7 @@ class WC_AJAX {
*/
public static function add_to_cart() {
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) );
$quantity = empty( $_POST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_POST['quantity'] );
$quantity = empty( $_POST['quantity'] ) ? 1 : wc_stock_amount( $_POST['quantity'] );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity ) ) {
@ -286,15 +275,14 @@ class WC_AJAX {
} else {
self::json_headers();
// If there was an error adding to the cart, redirect to the product page to show any errors
$data = array(
'error' => true,
'product_url' => apply_filters( 'woocommerce_cart_redirect_after_error', get_permalink( $product_id ), $product_id )
);
echo json_encode( $data );
wp_send_json( $data );
}
die();
@ -339,7 +327,7 @@ class WC_AJAX {
update_post_meta( $post_id, '_featured', 'yes' );
}
wc_delete_product_transients();
delete_transient( 'wc_featured_products' );
wp_safe_redirect( remove_query_arg( array( 'trashed', 'untrashed', 'deleted', 'ids' ), wp_get_referer() ) );
@ -403,8 +391,6 @@ class WC_AJAX {
check_ajax_referer( 'add-attribute', 'security' );
self::json_headers();
$taxonomy = esc_attr( $_POST['taxonomy'] );
$term = stripslashes( $_POST['term'] );
@ -413,15 +399,15 @@ class WC_AJAX {
$result = wp_insert_term( $term, $taxonomy );
if ( is_wp_error( $result ) ) {
echo json_encode( array(
wp_send_json( array(
'error' => $result->get_error_message()
));
) );
} else {
echo json_encode( array(
wp_send_json( array(
'term_id' => $result['term_id'],
'name' => $term,
'slug' => sanitize_title( $term ),
));
) );
}
}
@ -693,7 +679,7 @@ class WC_AJAX {
$attribute_field_name = 'attribute_' . sanitize_title( $attribute['name'] );
if ( $attribute['is_taxonomy'] ) {
$options = wc_get_product_terms( $post_id, $attribute['name'], array( 'fields' => 'slugs' ) );
$options = wc_get_product_terms( $post_id, $attribute['name'], array( 'fields' => 'names' ) );
} else {
$options = explode( WC_DELIMITER, $attribute['value'] );
}
@ -819,7 +805,7 @@ class WC_AJAX {
}
}
wc_delete_product_transients( $post_id );
delete_transient( 'wc_product_children_ids_' . $post_id );
echo $added;
@ -906,8 +892,6 @@ class WC_AJAX {
check_ajax_referer( 'get-customer-details', 'security' );
self::json_headers();
$user_id = (int) trim(stripslashes($_POST['user_id']));
$type_to_load = esc_attr(trim(stripslashes($_POST['type_to_load'])));
@ -927,10 +911,8 @@ class WC_AJAX {
$customer_data = apply_filters( 'woocommerce_found_customer_details', $customer_data );
echo json_encode( $customer_data );
wp_send_json( $customer_data );
// Quit out
die();
}
/**
@ -1183,9 +1165,8 @@ class WC_AJAX {
check_ajax_referer( 'calc-totals', 'security' );
self::json_headers();
$tax = new WC_Tax();
$taxes = $tax_rows = $item_taxes = $shipping_taxes = array();
$order_id = absint( $_POST['order_id'] );
$order = get_order( $order_id );
@ -1200,17 +1181,12 @@ class WC_AJAX {
// Calculate sales tax first
if ( sizeof( $items ) > 0 ) {
foreach( $items as $item_id => $item ) {
$item_id = absint( $item_id );
$line_subtotal = isset( $item['line_subtotal'] ) ? wc_format_decimal( $item['line_subtotal'] ) : 0;
$line_total = wc_format_decimal( $item['line_total'] );
$tax_class = sanitize_text_field( $item['tax_class'] );
$product_id = $order->get_item_meta( $item_id, '_product_id', true );
if ( ! $item_id || '0' == $tax_class ) {
continue;
}
// Get product details
if ( get_post_type( $product_id ) == 'product' ) {
$_product = get_product( $product_id );
@ -1219,10 +1195,8 @@ class WC_AJAX {
$item_tax_status = 'taxable';
}
// Only calc if taxable
if ( 'taxable' == $item_tax_status ) {
$tax_rates = $tax->find_rates( array(
if ( '0' !== $tax_class && 'taxable' === $item_tax_status ) {
$tax_rates = WC_Tax::find_rates( array(
'country' => $country,
'state' => $state,
'postcode' => $postcode,
@ -1230,18 +1204,10 @@ class WC_AJAX {
'tax_class' => $tax_class
) );
$line_subtotal_taxes = $tax->calc_tax( $line_subtotal, $tax_rates, false );
$line_taxes = $tax->calc_tax( $line_total, $tax_rates, false );
$line_subtotal_tax = array_sum( $line_subtotal_taxes );
$line_tax = array_sum( $line_taxes );
if ( $line_subtotal_tax < 0 ) {
$line_subtotal_tax = 0;
}
if ( $line_tax < 0 ) {
$line_tax = 0;
}
$line_subtotal_taxes = WC_Tax::calc_tax( $line_subtotal, $tax_rates, false );
$line_taxes = WC_Tax::calc_tax( $line_total, $tax_rates, false );
$line_subtotal_tax = max( 0, array_sum( $line_subtotal_taxes ) );
$line_tax = max( 0, array_sum( $line_taxes ) );
$item_taxes[ $item_id ] = array(
'line_subtotal_tax' => wc_format_localized_price( $line_subtotal_tax ),
@ -1255,14 +1221,13 @@ class WC_AJAX {
$taxes[ $key ] = ( isset( $line_taxes[ $key ] ) ? $line_taxes[ $key ] : 0 ) + ( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 );
}
}
}
}
// Now calculate shipping tax
$matched_tax_rates = array();
$tax_rates = $tax->find_rates( array(
$tax_rates = WC_Tax::find_rates( array(
'country' => $country,
'state' => $state,
'postcode' => $postcode,
@ -1278,77 +1243,32 @@ class WC_AJAX {
}
}
$shipping_taxes = $tax->calc_shipping_tax( $shipping, $matched_tax_rates );
$shipping_tax = $tax->round( array_sum( $shipping_taxes ) );
$shipping_taxes = WC_Tax::calc_shipping_tax( $shipping, $matched_tax_rates );
$shipping_tax = WC_Tax::round( array_sum( $shipping_taxes ) );
// Remove old tax rows
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = 'tax' )", $order_id ) );
$order->remove_order_items( 'tax' );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = 'tax'", $order_id ) );
// Get tax rates
$rates = $wpdb->get_results( "SELECT tax_rate_id, tax_rate_country, tax_rate_state, tax_rate_name, tax_rate_priority FROM {$wpdb->prefix}woocommerce_tax_rates ORDER BY tax_rate_name" );
$tax_codes = array();
foreach( $rates as $rate ) {
$code = array();
$code[] = $rate->tax_rate_country;
$code[] = $rate->tax_rate_state;
$code[] = $rate->tax_rate_name ? sanitize_title( $rate->tax_rate_name ) : 'TAX';
$code[] = absint( $rate->tax_rate_priority );
$tax_codes[ $rate->tax_rate_id ] = strtoupper( implode( '-', array_filter( $code ) ) );
// Add tax rows
foreach ( array_keys( $taxes + $shipping_taxes ) as $tax_rate_id ) {
$order->add_tax( $tax_rate_id, isset( $taxes[ $tax_rate_id ] ) ? $taxes[ $tax_rate_id ] : 0, isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] : 0 );
}
// Now merge to keep tax rows
ob_start();
foreach ( array_keys( $taxes + $shipping_taxes ) as $key ) {
$item = array();
$item['rate_id'] = $key;
$item['name'] = $tax_codes[ $key ];
$item['label'] = $tax->get_rate_label( $key );
$item['compound'] = $tax->is_compound( $key ) ? 1 : 0;
$item['tax_amount'] = wc_format_decimal( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 );
$item['shipping_tax_amount'] = wc_format_decimal( isset( $shipping_taxes[ $key ] ) ? $shipping_taxes[ $key ] : 0 );
if ( ! $item['label'] ) {
$item['label'] = WC()->countries->tax_or_vat();
}
// Add line item
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $item['name'],
'order_item_type' => 'tax'
) );
// Add line item meta
if ( $item_id ) {
wc_add_order_item_meta( $item_id, 'rate_id', $item['rate_id'] );
wc_add_order_item_meta( $item_id, 'label', $item['label'] );
wc_add_order_item_meta( $item_id, 'compound', $item['compound'] );
wc_add_order_item_meta( $item_id, 'tax_amount', $item['tax_amount'] );
wc_add_order_item_meta( $item_id, 'shipping_tax_amount', $item['shipping_tax_amount'] );
}
foreach ( $order->get_taxes() as $item_id => $item ) {
include( 'admin/meta-boxes/views/html-order-tax.php' );
}
$tax_row_html = ob_get_clean();
// Return
echo json_encode( array(
wp_send_json( array(
'item_tax' => $item_tax,
'item_taxes' => $item_taxes,
'shipping_tax' => $shipping_tax,
'tax_row_html' => $tax_row_html
) );
// Quit out
die();
}
/**
@ -1409,8 +1329,6 @@ class WC_AJAX {
check_ajax_referer( 'search-products', 'security' );
self::json_headers();
$term = (string) wc_clean( stripslashes( $_GET['term'] ) );
if ( empty( $term ) ) {
@ -1491,9 +1409,8 @@ class WC_AJAX {
$found_products = apply_filters( 'woocommerce_json_search_found_products', $found_products );
echo json_encode( $found_products );
wp_send_json( $found_products );
die();
}
/**
@ -1514,8 +1431,6 @@ class WC_AJAX {
check_ajax_referer( 'search-customers', 'security' );
self::json_headers();
$term = wc_clean( stripslashes( $_GET['term'] ) );
if ( empty( $term ) ) {
@ -1545,8 +1460,8 @@ class WC_AJAX {
}
}
echo json_encode( $found_customers );
die();
wp_send_json( $found_customers );
}
/**
@ -1584,8 +1499,8 @@ class WC_AJAX {
}
}
echo json_encode( $found_products );
die();
wp_send_json( $found_products );
}
/**
@ -1643,8 +1558,6 @@ class WC_AJAX {
die(-1);
}
self::json_headers();
$previd = isset( $_POST['previd'] ) ? $_POST['previd'] : false;
$nextid = isset( $_POST['nextid'] ) ? $_POST['nextid'] : false;
$new_pos = array(); // store new positions for ajax
@ -1710,7 +1623,8 @@ class WC_AJAX {
}
die( json_encode( $new_pos ) );
wp_send_json( $new_pos );
}
}

View File

@ -114,6 +114,7 @@ class WC_Cart {
);
add_action( 'init', array( $this, 'init' ), 5 ); // Get cart on init
add_action( 'wp', array( $this, 'maybe_set_cart_cookies' ), 99 ); // Set cookies
}
/**
@ -130,6 +131,35 @@ class WC_Cart {
add_action( 'woocommerce_after_checkout_validation', array( $this, 'check_customer_coupons' ), 1 );
}
/**
* Will set cart cookies if needed, once, during WP hook
*/
public function maybe_set_cart_cookies() {
if ( sizeof( $this->cart_contents ) > 0 ) {
$this->set_cart_cookies( true );
} elseif ( isset( $_COOKIE['woocommerce_items_in_cart'] ) ) {
$this->set_cart_cookies( false );
}
}
/**
* Set cart hash cookie and items in cart.
*
* @access private
* @param bool $set (default: true)
* @return void
*/
private function set_cart_cookies( $set = true ) {
if ( $set ) {
wc_setcookie( 'woocommerce_items_in_cart', 1 );
wc_setcookie( 'woocommerce_cart_hash', md5( json_encode( $this->get_cart() ) ) );
} elseif ( isset( $_COOKIE['woocommerce_items_in_cart'] ) ) {
wc_setcookie( 'woocommerce_items_in_cart', 0, time() - 3600 );
wc_setcookie( 'woocommerce_cart_hash', '', time() - 3600 );
}
do_action( 'woocommerce_set_cart_cookies', $set );
}
/*-----------------------------------------------------------------------------------*/
/* Cart Session Handling */
/*-----------------------------------------------------------------------------------*/
@ -187,8 +217,6 @@ class WC_Cart {
WC()->session->cart = $this->get_cart_for_session();
}
$this->set_cart_cookies( sizeof( $this->cart_contents ) > 0 );
// Trigger action
do_action( 'woocommerce_cart_loaded_from_session', $this );
@ -891,9 +919,12 @@ class WC_Cart {
}
if ( did_action( 'wp' ) ) {
$this->set_cart_cookies( sizeof( $this->cart_contents ) > 0 );
}
do_action( 'woocommerce_add_to_cart', $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data );
$this->set_cart_cookies();
$this->calculate_totals();
return true;
@ -920,25 +951,6 @@ class WC_Cart {
}
}
/**
* Set cart hash cookie and items in cart.
*
* @access private
* @param bool $set (default: true)
* @return void
*/
private function set_cart_cookies( $set = true ) {
if ( $set ) {
wc_setcookie( 'woocommerce_items_in_cart', 1 );
wc_setcookie( 'woocommerce_cart_hash', md5( json_encode( $this->get_cart() ) ) );
} elseif ( isset( $_COOKIE['woocommerce_items_in_cart'] ) ) {
wc_setcookie( 'woocommerce_items_in_cart', 0, time() - 3600 );
wc_setcookie( 'woocommerce_cart_hash', '', time() - 3600 );
}
do_action( 'woocommerce_set_cart_cookies', $set );
}
/*-----------------------------------------------------------------------------------*/
/* Cart Calculation Functions */
/*-----------------------------------------------------------------------------------*/
@ -1371,7 +1383,7 @@ class WC_Cart {
$needs_shipping_address = false;
if ( WC()->cart->needs_shipping() === true && ! WC()->cart->ship_to_billing_address_only() ) {
if ( $this->needs_shipping() === true && ! $this->ship_to_billing_address_only() ) {
$needs_shipping_address = true;
}
@ -1661,6 +1673,15 @@ class WC_Cart {
return $this->applied_coupons;
}
/**
* Get the discount amount for a used coupon
* @param string $code coupon code
* @return float discount amount
*/
public function get_coupon_discount_amount( $code ) {
return isset( $this->coupon_discount_amounts[ $code ] ) ? $this->coupon_discount_amounts[ $code ] : 0;
}
/**
* Remove coupons from the cart of a defined type. Type 1 is before tax, type 2 is after tax.
*
@ -2075,6 +2096,24 @@ class WC_Cart {
return apply_filters( 'woocommerce_get_cart_tax', $cart_total_tax ? wc_price( $cart_total_tax ) : '' );
}
/**
* Get a tax amount
* @param string $tax_rate_id
* @return float amount
*/
public function get_tax_amount( $tax_rate_id ) {
return isset( $this->taxes[ $tax_rate_id ] ) ? $this->taxes[ $tax_rate_id ] : 0;
}
/**
* Get a tax amount
* @param string $tax_rate_id
* @return float amount
*/
public function get_shipping_tax_amount( $tax_rate_id ) {
return isset( $this->shipping_taxes[ $tax_rate_id ] ) ? $this->shipping_taxes[ $tax_rate_id ] : 0;
}
/**
* Get tax row amounts with or without compound taxes includes.
*

View File

@ -34,20 +34,19 @@ class WC_Checkout {
private $customer_id;
/**
* @var WooCommerce The single instance of the class
* @var WC_Checkout The single instance of the class
* @since 2.1
*/
protected static $_instance = null;
/**
* Main WooCommerce Instance
* Main WC_Checkout Instance
*
* Ensures only one instance of WooCommerce is loaded or can be loaded.
* Ensures only one instance of WC_Checkout is loaded or can be loaded.
*
* @since 2.1
* @static
* @see WC()
* @return Main WooCommerce instance
* @return WC_Checkout Main instance
*/
public static function instance() {
if ( is_null( self::$_instance ) )
@ -123,7 +122,6 @@ class WC_Checkout {
do_action( 'woocommerce_checkout_init', $this );
}
/**
* Checkout process
*/
@ -132,7 +130,6 @@ class WC_Checkout {
do_action('woocommerce_check_cart_items');
}
/**
* Output the billing information form
*
@ -143,7 +140,6 @@ class WC_Checkout {
wc_get_template( 'checkout/form-billing.php', array( 'checkout' => $this ) );
}
/**
* Output the shipping information form
*
@ -154,242 +150,184 @@ class WC_Checkout {
wc_get_template( 'checkout/form-shipping.php', array( 'checkout' => $this ) );
}
/**
* create_order function.
* @access public
* @throws Exception
* @return int
* @return int|WP_ERROR
*/
public function create_order() {
global $wpdb;
// Give plugins the opportunity to create an order themselves
$order_id = apply_filters( 'woocommerce_create_order', null, $this );
if ( is_numeric( $order_id ) )
if ( $order_id = apply_filters( 'woocommerce_create_order', null, $this ) ) {
return $order_id;
}
// Create Order (send cart variable so we can record items and reduce inventory). Only create if this is a new order, not if the payment was rejected.
$order_data = apply_filters( 'woocommerce_new_order_data', array(
'post_type' => 'shop_order',
'post_title' => sprintf( __( 'Order &ndash; %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) ),
'post_status' => 'wc-' . apply_filters( 'woocommerce_default_order_status', 'pending' ),
'ping_status' => 'closed',
'post_excerpt' => isset( $this->posted['order_comments'] ) ? $this->posted['order_comments'] : '',
'post_author' => 1,
'post_password' => uniqid( 'order_' ) // Protects the post just in case
) );
try {
// Start transaction if available
$wpdb->query( 'START TRANSACTION' );
// Insert or update the post data
$create_new_order = true;
if ( WC()->session->order_awaiting_payment > 0 ) {
$order_data = array(
'status' => apply_filters( 'woocommerce_default_order_status', 'pending' ),
'customer_id' => $this->customer_id,
'customer_note' => isset( $this->posted['order_comments'] ) ? $this->posted['order_comments'] : ''
);
// Insert or update the post data
$order_id = absint( WC()->session->order_awaiting_payment );
// Resume the unpaid order if its pending
if ( ( $existing_order = get_post( $order_id ) ) && $existing_order->has_status( array( 'pending', 'failed' ) ) ) {
if ( $order_id > 0 && ( $order = new WC_Order( $order_id ) ) && $order->has_status( array( 'pending', 'failed' ) ) ) {
// Update the existing order as we are resuming it
$create_new_order = false;
$order_data['ID'] = $order_id;
wp_update_post( $order_data );
$order_data['order_id'] = $order_id;
$order = wc_update_order( $order_data );
// Clear the old line items - we'll add these again in case they changed
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d )", $order_id ) );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $order_id ) );
// Trigger an action for the resumed order
do_action( 'woocommerce_resume_order', $order_id );
}
}
if ( $create_new_order ) {
$order_id = wp_insert_post( $order_data, true );
if ( is_wp_error( $order_id ) )
throw new Exception( 'Error: Unable to create order. Please try again.' );
else
do_action( 'woocommerce_new_order', $order_id );
}
// Store user data
if ( $this->checkout_fields['billing'] )
foreach ( $this->checkout_fields['billing'] as $key => $field ) {
update_post_meta( $order_id, '_' . $key, $this->posted[ $key ] );
if ( $this->customer_id && apply_filters( 'woocommerce_checkout_update_customer_data', true, $this ) )
update_user_meta( $this->customer_id, $key, $this->posted[ $key ] );
}
if ( $this->checkout_fields['shipping'] && WC()->cart->needs_shipping() ) {
foreach ( $this->checkout_fields['shipping'] as $key => $field ) {
$postvalue = false;
if ( $this->posted['ship_to_different_address'] == false ) {
if ( isset( $this->posted[ str_replace( 'shipping_', 'billing_', $key ) ] ) ) {
$postvalue = $this->posted[ str_replace( 'shipping_', 'billing_', $key ) ];
update_post_meta( $order_id, '_' . $key, $postvalue );
}
if ( is_wp_error( $order ) ) {
throw new Exception( __( 'Error: Unable to create order. Please try again.', 'woocommerce' ) );
} else {
$postvalue = $this->posted[ $key ];
update_post_meta( $order_id, '_' . $key, $postvalue );
$order->remove_order_items();
do_action( 'woocommerce_resume_order', $order_id );
}
// User
if ( $postvalue && $this->customer_id && apply_filters( 'woocommerce_checkout_update_customer_data', true, $this ) )
update_user_meta( $this->customer_id, $key, $postvalue );
} else {
$order = wc_create_order( $order_data );
if ( is_wp_error( $order ) ) {
throw new Exception( __( 'Error: Unable to create order. Please try again.', 'woocommerce' ) );
} else {
$order_id = $order->id;
do_action( 'woocommerce_new_order', $order_id );
}
}
}
// Save any other user meta
if ( $this->customer_id )
do_action( 'woocommerce_checkout_update_user_meta', $this->customer_id, $this->posted );
// Store the line items to the new/resumed order
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$item_id = $order->add_product(
$values['data'],
$values['quantity'],
array(
'variation' => $values['variation'],
'totals' => array(
'subtotal' => $values['line_subtotal'],
'subtotal_tax' => $values['line_subtotal_tax'],
'total' => $values['line_total'],
'tax' => $values['line_tax']
)
)
);
// Store the line items to the new/resumed order
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
if ( ! $item_id ) {
throw new Exception( __( 'Error: Unable to create order. Please try again.', 'woocommerce' ) );
}
$_product = $values['data'];
// Allow plugins to add order item meta
do_action( 'woocommerce_add_order_item_meta', $item_id, $values, $cart_item_key );
}
// Add line item
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $_product->get_title(),
'order_item_type' => 'line_item'
) );
// Store fees
foreach ( WC()->cart->get_fees() as $fee_key => $fee ) {
$item_id = $order->add_fee( $fee );
// Add line item meta
if ( $item_id ) {
wc_add_order_item_meta( $item_id, '_qty', apply_filters( 'woocommerce_stock_amount', $values['quantity'] ) );
wc_add_order_item_meta( $item_id, '_tax_class', $_product->get_tax_class() );
wc_add_order_item_meta( $item_id, '_product_id', $values['product_id'] );
wc_add_order_item_meta( $item_id, '_variation_id', $values['variation_id'] );
wc_add_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( $values['line_subtotal'] ) );
wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $values['line_total'] ) );
wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $values['line_tax'] ) );
wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( $values['line_subtotal_tax'] ) );
if ( ! $item_id ) {
throw new Exception( __( 'Error: Unable to create order. Please try again.', 'woocommerce' ) );
}
// Allow plugins to add order item meta to fees
do_action( 'woocommerce_add_order_fee_meta', $order_id, $item_id, $fee, $fee_key );
}
// Store variation data in meta so admin can view it
if ( $values['variation'] && is_array( $values['variation'] ) ) {
foreach ( $values['variation'] as $key => $value ) {
$key = str_replace( 'attribute_', '', $key );
wc_add_order_item_meta( $item_id, $key, $value );
// Store shipping for all packages
foreach ( WC()->shipping->get_packages() as $package_key => $package ) {
if ( isset( $package['rates'][ $this->shipping_methods[ $package_key ] ] ) ) {
$item_id = $order->add_shipping( $package['rates'][ $this->shipping_methods[ $package_key ] ] );
if ( ! $item_id ) {
throw new Exception( __( 'Error: Unable to create order. Please try again.', 'woocommerce' ) );
}
// Allows plugins to add order item meta to shipping
do_action( 'woocommerce_add_shipping_order_item', $order_id, $item_id, $package_key );
}
}
// Store tax rows
foreach ( array_keys( WC()->cart->taxes + WC()->cart->shipping_taxes ) as $tax_rate_id ) {
if ( ! $order->add_tax( $tax_rate_id, WC()->cart->get_tax_amount( $tax_rate_id ), WC()->cart->get_shipping_tax_amount( $tax_rate_id ) ) ) {
throw new Exception( __( 'Error: Unable to create order. Please try again.', 'woocommerce' ) );
}
}
// Store coupons
foreach ( WC()->cart->get_coupons() as $code => $coupon ) {
if ( ! $order->add_coupon( $code, WC()->cart->get_coupon_discount_amount( $code ) ) ) {
throw new Exception( __( 'Error: Unable to create order. Please try again.', 'woocommerce' ) );
}
}
// Billing address
$billing_address = array(
'first_name' => $this->get_posted_address_data( 'first_name' ),
'last_name' => $this->get_posted_address_data( 'last_name' ),
'company' => $this->get_posted_address_data( 'company' ),
'email' => $this->get_posted_address_data( 'email' ),
'phone' => $this->get_posted_address_data( 'phone' ),
'address_1' => $this->get_posted_address_data( 'address_1' ),
'address_2' => $this->get_posted_address_data( 'address_2' ),
'city' => $this->get_posted_address_data( 'city' ),
'state' => $this->get_posted_address_data( 'state' ),
'postcode' => $this->get_posted_address_data( 'postcode' ),
'country' => $this->get_posted_address_data( 'country' )
);
$shipping_address = array(
'first_name' => $this->get_posted_address_data( 'first_name', 'shipping' ),
'last_name' => $this->get_posted_address_data( 'last_name', 'shipping' ),
'company' => $this->get_posted_address_data( 'company', 'shipping' ),
'address_1' => $this->get_posted_address_data( 'address_1', 'shipping' ),
'address_2' => $this->get_posted_address_data( 'address_2', 'shipping' ),
'city' => $this->get_posted_address_data( 'city', 'shipping' ),
'state' => $this->get_posted_address_data( 'state', 'shipping' ),
'postcode' => $this->get_posted_address_data( 'postcode', 'shipping' ),
'country' => $this->get_posted_address_data( 'country', 'shipping' ),
);
$order->set_address( $billing_address, 'billing' );
$order->set_address( $shipping_address, 'shipping' );
$order->set_payment_method( $this->payment_method );
$order->set_total( WC()->cart->shipping_total, 'shipping' );
$order->set_total( WC()->cart->get_order_discount_total(), 'order_discount' );
$order->set_total( WC()->cart->get_cart_discount_total(), 'cart_discount' );
$order->set_total( WC()->cart->tax_total, 'tax' );
$order->set_total( WC()->cart->shipping_tax_total, 'shipping_tax' );
$order->set_total( WC()->cart->total );
// Update user meta
if ( $this->customer_id ) {
if ( apply_filters( 'woocommerce_checkout_update_customer_data', true, $this ) ) {
foreach( $billing_address as $key => $value ) {
update_user_meta( $this->customer_id, 'billing_' . $key, $value );
}
foreach( $shipping_address as $key => $value ) {
update_user_meta( $this->customer_id, 'shipping_' . $key, $value );
}
}
// Add line item meta for backorder status
if ( $_product->backorders_require_notification() && $_product->is_on_backorder( $values['quantity'] ) ) {
wc_add_order_item_meta( $item_id, apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ), $cart_item_key, $order_id ), $values['quantity'] - max( 0, $_product->get_total_stock() ) );
}
// Allow plugins to add order item meta
do_action( 'woocommerce_add_order_item_meta', $item_id, $values, $cart_item_key );
}
}
// Store fees
foreach ( WC()->cart->get_fees() as $fee_key => $fee ) {
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $fee->name,
'order_item_type' => 'fee'
) );
if ( $fee->taxable )
wc_add_order_item_meta( $item_id, '_tax_class', $fee->tax_class );
else
wc_add_order_item_meta( $item_id, '_tax_class', '0' );
wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $fee->amount ) );
wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $fee->tax ) );
// Allow plugins to add order item meta to fees
do_action( 'woocommerce_add_order_fee_meta', $order_id, $item_id, $fee, $fee_key );
}
// Store shipping for all packages
$packages = WC()->shipping->get_packages();
foreach ( $packages as $i => $package ) {
if ( isset( $package['rates'][ $this->shipping_methods[ $i ] ] ) ) {
$method = $package['rates'][ $this->shipping_methods[ $i ] ];
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $method->label,
'order_item_type' => 'shipping'
) );
if ( $item_id ) {
wc_add_order_item_meta( $item_id, 'method_id', $method->id );
wc_add_order_item_meta( $item_id, 'cost', wc_format_decimal( $method->cost ) );
do_action( 'woocommerce_add_shipping_order_item', $order_id, $item_id, $i );
}
do_action( 'woocommerce_checkout_update_user_meta', $this->customer_id, $this->posted );
}
// Let plugins add meta
do_action( 'woocommerce_checkout_update_order_meta', $order_id, $this->posted );
// If we got here, the order was created without problems!
$wpdb->query( 'COMMIT' );
} catch ( Exception $e ) {
// There was an error adding order data!
$wpdb->query( 'ROLLBACK' );
return new WP_Error( 'checkout-error', $e->getMessage() );
}
// Store tax rows
foreach ( array_keys( WC()->cart->taxes + WC()->cart->shipping_taxes ) as $key ) {
$code = WC()->cart->tax->get_rate_code( $key );
if ( $code ) {
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $code,
'order_item_type' => 'tax'
) );
// Add line item meta
if ( $item_id ) {
wc_add_order_item_meta( $item_id, 'rate_id', $key );
wc_add_order_item_meta( $item_id, 'label', WC()->cart->tax->get_rate_label( $key ) );
wc_add_order_item_meta( $item_id, 'compound', absint( WC()->cart->tax->is_compound( $key ) ? 1 : 0 ) );
wc_add_order_item_meta( $item_id, 'tax_amount', wc_format_decimal( isset( WC()->cart->taxes[ $key ] ) ? WC()->cart->taxes[ $key ] : 0 ) );
wc_add_order_item_meta( $item_id, 'shipping_tax_amount', wc_format_decimal( isset( WC()->cart->shipping_taxes[ $key ] ) ? WC()->cart->shipping_taxes[ $key ] : 0 ) );
}
}
}
// Store coupons
if ( $applied_coupons = WC()->cart->get_coupons() ) {
foreach ( $applied_coupons as $code => $coupon ) {
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $code,
'order_item_type' => 'coupon'
) );
// Add line item meta
if ( $item_id ) {
wc_add_order_item_meta( $item_id, 'discount_amount', isset( WC()->cart->coupon_discount_amounts[ $code ] ) ? WC()->cart->coupon_discount_amounts[ $code ] : 0 );
}
}
}
if ( $this->payment_method ) {
update_post_meta( $order_id, '_payment_method', $this->payment_method->id );
update_post_meta( $order_id, '_payment_method_title', $this->payment_method->get_title() );
}
if ( empty( $this->posted['billing_email'] ) && is_user_logged_in() ) {
$current_user = wp_get_current_user();
update_post_meta( $order_id, '_billing_email', $current_user->user_email );
}
update_post_meta( $order_id, '_order_shipping', wc_format_decimal( WC()->cart->shipping_total ) );
update_post_meta( $order_id, '_order_discount', wc_format_decimal( WC()->cart->get_order_discount_total() ) );
update_post_meta( $order_id, '_cart_discount', wc_format_decimal( WC()->cart->get_cart_discount_total() ) );
update_post_meta( $order_id, '_order_tax', wc_format_decimal( WC()->cart->tax_total ) );
update_post_meta( $order_id, '_order_shipping_tax', wc_format_decimal( WC()->cart->shipping_tax_total ) );
update_post_meta( $order_id, '_order_total', wc_format_decimal( WC()->cart->total, get_option( 'woocommerce_price_num_decimals' ) ) );
update_post_meta( $order_id, '_order_key', 'wc_' . apply_filters('woocommerce_generate_order_key', uniqid('order_') ) );
update_post_meta( $order_id, '_customer_user', absint( $this->customer_id ) );
update_post_meta( $order_id, '_order_currency', get_woocommerce_currency() );
update_post_meta( $order_id, '_prices_include_tax', get_option( 'woocommerce_prices_include_tax' ) );
update_post_meta( $order_id, '_customer_ip_address', isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'] );
update_post_meta( $order_id, '_customer_user_agent', isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '' );
// Let plugins add meta
do_action( 'woocommerce_checkout_update_order_meta', $order_id, $this->posted );
return $order_id;
}
@ -658,6 +596,10 @@ class WC_Checkout {
$order_id = $this->create_order();
if ( is_wp_error( $order_id ) ) {
throw new Exception( $order_id->get_error_message() );
}
do_action( 'woocommerce_checkout_order_processed', $order_id, $this->posted );
// Process payment
@ -717,10 +659,9 @@ class WC_Checkout {
}
} catch ( Exception $e ) {
if ( ! empty( $e ) )
if ( ! empty( $e ) ) {
wc_add_notice( $e->getMessage(), 'error' );
}
}
} // endif
@ -746,6 +687,26 @@ class WC_Checkout {
}
}
/**
* Get a posted address field after sanitization and validation.
* @param string $key
* @param string $type billing for shipping
* @return string
*/
public function get_posted_address_data( $key, $type = 'billing' ) {
if ( 'billing' === $type || false === $this->posted['ship_to_different_address'] ) {
$return = isset( $this->posted[ 'billing_' . $key ] ) ? $this->posted[ 'billing_' . $key ] : '';
} else {
$return = isset( $this->posted[ 'shipping_' . $key ] ) ? $this->posted[ 'shipping_' . $key ] : '';
}
// Use logged in user's billing email if neccessary
if ( 'email' === $key && empty( $return ) && is_user_logged_in() ) {
$current_user = wp_get_current_user();
$return = $current_user->user_email;
}
return $return;
}
/**
* Gets the value either from the posted data, or from the users meta data

View File

@ -381,7 +381,7 @@ class WC_Countries {
'HU' => "{name}\n{company}\n{city}\n{address_1}\n{address_2}\n{postcode}\n{country}",
'IS' => $postcode_before_city,
'IT' => "{company}\n{name}\n{address_1}\n{address_2}\n{postcode}\n{city}\n{state_upper}\n{country}",
'JP' => "{postcode}\n{state}{city}{address_2}\n{address_1}\n{company}\n{last_name} {first_name}\n {country}",
'JP' => "{postcode}\n{state}{city}{address_1}\n{address_2}\n{company}\n{last_name} {first_name}\n {country}",
'TW' => "{postcode}\n{city}{address_2}\n{address_1}\n{company}\n{last_name} {first_name}\n {country}",
'LI' => $postcode_before_city,
'NL' => $postcode_before_city,
@ -725,7 +725,7 @@ class WC_Countries {
),
'JP' => array(
'state' => array(
'label' => __( 'Province', 'woocommerce' )
'label' => __( 'Prefecture', 'woocommerce' )
)
),
'KR' => array(

View File

@ -351,6 +351,24 @@ class WC_Coupon {
}
}
// Exclude Sale Items check for product coupons - valid if a non-sale item is present
if ( 'yes' === $this->exclude_sale_items && in_array( $this->type, array( 'fixed_product', 'percent_product' ) ) ) {
$valid_for_cart = false;
$product_ids_on_sale = wc_get_product_ids_on_sale();
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( sizeof( array_intersect( array( absint( $cart_item['product_id'] ), absint( $cart_item['variation_id'] ), $cart_item['data']->get_parent() ), $product_ids_on_sale ) ) === 0 ) {
// not on sale
$valid_for_cart = true;
}
}
}
if ( ! $valid_for_cart ) {
$valid = false;
$error_code = self::E_WC_COUPON_NOT_VALID_SALE_ITEMS;
}
}
// Cart discounts cannot be added if non-eligble product is found in cart
if ( $this->type != 'fixed_product' && $this->type != 'percent_product' ) {
@ -431,10 +449,8 @@ class WC_Coupon {
* @return bool
*/
public function is_valid_for_cart() {
if ( $this->type != 'fixed_cart' && $this->type != 'percent' )
return false;
else
return true;
$valid = $this->type != 'fixed_cart' && $this->type != 'percent' ? false : true;
return apply_filters( 'woocommerce_coupon_is_valid_for_cart', $valid, $this );
}
/**

View File

@ -157,7 +157,7 @@ class WC_Download_Handler {
// ...or serve it
$remote_file = true;
$parsed_file_path = parse_url( $file_path );
$wp_uploads = wp_upload_dir();
$wp_uploads_dir = $wp_uploads['basedir'];
$wp_uploads_url = $wp_uploads['baseurl'];
@ -191,7 +191,7 @@ class WC_Download_Handler {
$file_path = str_replace( site_url( '/', 'http' ), ABSPATH, $file_path );
} elseif ( file_exists( ABSPATH . $file_path ) ) {
/** Path needs an abspath to work */
$remote_file = false;
$file_path = ABSPATH . $file_path;
@ -238,16 +238,19 @@ class WC_Download_Handler {
/**
* Prevents errors, for example: transfer closed with 3 bytes remaining to read
*/
@ob_end_clean(); // Clear the output buffer
if ( ob_get_length() ) {
if ( ob_get_level() ) {
if ( ob_get_level() ) {
$levels = ob_get_level();
$levels = ob_get_level();
for ( $i = 0; $i < $levels; $i++ ) {
@ob_end_clean(); // Zip corruption fix
for ( $i = 0; $i < $levels; $i++ ) {
ob_end_clean(); // Zip corruption fix
}
} else {
ob_end_clean(); // Clear the output buffer
}
}
if ( $is_IE && is_ssl() ) {
@ -304,9 +307,9 @@ class WC_Download_Handler {
}
if ( $remote_file ) {
self::readfile_chunked( $file_path ) or header( 'Location: ' . $file_path );
self::readfile_chunked( $file_path ) || header( 'Location: ' . $file_path );
} else {
self::readfile_chunked( $file_path ) or wp_die( __( 'File not found', 'woocommerce' ) . ' <a href="' . esc_url( home_url() ) . '" class="wc-forward">' . __( 'Go to homepage', 'woocommerce' ) . '</a>', '', array( 'response' => 404 ) );
self::readfile_chunked( $file_path ) || wp_die( __( 'File not found', 'woocommerce' ) . ' <a href="' . esc_url( home_url() ) . '" class="wc-forward">' . __( 'Go to homepage', 'woocommerce' ) . '</a>', '', array( 'response' => 404 ) );
}
exit;
@ -325,16 +328,27 @@ class WC_Download_Handler {
$buffer = '';
$cnt = 0;
$handle = @fopen( $file, 'r' );
if ( $handle === FALSE ) {
if ( file_exists( $file ) ) {
$handle = fopen( $file, 'r' );
if ( $handle === FALSE ) {
return FALSE;
}
} elseif ( version_compare( PHP_VERSION, '5.4.0', '<' ) && ini_get( 'safe_mode' ) ) {
$handle = @fopen( $file, 'r' );
if ( $handle === FALSE ) {
return FALSE;
}
} else {
return FALSE;
}
while ( ! feof( $handle ) ) {
$buffer = fread( $handle, $chunksize );
echo $buffer;
@ob_flush();
@flush();
if ( ob_get_length() ) {
ob_flush();
flush();
}
if ( $retbytes ) {
$cnt += strlen( $buffer );

View File

@ -37,20 +37,19 @@ class WC_Emails {
private $_content_type;
/**
* @var WooCommerce The single instance of the class
* @var WC_Emails The single instance of the class
* @since 2.1
*/
protected static $_instance = null;
/**
* Main WooCommerce Instance
* Main WC_Emails Instance
*
* Ensures only one instance of WooCommerce is loaded or can be loaded.
* Ensures only one instance of WC_Emails is loaded or can be loaded.
*
* @since 2.1
* @static
* @see WC()
* @return Main WooCommerce instance
* @return WC_Emails Main instance
*/
public static function instance() {
if ( is_null( self::$_instance ) )

View File

@ -84,33 +84,36 @@ class WC_Form_Handler {
wc_add_notice( $field['label'] . ' ' . __( 'is a required field.', 'woocommerce' ), 'error' );
}
// Validation rules
if ( ! empty( $field['validate'] ) && is_array( $field['validate'] ) ) {
foreach ( $field['validate'] as $rule ) {
switch ( $rule ) {
case 'postcode' :
$_POST[ $key ] = strtoupper( str_replace( ' ', '', $_POST[ $key ] ) );
if ( ! empty( $_POST[ $key ] ) ) {
if ( ! WC_Validation::is_postcode( $_POST[ $key ], $_POST[ $load_address . '_country' ] ) ) {
wc_add_notice( __( 'Please enter a valid postcode/ZIP.', 'woocommerce' ), 'error' );
} else {
$_POST[ $key ] = wc_format_postcode( $_POST[ $key ], $_POST[ $load_address . '_country' ] );
}
break;
case 'phone' :
$_POST[ $key ] = wc_format_phone_number( $_POST[ $key ] );
// Validation rules
if ( ! empty( $field['validate'] ) && is_array( $field['validate'] ) ) {
foreach ( $field['validate'] as $rule ) {
switch ( $rule ) {
case 'postcode' :
$_POST[ $key ] = strtoupper( str_replace( ' ', '', $_POST[ $key ] ) );
if ( ! WC_Validation::is_phone( $_POST[ $key ] ) ) {
wc_add_notice( '<strong>' . $field['label'] . '</strong> ' . __( 'is not a valid phone number.', 'woocommerce' ), 'error' );
}
break;
case 'email' :
$_POST[ $key ] = strtolower( $_POST[ $key ] );
if ( ! WC_Validation::is_postcode( $_POST[ $key ], $_POST[ $load_address . '_country' ] ) ) {
wc_add_notice( __( 'Please enter a valid postcode/ZIP.', 'woocommerce' ), 'error' );
} else {
$_POST[ $key ] = wc_format_postcode( $_POST[ $key ], $_POST[ $load_address . '_country' ] );
}
break;
case 'phone' :
$_POST[ $key ] = wc_format_phone_number( $_POST[ $key ] );
if ( ! is_email( $_POST[ $key ] ) ) {
wc_add_notice( '<strong>' . $field['label'] . '</strong> ' . __( 'is not a valid email address.', 'woocommerce' ), 'error' );
}
break;
if ( ! WC_Validation::is_phone( $_POST[ $key ] ) ) {
wc_add_notice( '<strong>' . $field['label'] . '</strong> ' . __( 'is not a valid phone number.', 'woocommerce' ), 'error' );
}
break;
case 'email' :
$_POST[ $key ] = strtolower( $_POST[ $key ] );
if ( ! is_email( $_POST[ $key ] ) ) {
wc_add_notice( '<strong>' . $field['label'] . '</strong> ' . __( 'is not a valid email address.', 'woocommerce' ), 'error' );
}
break;
}
}
}
}
@ -403,7 +406,7 @@ class WC_Form_Handler {
}
// Sanitize
$quantity = apply_filters( 'woocommerce_stock_amount_cart_item', apply_filters( 'woocommerce_stock_amount', preg_replace( "/[^0-9\.]/", '', $cart_totals[ $cart_item_key ]['qty'] ) ), $cart_item_key );
$quantity = apply_filters( 'woocommerce_stock_amount_cart_item', wc_stock_amount( preg_replace( "/[^0-9\.]/", '', $cart_totals[ $cart_item_key ]['qty'] ) ), $cart_item_key );
if ( '' === $quantity || $quantity == $values['quantity'] )
continue;
@ -568,7 +571,7 @@ class WC_Form_Handler {
if ( 'variable' === $add_to_cart_handler ) {
$variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( $_REQUEST['variation_id'] );
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_REQUEST['quantity'] );
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
$all_variations_set = true;
$variations = array();
@ -683,7 +686,7 @@ class WC_Form_Handler {
// Simple Products
} else {
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_REQUEST['quantity'] );
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
// Add to cart validation
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );

View File

@ -15,4 +15,4 @@ class WC_Order extends WC_Abstract_Order {
$this->order_type = 'simple';
parent::__construct( $order );
}
}
}

View File

@ -16,20 +16,19 @@ class WC_Payment_Gateways {
var $payment_gateways;
/**
* @var WooCommerce The single instance of the class
* @var WC_Payment_Gateways The single instance of the class
* @since 2.1
*/
protected static $_instance = null;
/**
* Main WooCommerce Instance
* Main WC_Payment_Gateways Instance
*
* Ensures only one instance of WooCommerce is loaded or can be loaded.
* Ensures only one instance of WC_Payment_Gateways is loaded or can be loaded.
*
* @since 2.1
* @static
* @see WC()
* @return Main WooCommerce instance
* @return WC_Payment_Gateways Main instance
*/
public static function instance() {
if ( is_null( self::$_instance ) )

View File

@ -23,6 +23,12 @@ class WC_Post_Data {
* Hook in methods
*/
public static function init() {
add_action( 'set_object_terms', array( __CLASS__, 'set_object_terms' ), 10, 6 );
add_action( 'transition_post_status', array( __CLASS__, 'transition_post_status' ), 10, 3 );
add_action( 'woocommerce_product_set_stock_status', array( __CLASS__, 'delete_product_query_transients' ) );
add_action( 'woocommerce_product_set_visibility', array( __CLASS__, 'delete_product_query_transients' ) );
add_action( 'edit_term', array( __CLASS__, 'edit_term' ), 10, 3 );
add_action( 'edited_term', array( __CLASS__, 'edited_term' ), 10, 3 );
add_filter( 'update_order_item_metadata', array( __CLASS__, 'update_order_item_metadata' ), 10, 5 );
@ -31,6 +37,39 @@ class WC_Post_Data {
add_action( 'pre_post_update', array( __CLASS__, 'pre_post_update' ) );
}
/**
* Delete transients when terms are set
*/
public static function set_object_terms( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ) {
foreach ( array_merge( $tt_ids, $old_tt_ids ) as $id ) {
delete_transient( 'wc_ln_count_' . md5( sanitize_key( $taxonomy ) . sanitize_key( $id ) ) );
}
}
/**
* When a post status changes
*/
public static function transition_post_status( $new_status, $old_status, $post ) {
if ( ( 'publish' === $new_status || 'publish' === $old_status ) && in_array( $post->post_type, array( 'product', 'product_variation' ) ) ) {
self::delete_product_query_transients();
}
}
/**
* Delete product view transients when needed e.g. when post status changes, or visibility/stock status is modified.
*/
public static function delete_product_query_transients() {
global $wpdb;
if ( wp_using_ext_object_cache() ) {
wp_cache_flush(); // There isn't a reliable method of looking up the names, so flush the cache.
return;
}
$wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('\_transient\_wc\_uf\_pid\_%') OR `option_name` LIKE ('\_transient\_timeout\_wc\_uf\_pid\_%')" );
$wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('\_transient\_wc\_products\_will\_display\_%') OR `option_name` LIKE ('\_transient\_timeout\_wc\_products\_will\_display\_%')" );
}
/**
* When editing a term, check for product attributes
* @param id $term_id
@ -151,7 +190,9 @@ class WC_Post_Data {
*/
public static function pre_post_update( $post_id ) {
if ( isset( $_POST['_visibility'] ) ) {
update_post_meta( $post_id, '_visibility', stripslashes( $_POST['_visibility'] ) );
if ( update_post_meta( $post_id, '_visibility', wc_clean( $_POST['_visibility'] ) ) ) {
do_action( 'woocommerce_product_set_visibility', $post_id, wc_clean( $_POST['_visibility'] ) );
}
}
if ( isset( $_POST['_stock_status'] ) ) {
wc_update_product_stock_status( $post_id, wc_clean( $_POST['_stock_status'] ) );

View File

@ -244,7 +244,7 @@ class WC_Post_types {
'rewrite' => $product_permalink ? array( 'slug' => untrailingslashit( $product_permalink ), 'with_front' => false, 'feeds' => true ) : false,
'query_var' => true,
'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'comments', 'custom-fields', 'page-attributes' ),
'has_archive' => ( $shop_page_id = wc_get_page_id( 'shop' ) ) && get_page( $shop_page_id ) ? get_page_uri( $shop_page_id ) : 'shop',
'has_archive' => ( $shop_page_id = wc_get_page_id( 'shop' ) ) && get_post( $shop_page_id ) ? get_page_uri( $shop_page_id ) : 'shop',
'show_in_nav_menus' => true
)
)

View File

@ -64,7 +64,7 @@ class WC_Product_Grouped extends WC_Product {
$stock = get_post_meta( $child_id, '_stock', true );
if ( $stock != '' ) {
$this->total_stock += intval( $stock );
$this->total_stock += wc_stock_amount( $stock );
}
}
}
@ -73,7 +73,7 @@ class WC_Product_Grouped extends WC_Product {
}
}
return apply_filters( 'woocommerce_stock_amount', $this->total_stock );
return wc_stock_amount( $this->total_stock );
}
/**

View File

@ -92,6 +92,8 @@ class WC_Product_Simple extends WC_Product {
}
}
wc_delete_product_transients( $this->id );
delete_transient( 'wc_products_onsale' );
do_action( 'woocommerce_grouped_product_sync', $this->id, $children_by_price );
}
}

View File

@ -22,9 +22,8 @@ class WC_Product_Variable extends WC_Product {
public $total_stock;
/**
* __construct function.
* Constructor
*
* @access public
* @param mixed $product
*/
public function __construct( $product ) {
@ -51,28 +50,24 @@ class WC_Product_Variable extends WC_Product {
* @return int
*/
public function get_total_stock() {
if ( empty( $this->total_stock ) ) {
$transient_name = 'wc_product_total_stock_' . $this->id;
if ( false === ( $this->total_stock = get_transient( $transient_name ) ) ) {
$this->total_stock = $this->stock;
$this->total_stock = max( 0, wc_stock_amount( $this->stock ) );
if ( sizeof( $this->get_children() ) > 0 ) {
foreach ($this->get_children() as $child_id) {
$stock = get_post_meta( $child_id, '_stock', true );
if ( $stock != '' ) {
$this->total_stock += intval( $stock );
foreach ( $this->get_children() as $child_id ) {
if ( 'yes' === get_post_meta( $child_id, '_manage_stock', true ) ) {
$stock = get_post_meta( $child_id, '_stock', true );
$this->total_stock += max( 0, wc_stock_amount( $stock ) );
}
}
}
set_transient( $transient_name, $this->total_stock, YEAR_IN_SECONDS );
}
}
return apply_filters( 'woocommerce_stock_amount', $this->total_stock );
return wc_stock_amount( $this->total_stock );
}
/**
@ -82,14 +77,50 @@ class WC_Product_Variable extends WC_Product {
* @param string $mode can be set, add, or subtract
* @return int Stock
*/
function set_stock( $amount = null, $mode = 'set' ) {
// Empty total stock so its refreshed
public function set_stock( $amount = null, $mode = 'set' ) {
$this->total_stock = '';
// Call parent set_stock
delete_transient( 'wc_product_total_stock_' . $this->id );
return parent::set_stock( $amount, $mode );
}
/**
* Performed after a stock level change at product level
*/
protected function check_stock_status() {
$set_child_stock_status = '';
if ( ! $this->backorders_allowed() && $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
$set_child_stock_status = 'outofstock';
} elseif ( $this->backorders_allowed() || $this->get_stock_quantity() > get_option( 'woocommerce_notify_no_stock_amount' ) ) {
$set_child_stock_status = 'instock';
}
if ( $set_child_stock_status ) {
foreach ( $this->get_children() as $child_id ) {
if ( 'yes' !== get_post_meta( $child_id, '_manage_stock', true ) ) {
wc_update_product_stock_status( $child_id, $set_child_stock_status );
}
}
// Children statuses changed, so sync self
self::sync_stock_status( $this->id );
}
}
/**
* set_stock_status function.
*
* @access public
* @return void
*/
public function set_stock_status( $status ) {
$status = ( 'outofstock' === $status ) ? 'outofstock' : 'instock';
if ( update_post_meta( $this->id, '_stock_status', $status ) ) {
do_action( 'woocommerce_product_set_stock_status', $this->id, $status );
}
}
/**
* Return the products children posts.
*
@ -97,14 +128,22 @@ class WC_Product_Variable extends WC_Product {
* @return array of children ids
*/
public function get_children( $visible_only = false ) {
if ( ! is_array( $this->children ) ) {
$this->children = array();
$transient_name = 'wc_product_children_ids_' . $this->id;
if ( false === ( $this->children = get_transient( $transient_name ) ) ) {
$this->children = get_posts( 'post_parent=' . $this->id . '&post_type=product_variation&orderby=menu_order&order=ASC&fields=ids&post_status=any&numberposts=-1' );
$args = array(
'post_parent' => $this->id,
'post_type' => 'product_variation',
'orderby' => 'menu_order',
'order' => 'ASC',
'fields' => 'ids',
'post_status' => 'any',
'numberposts' => -1
);
$this->children = get_posts( $args );
set_transient( $transient_name, $this->children, YEAR_IN_SECONDS );
}
@ -112,14 +151,14 @@ class WC_Product_Variable extends WC_Product {
if ( $visible_only ) {
$children = array();
foreach ( $this->children as $child_id ) {
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
$stock = get_post_meta( $child_id, '_stock', true );
if ( $stock !== "" && $stock <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
continue;
foreach( $this->children as $child_id ) {
if ( 'yes' === get_post_meta( $child_id, '_manage_stock', true ) ) {
if ( 'instock' === get_post_meta( $child_id, '_stock_status', true ) ) {
$children[] = $child_id;
}
} elseif ( $this->is_in_stock() ) {
$children[] = $child_id;
}
$children[] = $child_id;
}
} else {
$children = $this->children;
@ -391,49 +430,51 @@ class WC_Product_Variable extends WC_Product {
$variation = $this->get_child( $child_id );
if ( ! empty( $variation->variation_id ) ) {
$variation_attributes = $variation->get_variation_attributes();
$availability = $variation->get_availability();
$availability_html = empty( $availability['availability'] ) ? '' : apply_filters( 'woocommerce_stock_html', '<p class="stock ' . esc_attr( $availability['class'] ) . '">'. wp_kses_post( $availability['availability'] ).'</p>', wp_kses_post( $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( 'single_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 );
$image_alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
} else {
$image = $image_link = $image_title = $image_alt = '';
}
$available_variations[] = apply_filters( 'woocommerce_available_variation', array(
'variation_id' => $child_id,
'variation_is_visible' => $variation->variation_is_visible(),
'is_purchasable' => $variation->is_purchasable(),
'attributes' => $variation_attributes,
'image_src' => $image,
'image_link' => $image_link,
'image_title' => $image_title,
'image_alt' => $image_alt,
'price_html' => $variation->get_price() === "" || $this->get_variation_price( 'min' ) !== $this->get_variation_price( 'max' ) ? '<span class="price">' . $variation->get_price_html() . '</span>' : '',
'availability_html' => $availability_html,
'sku' => $variation->get_sku(),
'weight' => $variation->get_weight() . ' ' . esc_attr( get_option('woocommerce_weight_unit' ) ),
'dimensions' => $variation->get_dimensions(),
'min_qty' => 1,
'max_qty' => $variation->backorders_allowed() ? '' : $variation->stock,
'backorders_allowed' => $variation->backorders_allowed(),
'is_in_stock' => $variation->is_in_stock(),
'is_downloadable' => $variation->is_downloadable() ,
'is_virtual' => $variation->is_virtual(),
'is_sold_individually' => $variation->is_sold_individually() ? 'yes' : 'no',
), $this, $variation );
if ( empty( $variation->variation_id ) || ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ! $variation->is_in_stock() ) ) {
continue;
}
$variation_attributes = $variation->get_variation_attributes();
$availability = $variation->get_availability();
$availability_html = empty( $availability['availability'] ) ? '' : apply_filters( 'woocommerce_stock_html', '<p class="stock ' . esc_attr( $availability['class'] ) . '">'. wp_kses_post( $availability['availability'] ).'</p>', wp_kses_post( $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( 'single_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 );
$image_alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
} else {
$image = $image_link = $image_title = $image_alt = '';
}
$available_variations[] = apply_filters( 'woocommerce_available_variation', array(
'variation_id' => $child_id,
'variation_is_visible' => $variation->variation_is_visible(),
'is_purchasable' => $variation->is_purchasable(),
'attributes' => $variation_attributes,
'image_src' => $image,
'image_link' => $image_link,
'image_title' => $image_title,
'image_alt' => $image_alt,
'price_html' => $variation->get_price() === "" || $this->get_variation_price( 'min' ) !== $this->get_variation_price( 'max' ) ? '<span class="price">' . $variation->get_price_html() . '</span>' : '',
'availability_html' => $availability_html,
'sku' => $variation->get_sku(),
'weight' => $variation->get_weight() . ' ' . esc_attr( get_option('woocommerce_weight_unit' ) ),
'dimensions' => $variation->get_dimensions(),
'min_qty' => 1,
'max_qty' => $variation->backorders_allowed() ? '' : $variation->stock,
'backorders_allowed' => $variation->backorders_allowed(),
'is_in_stock' => $variation->is_in_stock(),
'is_downloadable' => $variation->is_downloadable() ,
'is_virtual' => $variation->is_virtual(),
'is_sold_individually' => $variation->is_sold_individually() ? 'yes' : 'no',
), $this, $variation );
}
return $available_variations;
@ -464,6 +505,33 @@ class WC_Product_Variable extends WC_Product {
}
}
/**
* Sync variable product stock status with children
* @param int $product_id
*/
public static function sync_stock_status( $product_id ) {
$children = get_posts( array(
'post_parent' => $product_id,
'posts_per_page'=> -1,
'post_type' => 'product_variation',
'fields' => 'ids',
'post_status' => 'publish'
) );
$stock_status = 'outofstock';
foreach ( $children as $child_id ) {
$child_stock_status = get_post_meta( $child_id, '_stock_status', true );
$child_stock_status = $child_stock_status ? $child_stock_status : 'instock';
if ( 'instock' === $child_stock_status ) {
$stock_status = 'instock';
break;
}
}
wc_update_product_stock_status( $product_id, $stock_status );
}
/**
* Sync the variable product with it's children
*/
@ -547,10 +615,9 @@ class WC_Product_Variable extends WC_Product {
// The VARIABLE PRODUCT price should equal the min price of any type
update_post_meta( $product_id, '_price', $min_price );
delete_transient( 'wc_products_onsale' );
do_action( 'woocommerce_variable_product_sync', $product_id, $children );
wc_delete_product_transients( $product_id );
}
}
}

View File

@ -1,6 +1,7 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Product Variation Class
@ -8,7 +9,7 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
* The WooCommerce product variation class handles product variation data.
*
* @class WC_Product_Variation
* @version 2.1.0
* @version 2.2.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
@ -21,51 +22,50 @@ class WC_Product_Variation extends WC_Product {
/** @public object Parent Variable product object. */
public $parent;
/** @public array Stores variation data (attributes) for the current variation. */
public $variation_data = array();
/** @public bool True if the variation has a length. */
public $variation_has_length = false;
/** @public bool True if the variation has a width. */
public $variation_has_width = false;
/** @public bool True if the variation has a height. */
public $variation_has_height = false;
/** @public bool True if the variation has a weight. */
public $variation_has_weight = false;
/** @public bool True if the variation has stock and is managing stock. */
public $variation_has_stock = false;
/** @public bool True if the variation has a sku. */
public $variation_has_sku = false;
/** @public string Stores the shipping class of the variation. */
public $variation_shipping_class = false;
public $variation_shipping_class = false;
/** @public int Stores the shipping class ID of the variation. */
public $variation_shipping_class_id = false;
public $variation_shipping_class_id = false;
/** @public unused vars @deprecated in 2.2 */
public $variation_has_sku = true;
public $variation_has_length = true;
public $variation_has_width = true;
public $variation_has_height = true;
public $variation_has_weight = true;
public $variation_has_tax_class = true;
public $variation_has_downloadable_files = true;
/** @public bool True if the variation has a tax class. */
public $variation_has_tax_class = false;
/** @public bool True if the variation has file paths. */
public $variation_has_downloadable_files = false;
/** @private array List of meta keys which apply to variations */
public $variation_level_meta_keys = array(
'manage_stock',
'stock_status',
'stock',
'backorders',
'sku',
'downloadable_files',
'weight',
'length',
'height',
'downloadable',
'virtual',
'tax_class',
'sale_price_dates_from',
'sale_price_dates_to',
'price',
'regular_price',
'sale_price'
);
/**
* Loads all product data from custom fields
* Loads required variation data.
*
* @access public
* @param int $variation_id ID of the variation to load
* @param array $args Array of the arguments containing parent product data
* @return void
*/
public function __construct( $variation, $args = array() ) {
$this->product_type = 'variation';
if ( is_object( $variation ) ) {
$this->variation_id = absint( $variation->ID );
} else {
@ -73,106 +73,82 @@ class WC_Product_Variation extends WC_Product {
}
/* Get main product data from parent (args) */
$this->id = ! empty( $args['parent_id'] ) ? intval( $args['parent_id'] ) : wp_get_post_parent_id( $this->variation_id );
$this->id = ! empty( $args['parent_id'] ) ? intval( $args['parent_id'] ) : wp_get_post_parent_id( $this->variation_id );
// The post doesn't have a parent id, therefore its invalid.
if ( empty( $this->id ) )
if ( empty( $this->id ) ) {
return;
// Get post data
$this->parent = ! empty( $args['parent'] ) ? $args['parent'] : get_product( $this->id );
$this->post = ! empty( $this->parent->post ) ? $this->parent->post : array();
$this->product_custom_fields = get_post_meta( $this->variation_id );
// Get the variation attributes from meta
foreach ( $this->product_custom_fields as $name => $value ) {
if ( ! strstr( $name, 'attribute_' ) )
continue;
$this->variation_data[ $name ] = sanitize_title( $value[0] );
}
// Now get variation meta to override the parent variable product
if ( ! empty( $this->product_custom_fields['_sku'][0] ) ) {
$this->variation_has_sku = true;
$this->sku = $this->product_custom_fields['_sku'][0];
}
$this->product_type = 'variation';
$this->parent = ! empty( $args['parent'] ) ? $args['parent'] : get_product( $this->id );
$this->post = ! empty( $this->parent->post ) ? $this->parent->post : array();
}
if ( ! empty( $this->product_custom_fields['_downloadable_files'][0] ) ) {
$this->variation_has_downloadable_files = true;
$this->downloadable_files = $this->product_custom_fields['_downloadable_files'][0];
}
if ( isset( $this->product_custom_fields['_stock'][0] ) && '' !== $this->product_custom_fields['_stock'][0] && 'yes' === get_option( 'woocommerce_manage_stock' ) ) {
$this->variation_has_stock = true;
$this->manage_stock = 'yes';
$this->stock = $this->product_custom_fields['_stock'][0];
}
if ( isset( $this->product_custom_fields['_backorders'][0] ) && ! is_null( $this->product_custom_fields['_backorders'][0] ) ) {
$this->backorders = $this->product_custom_fields['_backorders'][0];
}
if ( isset( $this->product_custom_fields['_weight'][0] ) && $this->product_custom_fields['_weight'][0] !== '' ) {
$this->variation_has_weight = true;
$this->weight = $this->product_custom_fields['_weight'][0];
}
if ( isset( $this->product_custom_fields['_length'][0] ) && $this->product_custom_fields['_length'][0] !== '' ) {
$this->variation_has_length = true;
$this->length = $this->product_custom_fields['_length'][0];
}
if ( isset( $this->product_custom_fields['_width'][0] ) && $this->product_custom_fields['_width'][0] !== '' ) {
$this->variation_has_width = true;
$this->width = $this->product_custom_fields['_width'][0];
}
if ( isset( $this->product_custom_fields['_height'][0] ) && $this->product_custom_fields['_height'][0] !== '' ) {
$this->variation_has_height = true;
$this->height = $this->product_custom_fields['_height'][0];
}
if ( isset( $this->product_custom_fields['_downloadable'][0] ) && $this->product_custom_fields['_downloadable'][0] == 'yes' ) {
$this->downloadable = 'yes';
/**
* __isset function.
*
* @access public
* @param mixed $key
* @return bool
*/
public function __isset( $key ) {
if ( in_array( $key, $this->variation_level_meta_keys ) ) {
return metadata_exists( 'post', $this->variation_id, '_' . $key ) || metadata_exists( 'post', $this->id, '_' . $key );
} else {
$this->downloadable = 'no';
return metadata_exists( 'post', $this->id, '_' . $key );
}
}
if ( isset( $this->product_custom_fields['_virtual'][0] ) && $this->product_custom_fields['_virtual'][0] == 'yes' ) {
$this->virtual = 'yes';
} else {
$this->virtual = 'no';
}
/**
* Get method returns variation meta data if set, otherwise in most cases the data from the parent.
*
* @access public
* @param string $key
* @return mixed
*/
public function __get( $key ) {
if ( in_array( $key, $this->variation_level_meta_keys ) ) {
if ( isset( $this->product_custom_fields['_tax_class'][0] ) ) {
$this->variation_has_tax_class = true;
$this->tax_class = $this->product_custom_fields['_tax_class'][0];
}
// Get values or default if not set (no)
if ( in_array( $key, array( 'downloadable', 'virtual', 'manage_stock' ) ) ) {
$value = ( $value = get_post_meta( $this->variation_id, '_' . $key, true ) ) ? $value : 'no';
if ( isset( $this->product_custom_fields['_sale_price_dates_from'][0] ) )
$this->sale_price_dates_from = $this->product_custom_fields['_sale_price_dates_from'][0];
// Data which must be set (not null), otherwise use parent data
} elseif ( in_array( $key , array( 'tax_class', 'backorders' ) ) ) {
$value = metadata_exists( 'post', $this->variation_id, '_' . $key ) ? get_post_meta( $this->variation, '_' . $key, true ) : get_post_meta( $this->id, '_' . $key, true );
if ( isset( $this->product_custom_fields['_sale_price_dates_to'][0] ) )
$this->sale_price_dates_to = $this->product_custom_fields['_sale_price_dates_to'][0];
// Data which is only at variation level - no inheritance
} elseif ( in_array( $key , array( 'price', 'regular_price', 'sale_price', 'sale_price_dates_to', 'sale_price_dates_from' ) ) ) {
$value = ( $value = get_post_meta( $this->variation_id, '_' . $key, true ) ) ? $value : '';
// Prices
$this->price = isset( $this->product_custom_fields['_price'][0] ) ? $this->product_custom_fields['_price'][0] : '';
$this->regular_price = isset( $this->product_custom_fields['_regular_price'][0] ) ? $this->product_custom_fields['_regular_price'][0] : '';
$this->sale_price = isset( $this->product_custom_fields['_sale_price'][0] ) ? $this->product_custom_fields['_sale_price'][0] : '';
} elseif ( 'stock' === $key ) {
$value = ( $value = get_post_meta( $this->variation_id, '_stock', true ) ) ? $value : 0;
// Backwards compat for prices
if ( $this->price !== '' && $this->regular_price == '' ) {
update_post_meta( $this->variation_id, '_regular_price', $this->price );
$this->regular_price = $this->price;
if ( $this->sale_price !== '' && $this->sale_price < $this->regular_price ) {
update_post_meta( $this->variation_id, '_price', $this->sale_price );
$this->price = $this->sale_price;
} else {
$value = ( $value = get_post_meta( $this->variation_id, '_' . $key, true ) ) ? $value : get_post_meta( $this->id, '_' . $key, true );
}
} elseif ( 'variation_data' === $key ) {
$all_meta = get_post_meta( $this->variation_id );
// Get the variation attributes from meta
foreach ( $all_meta as $name => $value ) {
if ( ! strstr( $name, 'attribute_' ) ) {
continue;
}
$this->variation_data[ $name ] = sanitize_title( $value[0] );
}
return $this->variation_data;
} elseif ( 'variation_has_stock' === $key ) {
return $this->managing_stock();
} else {
$value = parent::__get( $key );
}
$this->total_stock = $this->stock;
return $value;
}
/**
@ -182,7 +158,7 @@ class WC_Product_Variation extends WC_Product {
* @return bool
*/
public function exists() {
return empty( $this->id ) ? false : true;
return ! empty( $this->id );
}
/**
@ -226,16 +202,19 @@ class WC_Product_Variation extends WC_Product {
$visible = true;
// Published == enabled checkbox
if ( get_post_status( $this->variation_id ) != 'publish' )
if ( get_post_status( $this->variation_id ) != 'publish' ) {
$visible = false;
}
// Out of stock visibility
elseif ( get_option('woocommerce_hide_out_of_stock_items') == 'yes' && ! $this->is_in_stock() )
elseif ( get_option('woocommerce_hide_out_of_stock_items') == 'yes' && ! $this->is_in_stock() ) {
$visible = false;
}
// Price not set
elseif ( $this->get_price() === "" )
elseif ( $this->get_price() === "" ) {
$visible = false;
}
return apply_filters( 'woocommerce_variation_is_visible', $visible, $this->variation_id, $this->id );
}
@ -247,15 +226,13 @@ class WC_Product_Variation extends WC_Product {
* @return bool
*/
public function is_purchasable() {
// Published == enabled checkbox
if ( get_post_status( $this->variation_id ) != 'publish' )
if ( get_post_status( $this->variation_id ) != 'publish' ) {
$purchasable = false;
else
} else {
$purchasable = parent::is_purchasable();
return $purchasable;
}
return apply_filters( 'woocommerce_variation_is_purchasable', $purchasable, $this );
}
/**
@ -292,7 +269,6 @@ class WC_Product_Variation extends WC_Product {
* @return string containing the formatted price
*/
public function get_price_html( $price = '' ) {
$tax_display_mode = get_option( 'woocommerce_tax_display_shop' );
$display_price = $tax_display_mode == 'incl' ? $this->get_price_including_tax() : $this->get_price_excluding_tax();
$display_regular_price = $tax_display_mode == 'incl' ? $this->get_price_including_tax( 1, $this->get_regular_price() ) : $this->get_price_excluding_tax( 1, $this->get_regular_price() );
@ -300,23 +276,11 @@ class WC_Product_Variation extends WC_Product {
if ( $this->get_price() !== '' ) {
if ( $this->is_on_sale() ) {
$price = '<del>' . wc_price( $display_regular_price ) . '</del> <ins>' . wc_price( $display_sale_price ) . '</ins>' . $this->get_price_suffix();
$price = apply_filters( 'woocommerce_variation_sale_price_html', $price, $this );
$price = apply_filters( 'woocommerce_variation_sale_price_html', '<del>' . wc_price( $display_regular_price ) . '</del> <ins>' . wc_price( $display_sale_price ) . '</ins>' . $this->get_price_suffix(), $this );
} elseif ( $this->get_price() > 0 ) {
$price = wc_price( $display_price ) . $this->get_price_suffix();
$price = apply_filters( 'woocommerce_variation_price_html', $price, $this );
$price = apply_filters( 'woocommerce_variation_price_html', wc_price( $display_price ) . $this->get_price_suffix(), $this );
} else {
$price = __( 'Free!', 'woocommerce' );
$price = apply_filters( 'woocommerce_variation_free_price_html', $price, $this );
$price = apply_filters( 'woocommerce_variation_free_price_html', __( 'Free!', 'woocommerce' ), $this );
}
} else {
$price = apply_filters( 'woocommerce_variation_empty_price_html', '', $this );
@ -359,10 +323,31 @@ class WC_Product_Variation extends WC_Product {
} else {
$image = wc_placeholder_img( $size );
}
return $image;
}
/**
* Returns whether or not the product is in stock.
*
* @access public
* @return bool
*/
public function is_in_stock() {
// If we're managing stock at variation level, check stock levels
if ( $this->managing_stock() ) {
if ( $this->backorders_allowed() ) {
return true;
} elseif ( $this->get_total_stock() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
return false;
} else {
return $this->stock_status === 'instock';
}
}
else {
return $this->stock_status === 'instock';
}
}
/**
* Set stock level of the product variation.
*
@ -370,103 +355,80 @@ class WC_Product_Variation extends WC_Product {
* We cannot rely on the original loaded value in case another order was made since then.
*
* @param int $amount
* @param bool $force_variation_stock If true, the variation's stock will be updated and not the parents.
* @param string $mode can be set, add, or subtract
* @return int new stock level
*/
public function set_stock( $amount = null, $force_variation_stock = false, $mode = 'set' ) {
public function set_stock( $amount = null, $mode = 'set' ) {
global $wpdb;
if ( ! is_null( $amount ) ) {
if ( ! is_null( $amount ) && $this->managing_stock() ) {
if ( '' === $amount && $force_variation_stock ) {
// Ensure key exists
add_post_meta( $this->variation_id, '_stock', 0, true );
// If amount is an empty string, stock management is being turned off at variation level
$this->variation_has_stock = false;
$this->stock = '';
unset( $this->manage_stock );
// Update meta
update_post_meta( $this->variation_id, '_stock', '' );
// Refresh parent prices
WC_Product_Variable::sync( $this->id );
} elseif ( $this->variation_has_stock || $force_variation_stock ) {
// Update stock values
$this->variation_has_stock = true;
$this->manage_stock = 'yes';
// Ensure _stock exists
add_post_meta( $this->variation_id, '_stock', '', true );
// Update stock in DB directly
switch ( $mode ) {
case 'add' :
$wpdb->query( "UPDATE {$wpdb->postmeta} SET meta_value = meta_value + {$amount} WHERE post_id = {$this->variation_id} AND meta_key='_stock'" );
break;
case 'subtract' :
$wpdb->query( "UPDATE {$wpdb->postmeta} SET meta_value = meta_value - {$amount} WHERE post_id = {$this->variation_id} AND meta_key='_stock'" );
break;
default :
$wpdb->query( "UPDATE {$wpdb->postmeta} SET meta_value = {$amount} WHERE post_id = {$this->variation_id} AND meta_key='_stock'" );
break;
}
// Clear caches
wp_cache_delete( $this->variation_id, 'post_meta' );
// Update stock amount in class
$this->stock = get_post_meta( $this->variation_id, '_stock', true );
// Clear total stock transient
delete_transient( 'wc_product_total_stock_' . $this->id );
// Check parents out of stock attribute
if ( ! $this->is_in_stock() ) {
// Check parent
$parent_product = get_product( $this->id );
// Only continue if the parent has backorders off and all children are stock managed and out of stock
if ( ! $parent_product->backorders_allowed() && $parent_product->get_total_stock() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
$all_managed = true;
if ( sizeof( $parent_product->get_children() ) > 0 ) {
foreach ( $parent_product->get_children() as $child_id ) {
$stock = get_post_meta( $child_id, '_stock', true );
if ( $stock == '' ) {
$all_managed = false;
break;
}
}
}
if ( $all_managed ) {
$this->set_stock_status( 'outofstock' );
}
}
} elseif ( $this->is_in_stock() ) {
$this->set_stock_status( 'instock' );
}
// Refresh parent prices
WC_Product_Variable::sync( $this->id );
// Trigger action
do_action( 'woocommerce_product_set_stock', $this );
} else {
return parent::set_stock( $amount, $mode );
// Update stock in DB directly
switch ( $mode ) {
case 'add' :
$wpdb->query( "UPDATE {$wpdb->postmeta} SET meta_value = meta_value + {$amount} WHERE post_id = {$this->variation_id} AND meta_key='_stock'" );
break;
case 'subtract' :
$wpdb->query( "UPDATE {$wpdb->postmeta} SET meta_value = meta_value - {$amount} WHERE post_id = {$this->variation_id} AND meta_key='_stock'" );
break;
default :
$wpdb->query( "UPDATE {$wpdb->postmeta} SET meta_value = {$amount} WHERE post_id = {$this->variation_id} AND meta_key='_stock'" );
break;
}
// Clear caches
wp_cache_delete( $this->variation_id, 'post_meta' );
// Clear total stock transient
delete_transient( 'wc_product_total_stock_' . $this->id );
// Stock status
$this->check_stock_status();
// Sync the parent
WC_Product_Variable::sync( $this->id );
// Trigger action
do_action( 'woocommerce_variation_set_stock', $this );
} elseif ( ! is_null( $amount ) ) {
return $this->parent->set_stock( $amount, $mode );
}
return $this->get_stock_quantity();
}
/**
* set_stock_status function.
*
* @access public
*/
public function set_stock_status( $status ) {
$status = 'outofstock' === $status ? 'outofstock' : 'instock';
// Sanity check
if ( $this->managing_stock() ) {
if ( ! $this->backorders_allowed() && $this->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
$status = 'outofstock';
}
} elseif ( $this->parent->managing_stock() ) {
if ( ! $this->parent->backorders_allowed() && $this->parent->get_stock_quantity() <= get_option( 'woocommerce_notify_no_stock_amount' ) ) {
$status = 'outofstock';
}
}
if ( update_post_meta( $this->variation_id, '_stock_status', $status ) ) {
do_action( 'woocommerce_variation_set_stock_status', $this->variation_id, $status );
if ( $this->managing_stock() ) {
WC_Product_Variable::sync_stock_status( $this->id );
}
}
}
/**
* Reduce stock level of the product.
*
@ -474,10 +436,10 @@ class WC_Product_Variation extends WC_Product {
* @return int stock level
*/
public function reduce_stock( $amount = 1 ) {
if ( $this->variation_has_stock ) {
return $this->set_stock( $amount, false, 'subtract' );
if ( $this->managing_stock() ) {
return $this->set_stock( $amount, 'subtract' );
} else {
return parent::reduce_stock( $amount );
return $this->parent->reduce_stock( $amount );
}
}
@ -488,13 +450,69 @@ class WC_Product_Variation extends WC_Product {
* @return int stock level
*/
public function increase_stock( $amount = 1 ) {
if ( $this->variation_has_stock ) {
return $this->set_stock( $amount, false, 'add' );
if ( $this->managing_stock() ) {
return $this->set_stock( $amount, 'add' );
} else {
return parent::increase_stock( $amount );
return $this->parent->increase_stock( $amount );
}
}
/**
* Returns the availability of the product.
*
* @access public
* @return string
*/
public function get_availability() {
if ( $this->managing_stock() ) {
return parent::get_availability();
} else {
return $this->parent->get_availability();
}
}
/**
* Returns whether or not the product needs to notify the customer on backorder.
*
* @access public
* @return bool
*/
public function backorders_require_notification() {
if ( $this->managing_stock() ) {
return parent::backorders_require_notification();
} else {
return $this->parent->backorders_require_notification();
}
}
/**
* is_on_backorder function.
*
* @access public
* @param int $qty_in_cart (default: 0)
* @return bool
*/
public function is_on_backorder( $qty_in_cart = 0 ) {
if ( $this->managing_stock() ) {
return parent::is_on_backorder( $qty_in_cart );
} else {
return $this->parent->is_on_backorder( $qty_in_cart );
} }
/**
* Returns whether or not the product has enough stock for the order.
*
* @access public
* @param mixed $quantity
* @return bool
*/
public function has_enough_stock( $quantity ) {
if ( $this->managing_stock() ) {
return parent::has_enough_stock( $quantity );
} else {
return $this->parent->has_enough_stock( $quantity );
} }
/**
* Get the shipping class, and if not set, get the shipping class of the parent.
*
@ -506,12 +524,11 @@ class WC_Product_Variation extends WC_Product {
$classes = get_the_terms( $this->variation_id, 'product_shipping_class' );
if ( $classes && ! is_wp_error( $classes ) ) {
$this->variation_shipping_class = esc_attr( current( $classes )->slug );
$this->variation_shipping_class = current( $classes )->slug;
} else {
$this->variation_shipping_class = parent::get_shipping_class();
}
}
return $this->variation_shipping_class;
}
@ -523,14 +540,13 @@ class WC_Product_Variation extends WC_Product {
*/
public function get_shipping_class_id() {
if ( ! $this->variation_shipping_class_id ) {
$classes = get_the_terms( $this->variation_id, 'product_shipping_class' );
if ( $classes && ! is_wp_error( $classes ) )
if ( $classes && ! is_wp_error( $classes ) ) {
$this->variation_shipping_class_id = current( $classes )->term_id;
else
} else {
$this->variation_shipping_class_id = parent::get_shipping_class_id();
}
}
return absint( $this->variation_shipping_class_id );
}
@ -543,11 +559,11 @@ class WC_Product_Variation extends WC_Product {
* @return string Formatted product name, including attributes and price
*/
public function get_formatted_name() {
if ( $this->get_sku() )
if ( $this->get_sku() ) {
$identifier = $this->get_sku();
else
} else {
$identifier = '#' . $this->variation_id;
}
$attributes = $this->get_variation_attributes();
$extra_data = ' &ndash; ' . implode( ', ', $attributes ) . ' &ndash; ' . wc_price( $this->get_price() );

View File

@ -56,7 +56,7 @@ class WC_Query {
add_action( 'init', array( $this, 'get_errors' ) );
add_filter( 'query_vars', array( $this, 'add_query_vars'), 0 );
add_action( 'parse_request', array( $this, 'parse_request'), 0 );
add_filter( 'pre_get_posts', array( $this, 'pre_get_posts' ) );
add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ) );
add_filter( 'the_posts', array( $this, 'the_posts' ), 11, 2 );
add_action( 'wp', array( $this, 'remove_product_query' ) );
add_action( 'wp', array( $this, 'remove_ordering_args' ) );
@ -98,7 +98,7 @@ class WC_Query {
*/
public function add_endpoints() {
foreach ( $this->query_vars as $key => $var )
add_rewrite_endpoint( $var, EP_PAGES );
add_rewrite_endpoint( $var, EP_ROOT | EP_PAGES );
}
/**
@ -150,9 +150,22 @@ class WC_Query {
*/
public function pre_get_posts( $q ) {
// We only want to affect the main query
if ( ! $q->is_main_query() )
if ( ! $q->is_main_query() ) {
return;
}
// Fix for endpoints on the homepage
if ( $q->is_home() && 'page' == get_option('show_on_front') && get_option('page_on_front') != $q->get('page_id') ) {
$_query = wp_parse_args( $q->query );
if ( ! empty( $_query ) && array_intersect( array_keys( $_query ), array_keys( $this->query_vars ) ) ) {
$q->is_page = true;
$q->is_home = false;
$q->is_singular = true;
$q->set( 'page_id', get_option('page_on_front') );
}
}
// When orderby is set, WordPress shows posts. Get around that here.
if ( $q->is_home() && 'page' == get_option('show_on_front') && get_option('page_on_front') == wc_get_page_id('shop') ) {
$_query = wp_parse_args( $q->query );
@ -200,12 +213,9 @@ class WC_Query {
add_filter( 'wpseo_metakey', array( $this, 'wpseo_metakey' ) );
}
} else {
// Only apply to product categories, the product post archive, the shop page, product tags, and product attribute taxonomies
if ( ! $q->is_post_type_archive( 'product' ) && ! $q->is_tax( get_object_taxonomies( 'product' ) ) )
return;
// Only apply to product categories, the product post archive, the shop page, product tags, and product attribute taxonomies
} elseif ( ! $q->is_post_type_archive( 'product' ) && ! $q->is_tax( get_object_taxonomies( 'product' ) ) ) {
return;
}
$this->product_query( $q );
@ -385,7 +395,7 @@ class WC_Query {
* @return void
*/
public function remove_product_query() {
remove_filter( 'pre_get_posts', array( $this, 'pre_get_posts' ) );
remove_action( 'pre_get_posts', array( $this, 'pre_get_posts' ) );
}
/**
@ -617,7 +627,7 @@ class WC_Query {
public function stock_status_meta_query( $status = 'instock' ) {
$meta_query = array();
if ( get_option( 'woocommerce_hide_out_of_stock_items' ) == 'yes' ) {
$meta_query = array(
$meta_query = array(
'key' => '_stock_status',
'value' => $status,
'compare' => '='
@ -701,7 +711,7 @@ class WC_Query {
array(
'taxonomy' => $attribute,
'terms' => $value,
'field' => 'id'
'field' => 'term_id'
)
)
)

View File

@ -34,20 +34,19 @@ class WC_Shipping {
var $packages = array();
/**
* @var WooCommerce The single instance of the class
* @var WC_Shipping The single instance of the class
* @since 2.1
*/
protected static $_instance = null;
/**
* Main WooCommerce Instance
* Main WC_Shipping Instance
*
* Ensures only one instance of WooCommerce is loaded or can be loaded.
* Ensures only one instance of WC_Shipping is loaded or can be loaded.
*
* @since 2.1
* @static
* @see WC()
* @return Main WooCommerce instance
* @return WC_Shipping Main instance
*/
public static function instance() {
if ( is_null( self::$_instance ) )

View File

@ -194,7 +194,12 @@ class WC_Shortcodes {
woocommerce_reset_loop();
wp_reset_postdata();
return '<div class="woocommerce columns-' . $columns . '">' . ob_get_clean() . '</div>';
$return = '<div class="woocommerce columns-' . $columns . '">' . ob_get_clean() . '</div>';
// Remove ordering query arguments
WC()->query->remove_ordering_args();
return $return;
}

View File

@ -3,28 +3,24 @@
* Performs tax calculations and loads tax rates.
*
* @class WC_Tax
* @version 2.0.0
* @version 2.2.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
*/
class WC_Tax {
/** @var array */
public $matched_rates;
var $log = array();
public static $precision;
public static $round_at_subtotal;
/**
* __construct function.
* Load options
*
* @access public
*/
public function __construct() {
$this->precision = WC_ROUNDING_PRECISION;
$this->dp = (int) get_option( 'woocommerce_price_num_decimals' );
$this->round_at_subtotal = get_option('woocommerce_tax_round_at_subtotal') == 'yes';
public static function init() {
self::$precision = WC_ROUNDING_PRECISION;
self::$round_at_subtotal = 'yes' === get_option( 'woocommerce_tax_round_at_subtotal' );
}
/**
@ -35,23 +31,23 @@ class WC_Tax {
* @param boolean $suppress_rounding Whether to suppress any rounding from taking place
* @return array Array of rates + prices after tax
*/
public function calc_tax( $price, $rates, $price_includes_tax = false, $suppress_rounding = false ) {
public static function calc_tax( $price, $rates, $price_includes_tax = false, $suppress_rounding = false ) {
// Work in pence to X precision
$price = $this->precision( $price );
$price = self::precision( $price );
if ( $price_includes_tax )
$taxes = $this->calc_inclusive_tax( $price, $rates );
$taxes = self::calc_inclusive_tax( $price, $rates );
else
$taxes = $this->calc_exclusive_tax( $price, $rates );
$taxes = self::calc_exclusive_tax( $price, $rates );
// Round to precision
if ( ! $this->round_at_subtotal && ! $suppress_rounding ) {
if ( ! self::$round_at_subtotal && ! $suppress_rounding ) {
$taxes = array_map( 'round', $taxes ); // Round to precision
}
// Remove precision
$price = $this->remove_precision( $price );
$taxes = array_map( array( $this, 'remove_precision' ), $taxes );
$price = self::remove_precision( $price );
$taxes = array_map( array( __CLASS__, 'remove_precision' ), $taxes );
return apply_filters( 'woocommerce_calc_tax', $taxes, $price, $rates, $price_includes_tax, $suppress_rounding );
}
@ -63,8 +59,8 @@ class WC_Tax {
* @param array Taxation Rate
* @return array
*/
public function calc_shipping_tax( $price, $rates ) {
return $this->calc_exclusive_tax( $price, $rates );
public static function calc_shipping_tax( $price, $rates ) {
return self::calc_exclusive_tax( $price, $rates );
}
/**
@ -72,8 +68,8 @@ class WC_Tax {
* @param float $price
* @return float
*/
private function precision( $price ) {
return $price * ( pow( 10, $this->precision ) );
private static function precision( $price ) {
return $price * ( pow( 10, self::$precision ) );
}
/**
@ -81,8 +77,8 @@ class WC_Tax {
* @param float $price
* @return float
*/
private function remove_precision( $price ) {
return $price / ( pow( 10, $this->precision ) );
private static function remove_precision( $price ) {
return $price / ( pow( 10, self::$precision ) );
}
/**
@ -95,8 +91,8 @@ class WC_Tax {
* }
* add_filter( 'woocommerce_tax_round', 'euro_5cent_rounding' );
*/
public function round( $in ) {
return apply_filters( 'woocommerce_tax_round', round( $in, $this->precision ), $in );
public static function round( $in ) {
return apply_filters( 'woocommerce_tax_round', round( $in, self::$precision ), $in );
}
/**
@ -106,7 +102,7 @@ class WC_Tax {
* @param array $rates
* @return array
*/
private function calc_inclusive_tax( $price, $rates ) {
private static function calc_inclusive_tax( $price, $rates ) {
$taxes = array();
$regular_tax_rates = $compound_tax_rates = 0;
@ -150,7 +146,7 @@ class WC_Tax {
* @param array $rates
* @return array
*/
private function calc_exclusive_tax( $price, $rates ) {
private static function calc_exclusive_tax( $price, $rates ) {
$taxes = array();
// Multiple taxes
@ -205,7 +201,7 @@ class WC_Tax {
* @param array $args
* @return array
*/
public function find_rates( $args = array() ) {
public static function find_rates( $args = array() ) {
global $wpdb;
$defaults = array(
@ -261,7 +257,7 @@ class WC_Tax {
AND (
locations2.location_type = 'city' AND locations2.location_code = %s
OR 0 = (
SELECT COUNT(*) FROM wp_woocommerce_tax_rate_locations as sublocations
SELECT COUNT(*) FROM {$wpdb->prefix}woocommerce_tax_rate_locations as sublocations
WHERE sublocations.location_type = 'city'
AND sublocations.tax_rate_id = tax_rates.tax_rate_id
)
@ -271,7 +267,7 @@ class WC_Tax {
locations.location_type = 'city'
AND locations.location_code = %s
AND 0 = (
SELECT COUNT(*) FROM wp_woocommerce_tax_rate_locations as sublocations
SELECT COUNT(*) FROM {$wpdb->prefix}woocommerce_tax_rate_locations as sublocations
WHERE sublocations.location_type = 'postcode'
AND sublocations.tax_rate_id = tax_rates.tax_rate_id
)
@ -318,7 +314,7 @@ class WC_Tax {
* @param string $tax_class
* @return array
*/
public function get_rates( $tax_class = '' ) {
public static function get_rates( $tax_class = '' ) {
$tax_class = sanitize_title( $tax_class );
@ -327,7 +323,7 @@ class WC_Tax {
list( $country, $state, $postcode, $city ) = WC()->customer->get_taxable_address();
$matched_tax_rates = $this->find_rates( array(
$matched_tax_rates = self::find_rates( array(
'country' => $country,
'state' => $state,
'postcode' => $postcode,
@ -341,7 +337,7 @@ class WC_Tax {
// Prices excluding tax however should just not add any taxes, as they will be added during checkout.
// The woocommerce_default_customer_address option (when set to base) is also used here.
$matched_tax_rates = get_option( 'woocommerce_prices_include_tax' ) == 'yes' || get_option( 'woocommerce_default_customer_address' ) == 'base'
? $this->get_shop_base_rate( $tax_class )
? self::get_shop_base_rate( $tax_class )
: array();
}
@ -355,8 +351,8 @@ class WC_Tax {
* @param string Tax Class
* @return array
*/
public function get_shop_base_rate( $tax_class = '' ) {
return $this->find_rates( array(
public static function get_shop_base_rate( $tax_class = '' ) {
return self::find_rates( array(
'country' => WC()->countries->get_base_country(),
'state' => WC()->countries->get_base_state(),
'postcode' => WC()->countries->get_base_postcode(),
@ -371,7 +367,7 @@ class WC_Tax {
* @param string Tax Class
* @return mixed
*/
public function get_shipping_tax_rates( $tax_class = null ) {
public static function get_shipping_tax_rates( $tax_class = null ) {
// See if we have an explicitly set shipping tax class
if ( $shipping_tax_class = get_option( 'woocommerce_shipping_tax_class' ) ) {
@ -403,7 +399,7 @@ class WC_Tax {
$matched_tax_rates = array();
// This will be per item shipping
$rates = $this->find_rates( array(
$rates = self::find_rates( array(
'country' => $country,
'state' => $state,
'postcode' => $postcode,
@ -418,7 +414,7 @@ class WC_Tax {
if ( sizeof( $matched_tax_rates ) == 0 ) {
// Get standard rate
$rates = $this->find_rates( array(
$rates = self::find_rates( array(
'country' => $country,
'state' => $state,
'city' => $city,
@ -451,7 +447,7 @@ class WC_Tax {
if ( sizeof( $found_tax_classes ) > 1 ) {
if ( in_array( '', $found_tax_classes ) ) {
$rates = $this->find_rates( array(
$rates = self::find_rates( array(
'country' => $country,
'state' => $state,
'city' => $city,
@ -462,7 +458,7 @@ class WC_Tax {
foreach ( $tax_classes as $tax_class ) {
if ( in_array( $tax_class, $found_tax_classes ) ) {
$rates = $this->find_rates( array(
$rates = self::find_rates( array(
'country' => $country,
'state' => $state,
'postcode' => $postcode,
@ -477,7 +473,7 @@ class WC_Tax {
// If a single tax class is found, use it
} elseif ( sizeof( $found_tax_classes ) == 1 ) {
$rates = $this->find_rates( array(
$rates = self::find_rates( array(
'country' => $country,
'state' => $state,
'postcode' => $postcode,
@ -489,7 +485,7 @@ class WC_Tax {
// If no class rate are found, use standard rates
if ( ! $rates )
$rates = $this->find_rates( array(
$rates = self::find_rates( array(
'country' => $country,
'state' => $state,
'postcode' => $postcode,
@ -513,7 +509,7 @@ class WC_Tax {
* @param int key
* @return bool
*/
public function is_compound( $key ) {
public static function is_compound( $key ) {
global $wpdb;
return $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate_compound FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $key ) ) ? true : false;
}
@ -524,7 +520,7 @@ class WC_Tax {
* @param int key
* @return string
*/
public function get_rate_label( $key ) {
public static function get_rate_label( $key ) {
global $wpdb;
$rate_name = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate_name FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $key ) );
@ -532,7 +528,7 @@ class WC_Tax {
if ( ! $rate_name )
$rate_name = WC()->countries->tax_or_vat();
return apply_filters( 'woocommerce_rate_label', $rate_name, $key, $this );
return apply_filters( 'woocommerce_rate_label', $rate_name, $key );
}
/**
@ -542,7 +538,7 @@ class WC_Tax {
* @param mixed $key
* @return string
*/
public function get_rate_code( $key ) {
public static function get_rate_code( $key ) {
global $wpdb;
$rate = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $key ) );
@ -558,7 +554,7 @@ class WC_Tax {
$code[] = $rate->tax_rate_name ? $rate->tax_rate_name : 'TAX';
$code[] = absint( $rate->tax_rate_priority );
return apply_filters( 'woocommerce_rate_code', strtoupper( implode( '-', array_filter( $code ) ) ), $key, $this );
return apply_filters( 'woocommerce_rate_code', strtoupper( implode( '-', array_filter( $code ) ) ), $key );
}
/**
@ -567,7 +563,8 @@ class WC_Tax {
* @param array
* @return float
*/
public function get_tax_total( $taxes ) {
return array_sum( array_map( array( $this, 'round' ), $taxes ) );
public static function get_tax_total( $taxes ) {
return array_sum( array_map( array( __CLASS__, 'round' ), $taxes ) );
}
}
WC_Tax::init();

View File

@ -41,7 +41,7 @@ class WC_Template_Loader {
$file = 'single-product.php';
$find[] = $file;
$find[] = WC_TEMPLATE_PATH . $file;
$find[] = WC()->template_path() . $file;
} elseif ( is_product_taxonomy() ) {
@ -54,17 +54,17 @@ class WC_Template_Loader {
}
$find[] = 'taxonomy-' . $term->taxonomy . '-' . $term->slug . '.php';
$find[] = WC_TEMPLATE_PATH . 'taxonomy-' . $term->taxonomy . '-' . $term->slug . '.php';
$find[] = WC()->template_path() . 'taxonomy-' . $term->taxonomy . '-' . $term->slug . '.php';
$find[] = 'taxonomy-' . $term->taxonomy . '.php';
$find[] = WC_TEMPLATE_PATH . 'taxonomy-' . $term->taxonomy . '.php';
$find[] = WC()->template_path() . 'taxonomy-' . $term->taxonomy . '.php';
$find[] = $file;
$find[] = WC_TEMPLATE_PATH . $file;
$find[] = WC()->template_path() . $file;
} elseif ( is_post_type_archive( 'product' ) || is_page( wc_get_page_id( 'shop' ) ) ) {
$file = 'archive-product.php';
$find[] = $file;
$find[] = WC_TEMPLATE_PATH . $file;
$find[] = WC()->template_path() . $file;
}
@ -89,17 +89,17 @@ class WC_Template_Loader {
if ( get_post_type() !== 'product' )
return $template;
if ( file_exists( STYLESHEETPATH . '/' . WC_TEMPLATE_PATH . 'single-product-reviews.php' ))
return STYLESHEETPATH . '/' . WC_TEMPLATE_PATH . 'single-product-reviews.php';
elseif ( file_exists( TEMPLATEPATH . '/' . WC_TEMPLATE_PATH . 'single-product-reviews.php' ))
return TEMPLATEPATH . '/' . WC_TEMPLATE_PATH . 'single-product-reviews.php';
elseif ( file_exists( STYLESHEETPATH . '/' . 'single-product-reviews.php' ))
return STYLESHEETPATH . '/' . 'single-product-reviews.php';
elseif ( file_exists( TEMPLATEPATH . '/' . 'single-product-reviews.php' ))
return TEMPLATEPATH . '/' . 'single-product-reviews.php';
if ( file_exists( get_stylesheet_directory() . '/' . WC()->template_path() . 'single-product-reviews.php' ))
return get_stylesheet_directory() . '/' . WC()->template_path() . 'single-product-reviews.php';
elseif ( file_exists( get_template_directory() . '/' . WC()->template_path() . 'single-product-reviews.php' ))
return get_template_directory() . '/' . WC()->template_path() . 'single-product-reviews.php';
elseif ( file_exists( get_stylesheet_directory() . '/' . 'single-product-reviews.php' ))
return get_stylesheet_directory() . '/' . 'single-product-reviews.php';
elseif ( file_exists( get_template_directory() . '/' . 'single-product-reviews.php' ))
return get_template_directory() . '/' . 'single-product-reviews.php';
else
return WC()->plugin_path() . '/templates/single-product-reviews.php';
}
}
WC_Template_Loader::init();
WC_Template_Loader::init();

View File

@ -24,15 +24,15 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
* @return void
*/
public function __construct() {
$this->id = 'paypal';
$this->icon = apply_filters( 'woocommerce_paypal_icon', WC()->plugin_url() . '/assets/images/icons/paypal.png' );
$this->has_fields = false;
$this->order_button_text = __( 'Proceed to PayPal', 'woocommerce' );
$this->liveurl = 'https://www.paypal.com/cgi-bin/webscr';
$this->testurl = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
$this->method_title = __( 'PayPal', 'woocommerce' );
$this->notify_url = WC()->api_request_url( 'WC_Gateway_Paypal' );
$this->id = 'paypal';
$this->icon = apply_filters( 'woocommerce_paypal_icon', WC()->plugin_url() . '/assets/images/icons/paypal.png' );
$this->has_fields = false;
$this->order_button_text = __( 'Proceed to PayPal', 'woocommerce' );
$this->liveurl = 'https://www.paypal.com/cgi-bin/webscr';
$this->testurl = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
$this->method_title = __( 'PayPal', 'woocommerce' );
$this->view_transaction_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
$this->notify_url = WC()->api_request_url( 'WC_Gateway_Paypal' );
// Load the settings.
$this->init_form_fields();
@ -293,8 +293,8 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
'charset' => 'UTF-8',
'rm' => is_ssl() ? 2 : 1,
'upload' => 1,
'return' => esc_url( add_query_arg( 'utm_nooverride', '1', $this->get_return_url( $order ) ) ),
'cancel_return' => esc_url( $order->get_cancel_order_url() ),
'return' => urlencode( esc_url( add_query_arg( 'utm_nooverride', '1', $this->get_return_url( $order ) ) ) ),
'cancel_return' => urlencode( esc_url( $order->get_cancel_order_url() ) ),
'page_style' => $this->page_style,
'paymentaction' => $this->paymentaction,
'bn' => 'WooThemes_Cart',

View File

@ -107,4 +107,19 @@ $wpdb->query( "
AND tax.taxonomy = 'shop_order_status'
AND term.slug LIKE 'failed%';
"
);
);
// Update variations which manage stock
$update_variations = $wpdb->get_col( "
SELECT DISTINCT posts.ID FROM {$wpdb->posts} as posts
LEFT OUTER JOIN {$wpdb->postmeta} AS postmeta ON posts.ID = postmeta.post_id AND postmeta.meta_key = '_stock'
LEFT OUTER JOIN {$wpdb->postmeta} as postmeta2 ON posts.ID = postmeta2.post_id AND postmeta2.meta_key = '_manage_stock'
WHERE posts.post_type = 'product_variation'
AND postmeta.meta_value IS NOT NULL
AND postmeta.meta_value != ''
AND postmeta2.meta_value IS NULL
" );
foreach ( $update_variations as $variation_id ) {
add_post_meta( $variation_id, '_manage_stock', 'yes', true );
}

View File

@ -289,11 +289,3 @@ function wc_cart_totals_shipping_method_label( $method ) {
return apply_filters( 'woocommerce_cart_shipping_method_full_label', $label, $method );
}
/**
* See if we only ship to billing addresses
* @return bool
*/
function wc_ship_to_billing_address_only() {
return 'billing_only' === get_option( 'woocommerce_ship_to_destination' );
}

View File

@ -42,6 +42,87 @@ add_filter( 'woocommerce_short_description', 'shortcode_unautop' );
add_filter( 'woocommerce_short_description', 'prepend_attachment' );
add_filter( 'woocommerce_short_description', 'do_shortcode', 11 ); // AFTER wpautop()
/**
* Create a new order programmatically
*
* Returns a new order object on success which can then be used to add additonal data.
*
* @return WC_Order on success, WP_Error on failure
*/
function wc_create_order( $args = array() ) {
$default_args = array(
'status' => '',
'customer_id' => null,
'customer_note' => null,
'order_id' => 0
);
$args = wp_parse_args( $args, $default_args );
$order_data = array();
if ( $args['order_id'] > 0 ) {
$updating = true;
$order_data['ID'] = $args['order_id'];
} else {
$updating = false;
$order_data['post_type'] = 'shop_order';
$order_data['post_status'] = 'wc-' . apply_filters( 'woocommerce_default_order_status', 'pending' );
$order_data['ping_status'] = 'closed';
$order_data['post_author'] = 1;
$order_data['post_password'] = uniqid( 'order_' );
$order_data['post_title'] = sprintf( __( 'Order &ndash; %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) );
}
if ( $args['status'] ) {
if ( ! in_array( 'wc-' . $args['status'], array_keys( wc_get_order_statuses() ) ) ) {
return new WP_Error( __( 'Invalid order status', 'woocommerce' ) );
}
$order_data['post_status'] = 'wc-' . $args['status'];
}
if ( ! is_null( $args['customer_note'] ) ) {
$order_data['post_excerpt'] = $args['customer_note'];
}
if ( $updating ) {
$order_id = wp_update_post( $order_data );
} else {
$order_id = wp_insert_post( apply_filters( 'woocommerce_new_order_data', $order_data ), true );
}
if ( is_wp_error( $order_id ) ) {
return $order_id;
}
// Default order meta data.
if ( ! $updating ) {
update_post_meta( $order_id, '_order_key', 'wc_' . apply_filters( 'woocommerce_generate_order_key', uniqid( 'order_' ) ) );
update_post_meta( $order_id, '_order_currency', get_woocommerce_currency() );
update_post_meta( $order_id, '_prices_include_tax', get_option( 'woocommerce_prices_include_tax' ) );
update_post_meta( $order_id, '_customer_ip_address', isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'] );
update_post_meta( $order_id, '_customer_user_agent', isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '' );
update_post_meta( $order_id, '_customer_user', 0 );
}
if ( is_numeric( $args['customer_id'] ) ) {
update_post_meta( $order_id, '_customer_user', $args['customer_id'] );
}
return new WC_Order( $order_id );
}
/**
* Update an order. Uses wc_create_order.
* @param array $args
* @return WC_Error | WC_Order
*/
function wc_update_order( $args ) {
if ( ! $args['order_id'] ) {
return new WP_Error( __( 'Invalid order ID', 'woocommerce' ) );
}
return wc_create_order( $args );
}
/**
* Get template part (for templates like the shop-loop).
*
@ -173,6 +254,7 @@ function get_woocommerce_currencies() {
'COP' => __( 'Colombian Peso', 'woocommerce' ),
'CZK' => __( 'Czech Koruna', 'woocommerce' ),
'DKK' => __( 'Danish Krone', 'woocommerce' ),
'DOP' => __( 'Dominican Peso', 'woocommerce' ),
'EUR' => __( 'Euros', 'woocommerce' ),
'HKD' => __( 'Hong Kong Dollar', 'woocommerce' ),
'HRK' => __( 'Croatia kuna', 'woocommerce' ),
@ -278,6 +360,7 @@ function get_woocommerce_currency_symbol( $currency = '' ) {
case 'NGN' : $currency_symbol = '&#8358;'; break;
case 'HRK' : $currency_symbol = 'Kn'; break;
case 'EGP' : $currency_symbol = 'EGP'; break;
case 'DOP' : $currency_symbol = 'RD&#36;'; break;
default : $currency_symbol = ''; break;
}
@ -469,4 +552,63 @@ function wc_ms_protect_download_rewite_rules( $rewrite ) {
return $rule . $rewrite;
}
add_filter( 'mod_rewrite_rules', 'wc_ms_protect_download_rewite_rules' );
add_filter( 'mod_rewrite_rules', 'wc_ms_protect_download_rewite_rules' );
/**
* Remove order notes from wp_count_comments()
*
* @since 2.2
* @param object $stats
* @param int $post_id
* @return object
*/
function wc_remove_order_notes_from_wp_count_comments( $stats, $post_id ) {
global $wpdb;
if ( 0 === $post_id ) {
$count = wp_cache_get( 'comments-0', 'counts' );
if ( false !== $count ) {
return $count;
}
$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} WHERE comment_type != 'order_note' GROUP BY comment_approved", ARRAY_A );
$total = 0;
$approved = array( '0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed' );
foreach ( (array) $count as $row ) {
// Don't count post-trashed toward totals
if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
$total += $row['num_comments'];
}
if ( isset( $approved[ $row['comment_approved'] ] ) ) {
$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
}
}
$stats['total_comments'] = $total;
foreach ( $approved as $key ) {
if ( empty( $stats[ $key ] ) ) {
$stats[ $key ] = 0;
}
}
$stats = (object) $stats;
wp_cache_set( 'comments-0', $stats, 'counts' );
}
return $stats;
}
add_filter( 'wp_count_comments', 'wc_remove_order_notes_from_wp_count_comments', 10, 2 );
/**
* WooCommerce Core Supported Themes
*
* @since 2.2
* @return array
*/
function wc_get_core_supported_themes() {
return array( 'twentyfourteen', 'twentythirteen', 'twentyeleven', 'twentytwelve', 'twentyten' );
}

View File

@ -266,6 +266,15 @@ function wc_array_overlay( $a1, $a2 ) {
return $a1;
}
/**
* Formats a stock amount by running it through a filter
* @param int|float $amount
* @return int|float
*/
function wc_stock_amount( $amount ) {
return apply_filters( 'woocommerce_stock_amount', $amount );
}
/**
* Get the price format depending on the currency position
*

View File

@ -374,3 +374,11 @@ function wc_delete_shop_order_transients( $post_id = 0 ) {
do_action( 'woocommerce_delete_shop_order_transients', $post_id );
}
/**
* See if we only ship to billing addresses
* @return bool
*/
function wc_ship_to_billing_address_only() {
return 'billing_only' === get_option( 'woocommerce_ship_to_destination' );
}

View File

@ -30,10 +30,9 @@ function get_product( $the_product = false, $args = array() ) {
function wc_update_product_stock( $product_id, $new_stock_level ) {
$product = get_product( $product_id );
if ( $product->is_type( 'variation' ) )
$product->set_stock( $new_stock_level, true );
else
if ( $product->get_stock_quantity() !== $new_stock_level ) {
$product->set_stock( $new_stock_level );
}
}
/**
@ -44,7 +43,7 @@ function wc_update_product_stock( $product_id, $new_stock_level ) {
*/
function wc_update_product_stock_status( $product_id, $status ) {
$product = get_product( $product_id );
$product-> set_stock_status( $status );
$product->set_stock_status( $status );
}
/**
@ -84,24 +83,12 @@ function wc_delete_product_transients( $post_id = 0 ) {
return;
}
$post_id = absint( $post_id );
// Clear core transients
$transients_to_clear = array(
'wc\_products\_onsale',
'wc\_hidden\_product\_ids',
'wc\_hidden\_product\_ids\_search',
'wc\_attribute\_taxonomies',
'wc\_term\_counts',
'wc\_featured\_products'
'wc_products_onsale',
'wc_featured_products'
);
// Clear transients for which we don't have the name
$wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('\_transient\_wc\_uf\_pid\_%') OR `option_name` LIKE ('\_transient\_timeout\_wc\_uf\_pid\_%')" );
$wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('\_transient\_wc\_ln\_count\_%') OR `option_name` LIKE ('\_transient\_timeout\_wc\_ln\_count\_%')" );
$wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('\_transient\_wc\_ship\_%') OR `option_name` LIKE ('\_transient\_timeout\_wc\_ship\_%')" );
$wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('\_transient\_wc\_products\_will\_display\_%') OR `option_name` LIKE ('\_transient\_timeout\_wc\_products\_will\_display\_%')" );
// Clear product specific transients
$post_transient_names = array(
'wc_product_children_ids_',
@ -116,7 +103,7 @@ function wc_delete_product_transients( $post_id = 0 ) {
}
} else {
foreach( $post_transient_names as $transient ) {
$transient = str_replace('_', '\_', $transient);
$transient = str_replace( '_', '\_', $transient );
$wpdb->query( $wpdb->prepare( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE %s OR `option_name` LIKE %s", '\_transient\_' . $transient . '%', '\_transient\_timeout\_' . $transient . '%' ) );
}
}
@ -219,55 +206,55 @@ function wc_get_featured_product_ids() {
* @return string
*/
function wc_product_post_type_link( $permalink, $post ) {
// Abort if post is not a product
if ( $post->post_type !== 'product' )
return $permalink;
// Abort if post is not a product
if ( $post->post_type !== 'product' )
return $permalink;
// Abort early if the placeholder rewrite tag isn't in the generated URL
if ( false === strpos( $permalink, '%' ) )
return $permalink;
// Abort early if the placeholder rewrite tag isn't in the generated URL
if ( false === strpos( $permalink, '%' ) )
return $permalink;
// Get the custom taxonomy terms in use by this post
$terms = get_the_terms( $post->ID, 'product_cat' );
// Get the custom taxonomy terms in use by this post
$terms = get_the_terms( $post->ID, 'product_cat' );
if ( empty( $terms ) ) {
// If no terms are assigned to this post, use a string instead (can't leave the placeholder there)
$product_cat = _x( 'uncategorized', 'slug', 'woocommerce' );
} else {
// Replace the placeholder rewrite tag with the first term's slug
$first_term = array_shift( $terms );
$product_cat = $first_term->slug;
}
if ( empty( $terms ) ) {
// If no terms are assigned to this post, use a string instead (can't leave the placeholder there)
$product_cat = _x( 'uncategorized', 'slug', 'woocommerce' );
} else {
// Replace the placeholder rewrite tag with the first term's slug
$first_term = array_shift( $terms );
$product_cat = $first_term->slug;
}
$find = array(
'%year%',
'%monthnum%',
'%day%',
'%hour%',
'%minute%',
'%second%',
'%post_id%',
'%category%',
'%product_cat%'
);
$find = array(
'%year%',
'%monthnum%',
'%day%',
'%hour%',
'%minute%',
'%second%',
'%post_id%',
'%category%',
'%product_cat%'
);
$replace = array(
date_i18n( 'Y', strtotime( $post->post_date ) ),
date_i18n( 'm', strtotime( $post->post_date ) ),
date_i18n( 'd', strtotime( $post->post_date ) ),
date_i18n( 'H', strtotime( $post->post_date ) ),
date_i18n( 'i', strtotime( $post->post_date ) ),
date_i18n( 's', strtotime( $post->post_date ) ),
$post->ID,
$product_cat,
$product_cat
);
$replace = array(
date_i18n( 'Y', strtotime( $post->post_date ) ),
date_i18n( 'm', strtotime( $post->post_date ) ),
date_i18n( 'd', strtotime( $post->post_date ) ),
date_i18n( 'H', strtotime( $post->post_date ) ),
date_i18n( 'i', strtotime( $post->post_date ) ),
date_i18n( 's', strtotime( $post->post_date ) ),
$post->ID,
$product_cat,
$product_cat
);
$replace = array_map( 'sanitize_title', $replace );
$replace = array_map( 'sanitize_title', $replace );
$permalink = str_replace( $find, $replace, $permalink );
$permalink = str_replace( $find, $replace, $permalink );
return $permalink;
return $permalink;
}
add_filter( 'post_type_link', 'wc_product_post_type_link', 10, 2 );
@ -291,7 +278,7 @@ function wc_placeholder_img_src() {
function wc_placeholder_img( $size = 'shop_thumbnail' ) {
$dimensions = wc_get_image_size( $size );
return apply_filters('woocommerce_placeholder_img', '<img src="' . wc_placeholder_img_src() . '" alt="' . __( 'Placeholder', 'woocommerce' ) . '" width="' . esc_attr( $dimensions['width'] ) . '" class="woocommerce-placeholder wp-post-image" height="' . esc_attr( $dimensions['height'] ) . '" />' );
return apply_filters('woocommerce_placeholder_img', '<img src="' . wc_placeholder_img_src() . '" alt="' . __( 'Placeholder', 'woocommerce' ) . '" width="' . esc_attr( $dimensions['width'] ) . '" class="woocommerce-placeholder wp-post-image" height="' . esc_attr( $dimensions['height'] ) . '" />', $size, $dimensions );
}
/**
@ -320,11 +307,11 @@ function wc_get_formatted_variation( $variation, $flat = false ) {
}
// If this is a term slug, get the term's nice name
if ( taxonomy_exists( esc_attr( str_replace( 'attribute_', '', $name ) ) ) ) {
$term = get_term_by( 'slug', $value, esc_attr( str_replace( 'attribute_', '', $name ) ) );
if ( ! is_wp_error( $term ) && $term->name )
$value = $term->name;
}
if ( taxonomy_exists( esc_attr( str_replace( 'attribute_', '', $name ) ) ) ) {
$term = get_term_by( 'slug', $value, esc_attr( str_replace( 'attribute_', '', $name ) ) );
if ( ! is_wp_error( $term ) && $term->name )
$value = $term->name;
}
if ( $flat ) {
$variation_list[] = wc_attribute_label( str_replace( 'attribute_', '', $name ) ) . ': ' . urldecode( $value );
@ -380,8 +367,6 @@ function wc_scheduled_sales() {
update_post_meta( $product_id, '_sale_price_dates_to', '' );
}
wc_delete_product_transients( $product_id );
$parent = wp_get_post_parent_id( $product_id );
// Sync parent
@ -391,12 +376,14 @@ function wc_scheduled_sales() {
// Grouped products need syncing via a function
$this_product = get_product( $product_id );
if ( $this_product->is_type( 'simple' ) )
$this_product->grouped_product_sync();
wc_delete_product_transients( $parent );
if ( $this_product->is_type( 'simple' ) ) {
$this_product->grouped_product_sync();
}
}
}
delete_transient( 'wc_products_onsale' );
}
// Sales which are due to end
@ -421,8 +408,6 @@ function wc_scheduled_sales() {
update_post_meta( $product_id, '_sale_price_dates_from', '' );
update_post_meta( $product_id, '_sale_price_dates_to', '' );
wc_delete_product_transients( $product_id );
$parent = wp_get_post_parent_id( $product_id );
// Sync parent
@ -432,12 +417,13 @@ function wc_scheduled_sales() {
// Grouped products need syncing via a function
$this_product = get_product( $product_id );
if ( $this_product->is_type( 'simple' ) )
if ( $this_product->is_type( 'simple' ) ) {
$this_product->grouped_product_sync();
wc_delete_product_transients( $parent );
}
}
}
delete_transient( 'wc_products_onsale' );
}
}
add_action( 'woocommerce_scheduled_sales', 'wc_scheduled_sales' );
@ -450,8 +436,9 @@ add_action( 'woocommerce_scheduled_sales', 'wc_scheduled_sales' );
* @return array
*/
function wc_get_attachment_image_attributes( $attr ) {
if ( strstr( $attr['src'], 'woocommerce_uploads/' ) )
if ( strstr( $attr['src'], 'woocommerce_uploads/' ) ) {
$attr['src'] = wc_placeholder_img_src();
}
return $attr;
}
@ -505,3 +492,46 @@ function wc_track_product_view() {
}
add_action( 'template_redirect', 'wc_track_product_view', 20 );
/**
* Get product types
*
* @since 2.2
* @return array
*/
function wc_get_product_types() {
return (array) apply_filters( 'product_type_selector', array(
'simple' => __( 'Simple product', 'woocommerce' ),
'grouped' => __( 'Grouped product', 'woocommerce' ),
'external' => __( 'External/Affiliate product', 'woocommerce' ),
'variable' => __( 'Variable product', 'woocommerce' )
) );
}
/**
* Check if product sku is unique.
*
* @since 2.2
* @param int $product_id
* @param string $sku
* @return bool
*/
function wc_product_has_unique_sku( $product_id, $sku ) {
global $wpdb;
$sku_found = $wpdb->get_var( $wpdb->prepare( "
SELECT $wpdb->posts.ID
FROM $wpdb->posts
LEFT JOIN $wpdb->postmeta ON ( $wpdb->posts.ID = $wpdb->postmeta.post_id )
WHERE $wpdb->posts.post_type IN ( 'product', 'product_variation' )
AND $wpdb->posts.post_status = 'publish'
AND $wpdb->postmeta.meta_key = '_sku' AND $wpdb->postmeta.meta_value = '%s'
AND $wpdb->postmeta.post_id <> %d LIMIT 1
", $sku, $product_id ) );
if ( $sku_found ) {
return false;
} else {
return true;
}
}

View File

@ -497,6 +497,8 @@ function _wc_term_recount( $terms, $taxonomy, $callback = true, $terms_are_term_
// Update the count
update_woocommerce_term_meta( $term_id, 'product_count_' . $taxonomy->name, absint( $count ) );
}
delete_transient( 'wc_term_counts' );
}
/**
@ -525,8 +527,6 @@ function wc_recount_after_stock_change( $product_id ) {
_wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), false, false );
}
delete_transient( 'wc_term_counts' );
}
add_action( 'woocommerce_product_set_stock_status', 'wc_recount_after_stock_change' );

View File

@ -449,7 +449,7 @@ function wc_get_customer_available_downloads( $customer_id ) {
);
$downloads[] = array(
'download_url' => add_query_arg( array( 'download_file' => $result->product_id, 'order' => $result->order_key, 'email' => $result->user_email, 'key' => $result->download_id ), home_url( '/', 'http' ) ),
'download_url' => add_query_arg( array( 'download_file' => $result->product_id, 'order' => $result->order_key, 'email' => $result->user_email, 'key' => $result->download_id ), home_url( '/' ) ),
'download_id' => $result->download_id,
'product_id' => $result->product_id,
'download_name' => $download_name,

View File

@ -3,6 +3,10 @@
"title": "WooCommerce",
"version": "2.2.0",
"homepage": "http://www.woothemes.com/woocommerce/",
"repository": {
"type" : "git",
"url" : "https://github.com/woothemes/woocommerce.git"
},
"main": "Gruntfile.js",
"devDependencies": {
"grunt": "~0.4.2",

View File

@ -1,5 +1,5 @@
=== WooCommerce - excelling eCommerce ===
Contributors: woothemes, mikejolley, jameskoster, CoenJacobs
Contributors: woothemes, mikejolley, jameskoster
Tags: ecommerce, e-commerce, commerce, woothemes, wordpress ecommerce, affiliate, store, sales, sell, shop, shopping, cart, checkout, configurable, variable, widgets, reports, download, downloadable, digital, inventory, stock, reports, shipping, tax
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=paypal@woothemes.com&item_name=Donation+for+WooCommerce
Requires at least: 3.8
@ -133,6 +133,7 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc
* Feature - Allow backorders to be configured at variation level.
* Feature - Protect admins from shop manager users.
* Feature - Ability to add custom quantity using add_to_cart shortcode.
* Fix - Allow endpoint use on the front page.
* Tweak - Recalculate the cart totals, in the event a user registers during checkout and in doing so qualifies for any discounts.
* Tweak - Use `woocommerce_valid_order_statuses_for_payment` in `pay_action` too.
* Tweak - Added the possibility to translate the edit-address endpoint slug.
@ -167,6 +168,14 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc
* Localisation - Address format of Taiwan.
* Localisation - Removed language files from core to made the package lighter (see language pack downloader feature).
= 2.1.12 - 01/07/2014 =
* Fix - Total tax should be +, not -.
* Fix - Address format in plain text emails to use line breaks, not commas.
* Fix - order item count fix and tr class filters.
* Fix - Missing translations during checkout.
* Fix - Correctly clear transients, including sale transient.
* Tweak - woocommerce_get_order_item_totals_excl_free_fees hook.
= 2.1.11 - 09/06/2014 =
* Fix - Plain text email display of customer address.
* Fix - Saving tax rates threw notices (missing git cherry pick).

View File

@ -33,10 +33,13 @@ global $woocommerce;
?>
<li>
<?php if ( ! $_product->is_visible() ) { ?>
<?php echo str_replace( array( 'http:', 'https:' ), '', $thumbnail ) . $product_name; ?>
<?php } else { ?>
<a href="<?php echo get_permalink( $product_id ); ?>">
<?php echo str_replace( array( 'http:', 'https:' ), '', $thumbnail ) . $product_name; ?>
</a>
<?php } ?>
<?php echo WC()->cart->get_item_data( $cart_item ); ?>
<?php echo apply_filters( 'woocommerce_widget_cart_item_quantity', '<span class="quantity">' . sprintf( '%s &times; %s', $cart_item['quantity'], $product_price ) . '</span>', $cart_item, $cart_item_key ); ?>
@ -67,4 +70,4 @@ global $woocommerce;
<?php endif; ?>
<?php do_action( 'woocommerce_after_mini_cart' ); ?>
<?php do_action( 'woocommerce_after_mini_cart' ); ?>

View File

@ -24,7 +24,7 @@ if ( ! $checkout->enable_signup && ! $checkout->enable_guest_checkout && ! is_us
// filter hook for include new pages inside the payment method
$get_checkout_url = apply_filters( 'woocommerce_get_checkout_url', WC()->cart->get_checkout_url() ); ?>
<form name="checkout" method="post" class="checkout" action="<?php echo esc_url( $get_checkout_url ); ?>">
<form name="checkout" method="post" class="checkout" action="<?php echo esc_url( $get_checkout_url ); ?>" enctype="multipart/form-data">
<?php if ( sizeof( $checkout->checkout_fields ) > 0 ) : ?>

View File

@ -87,11 +87,13 @@ $header_content_h1 = "
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
<tr>
<td align="center" valign="top">
<?php
if ( $img = get_option( 'woocommerce_email_header_image' ) ) {
echo '<p style="margin-top:0;"><img src="' . esc_url( $img ) . '" alt="' . get_bloginfo( 'name' ) . '" /></p>';
}
?>
<div id="template_header_image">
<?php
if ( $img = get_option( 'woocommerce_email_header_image' ) ) {
echo '<p style="margin-top:0;"><img src="' . esc_url( $img ) . '" alt="' . get_bloginfo( 'name' ) . '" /></p>';
}
?>
</div>
<table border="0" cellpadding="0" cellspacing="0" width="600" id="template_container" style="<?php echo $template_container; ?>">
<tr>
<td align="center" valign="top">
@ -117,4 +119,4 @@ $header_content_h1 = "
<table border="0" cellpadding="20" cellspacing="0" width="100%">
<tr>
<td valign="top">
<div style="<?php echo $body_content_inner; ?>">
<div style="<?php echo $body_content_inner; ?>">

View File

@ -12,11 +12,11 @@ if ( ! defined( 'ABSPATH' ) ) {
}
echo "\n" . __( 'Billing address', 'woocommerce' ) . ":\n";
echo preg_replace( '#<br\s*/?>#i', ', ', $order->get_formatted_billing_address() ) . "\n\n";
echo preg_replace( '#<br\s*/?>#i', "\n", $order->get_formatted_billing_address() ) . "\n\n";
if ( ! wc_ship_to_billing_address_only() && $order->needs_shipping_address() && ( $shipping = $order->get_formatted_shipping_address() ) ) {
echo __( 'Shipping address', 'woocommerce' ) . ":\n";
echo preg_replace( '#<br\s*/?>#i', ', ', $shipping ) . "\n\n";
echo preg_replace( '#<br\s*/?>#i', "\n", $shipping ) . "\n\n";
}

View File

@ -7,6 +7,7 @@
* @version 1.6.4
*/
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
$template = get_option( 'template' );

View File

@ -29,7 +29,7 @@ if ( ! woocommerce_products_will_display() )
} elseif ( $total <= $per_page || -1 == $per_page ) {
printf( __( 'Showing all %d results', 'woocommerce' ), $total );
} else {
printf( _x( 'Showing %1$d%2$d of %3$d results', '%1$d = first, %2$d = last, %3$d = total', 'woocommerce' ), $first, $last, $total );
printf( _x( 'Showing %1$d&ndash;%2$d of %3$d results', '%1$d = first, %2$d = last, %3$d = total', 'woocommerce' ), $first, $last, $total );
}
?>
</p>
</p>

View File

@ -4,7 +4,7 @@
*
* @author WooThemes
* @package WooCommerce/Templates
* @version 1.6.4
* @version 2.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
@ -16,6 +16,8 @@ if ( ! defined( 'ABSPATH' ) ) {
<form action="" method="post">
<?php do_action( 'woocommerce_edit_account_form_start' ); ?>
<p class="form-row form-row-first">
<label for="account_first_name"><?php _e( 'First name', 'woocommerce' ); ?> <span class="required">*</span></label>
<input type="text" class="input-text" name="account_first_name" id="account_first_name" value="<?php echo esc_attr( $user->first_name ); ?>" />
@ -47,8 +49,14 @@ if ( ! defined( 'ABSPATH' ) ) {
</fieldset>
<div class="clear"></div>
<p><input type="submit" class="button" name="save_account_details" value="<?php _e( 'Save changes', 'woocommerce' ); ?>" /></p>
<?php do_action( 'woocommerce_edit_account_form' ); ?>
<?php wp_nonce_field( 'save_account_details' ); ?>
<input type="hidden" name="action" value="save_account_details" />
<p>
<?php wp_nonce_field( 'save_account_details' ); ?>
<input type="submit" class="button" name="save_account_details" value="<?php _e( 'Save changes', 'woocommerce' ); ?>" />
<input type="hidden" name="action" value="save_account_details" />
</p>
<?php do_action( 'woocommerce_edit_account_form_end' ); ?>
</form>

View File

@ -76,6 +76,11 @@ final class WooCommerce {
*/
public $customer = null;
/**
* @var WC_Order_Factory $order_factory
*/
public $order_factory = null;
/**
* Main WooCommerce Instance
*
@ -157,8 +162,8 @@ final class WooCommerce {
}
else switch( $key ) {
case 'template_url':
_deprecated_argument( 'Woocommerce->template_url', '2.1', 'WC_TEMPLATE_PATH constant' );
return WC_TEMPLATE_PATH;
_deprecated_argument( 'Woocommerce->template_url', '2.1', 'Use WC()->template_path()' );
return $this->template_path();
case 'messages':
_deprecated_argument( 'Woocommerce->messages', '2.1', 'Use wc_get_notices' );
return wc_get_notices( 'success' );
@ -229,27 +234,19 @@ final class WooCommerce {
private function define_constants() {
define( 'WC_PLUGIN_FILE', __FILE__ );
define( 'WC_VERSION', $this->version );
define( 'WOOCOMMERCE_VERSION', WC_VERSION ); // Backwards compat
if ( ! defined( 'WC_TEMPLATE_PATH' ) ) {
define( 'WC_TEMPLATE_PATH', $this->template_path() );
}
define( 'WOOCOMMERCE_VERSION', WC_VERSION ); // Backwards compatibility
if ( ! defined( 'WC_ROUNDING_PRECISION' ) ) {
define( 'WC_ROUNDING_PRECISION', 4 );
}
if ( ! defined( 'WC_TAX_ROUNDING_MODE' ) ) {
// 1 = PHP_ROUND_HALF_UP, 2 = PHP_ROUND_HALF_DOWN
define( 'WC_TAX_ROUNDING_MODE', get_option( 'woocommerce_prices_include_tax' ) === 'yes' ? 2 : 1 );
}
if ( ! defined( 'WC_DELIMITER' ) ) {
define( 'WC_DELIMITER', '|' );
}
if ( ! defined( 'WC_LOG_DIR' ) ) {
// Absolute path to the folder for logs. Defaults to 1 level above WordPress.
define( 'WC_LOG_DIR', dirname( ABSPATH ) . '/wc-logs/' );
}
}
@ -371,6 +368,7 @@ final class WooCommerce {
// Load class instances
$this->product_factory = new WC_Product_Factory(); // Product Factory to create new product instances
$this->order_factory = new WC_Order_Factory(); // Order Factory to create new order instances
$this->countries = new WC_Countries(); // Countries class
$this->integrations = new WC_Integrations(); // Integrations class
@ -432,15 +430,19 @@ final class WooCommerce {
* Ensure theme and server variable compatibility and setup image sizes..
*/
public function setup_environment() {
// Post thumbnail support
if ( ! current_theme_supports( 'post-thumbnails', 'product' ) ) {
add_theme_support( 'post-thumbnails' );
remove_post_type_support( 'post', 'thumbnail' );
remove_post_type_support( 'page', 'thumbnail' );
} else {
add_post_type_support( 'product', 'thumbnail' );
/**
* @deprecated 2.2 Use WC()->template_path()
*/
if ( ! defined( 'WC_TEMPLATE_PATH' ) ) {
define( 'WC_TEMPLATE_PATH', $this->template_path() );
}
// Post thumbnail support
if ( ! current_theme_supports( 'post-thumbnails' ) ) {
add_theme_support( 'post-thumbnails' );
}
add_post_type_support( 'product', 'thumbnail' );
// Add image sizes
$shop_thumbnail = wc_get_image_size( 'shop_thumbnail' );
$shop_catalog = wc_get_image_size( 'shop_catalog' );
@ -499,7 +501,7 @@ final class WooCommerce {
* @return string
*/
public function template_path() {
return apply_filters( 'WC_TEMPLATE_PATH', 'woocommerce/' );
return apply_filters( 'woocommerce_template_path', 'woocommerce/' );
}
/**