Merge branch 'master' of github.com:woothemes/woocommerce

This commit is contained in:
Claudio Sanches 2015-07-28 12:43:25 -03:00
commit 11f4956012
14 changed files with 179 additions and 131 deletions

View File

@ -29,6 +29,12 @@
return false; return false;
} ) } )
// Reload product variations data
.on( 'reload_product_variations', function() {
$product_variations = $form.data( 'product_variations' );
$use_ajax = $product_variations === false;
} )
// Reset product data // Reset product data
.on( 'reset_data', function() { .on( 'reset_data', function() {
var to_reset = { var to_reset = {

File diff suppressed because one or more lines are too long

View File

@ -1859,7 +1859,7 @@ abstract class WC_Abstract_Order {
if ( 'excl' == $tax_display ) { if ( 'excl' == $tax_display ) {
$total_rows[ 'fee_' . $id ] = array( $total_rows[ 'fee_' . $id ] = array(
'label' => $fee['name'] . ':', 'label' => ( $fee['name'] ? $fee['name'] : __( 'Fee', 'woocommerce' ) ) . ':',
'value' => wc_price( $fee['line_total'], array('currency' => $this->get_order_currency()) ) 'value' => wc_price( $fee['line_total'], array('currency' => $this->get_order_currency()) )
); );

View File

@ -389,16 +389,6 @@ if ( ! defined( 'ABSPATH' ) ) {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr>
<td data-export-label="API Enabled"><?php _e( 'API Enabled', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo '<a href="#" class="help_tip" data-tip="' . esc_attr__( 'Does your site have REST API enabled?', 'woocommerce' ) . '">[?]</a>'; ?></td>
<td><?php echo 'yes' === get_option( 'woocommerce_api_enabled' ) ? '<mark class="yes">'.'&#10004;'.'</mark>' : '<mark class="no">'.'&ndash;'.'</mark>'; ?></td>
</tr>
<tr>
<td data-export-label="API Version"><?php _e( 'API Version', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo '<a href="#" class="help_tip" data-tip="' . esc_attr__( 'What version of the REST API does your site use?', 'woocommerce' ) . '">[?]</a>'; ?></td>
<td><?php echo WC_API::VERSION ?></td>
</tr>
<tr> <tr>
<td data-export-label="Force SSL"><?php _e( 'Force SSL', 'woocommerce' ); ?>:</td> <td data-export-label="Force SSL"><?php _e( 'Force SSL', 'woocommerce' ); ?>:</td>
<td class="help"><?php echo '<a href="#" class="help_tip" data-tip="' . esc_attr__( 'Does your site force a SSL Certificate for transactions?', 'woocommerce' ) . '">[?]</a>'; ?></td> <td class="help"><?php echo '<a href="#" class="help_tip" data-tip="' . esc_attr__( 'Does your site force a SSL Certificate for transactions?', 'woocommerce' ) . '">[?]</a>'; ?></td>

View File

@ -2527,31 +2527,7 @@ class WC_AJAX {
} }
// Add the variation attributes // Add the variation attributes
foreach ( $variation_meta as $key => $value ) { $variation_data = array_merge( $variation_data, wc_get_product_variation_attributes( $variation_id ) );
if ( 0 !== strpos( $key, 'attribute_' ) ) {
continue;
}
/**
* Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
* Attempt to get full version of the text attribute from the parent.
*/
if ( sanitize_title( $value[0] ) === $value[0] && version_compare( get_post_meta( $product_id, '_product_version', true ), '2.4.0', '<' ) ) {
foreach ( $attributes as $attribute ) {
if ( $key !== 'attribute_' . sanitize_title( $attribute['name'] ) ) {
continue;
}
$text_attributes = wc_get_text_attributes( $attribute['value'] );
foreach ( $text_attributes as $text_attribute ) {
if ( sanitize_title( $text_attribute ) === $value[0] ) {
$value[0] = $text_attribute;
}
}
}
}
$variation_data[ $key ] = $value[0];
}
// Formatting // Formatting
$variation_data['_regular_price'] = wc_format_localized_price( $variation_data['_regular_price'] ); $variation_data['_regular_price'] = wc_format_localized_price( $variation_data['_regular_price'] );

View File

@ -622,20 +622,6 @@ class WC_Form_Handler {
// Allow if valid // Allow if valid
if ( '' === $valid_value || $valid_value === $value ) { if ( '' === $valid_value || $valid_value === $value ) {
// Pre 2.4 handling where 'slugs' were saved instead of the full text attribute
if ( ! $attribute['is_taxonomy'] ) {
if ( $value === sanitize_title( $value ) && version_compare( get_post_meta( $product_id, '_product_version', true ), '2.4.0', '<' ) ) {
$text_attributes = wc_get_text_attributes( $attribute['value'] );
foreach ( $text_attributes as $text_attribute ) {
if ( sanitize_title( $text_attribute ) === $value ) {
$value = $text_attribute;
break;
}
}
}
}
$variations[ $taxonomy ] = $value; $variations[ $taxonomy ] = $value;
continue; continue;
} }

View File

@ -603,6 +603,53 @@ class WC_Product_Variable extends WC_Product {
wc_update_product_stock_status( $product_id, $stock_status ); wc_update_product_stock_status( $product_id, $stock_status );
} }
/**
* Sync the variable product's attributes with the variations
*/
public static function sync_attributes( $product_id, $children = false ) {
if ( ! $children ) {
$children = get_posts( array(
'post_parent' => $product_id,
'posts_per_page'=> -1,
'post_type' => 'product_variation',
'fields' => 'ids',
'post_status' => 'any'
) );
}
/**
* Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
* Attempt to get full version of the text attribute from the parent and UPDATE meta.
*/
if ( version_compare( get_post_meta( $product_id, '_product_version', true ), '2.4.0', '<' ) ) {
$parent_attributes = array_filter( (array) get_post_meta( $product_id, '_product_attributes', true ) );
foreach ( $children as $child_id ) {
$all_meta = get_post_meta( $child_id );
foreach ( $all_meta as $name => $value ) {
if ( 0 !== strpos( $name, 'attribute_' ) ) {
continue;
}
if ( sanitize_title( $value[0] ) === $value[0] ) {
foreach ( $parent_attributes as $attribute ) {
if ( $name !== 'attribute_' . sanitize_title( $attribute['name'] ) ) {
continue;
}
$text_attributes = wc_get_text_attributes( $attribute['value'] );
foreach ( $text_attributes as $text_attribute ) {
if ( sanitize_title( $text_attribute ) === $value[0] ) {
update_post_meta( $child_id, $name, $text_attribute );
break;
}
}
}
}
}
}
}
}
/** /**
* Sync the variable product with it's children * Sync the variable product with it's children
*/ */
@ -703,6 +750,9 @@ class WC_Product_Variable extends WC_Product {
update_post_meta( $product_id, '_price', $min_price ); update_post_meta( $product_id, '_price', $min_price );
delete_transient( 'wc_products_onsale' ); delete_transient( 'wc_products_onsale' );
// Sync attributes
self::sync_attributes( $product_id, $children );
do_action( 'woocommerce_variable_product_sync', $product_id, $children ); do_action( 'woocommerce_variable_product_sync', $product_id, $children );
} }
} }

View File

@ -135,55 +135,7 @@ class WC_Product_Variation extends WC_Product {
} }
} elseif ( 'variation_data' === $key ) { } elseif ( 'variation_data' === $key ) {
// Build variation data from meta return $this->variation_data = wc_get_product_variation_attributes( $this->variation_id );
$all_meta = get_post_meta( $this->variation_id );
$parent_attributes = $this->parent->get_attributes();
$found_parent_attributes = array();
// The variation data array
$this->variation_data = array();
// Compare to parent variable product attributes and ensure they match
foreach ( $parent_attributes as $attribute_name => $options ) {
$attribute = 'attribute_' . sanitize_title( $attribute_name );
$found_parent_attributes[] = $attribute;
if ( ! array_key_exists( $attribute, $this->variation_data ) ) {
$this->variation_data[ $attribute ] = ''; // Add it - 'any' will be asumed
}
}
// Get the variation attributes from meta
foreach ( $all_meta as $name => $value ) {
// Only look at valid attribute meta, and also compare variation level attributes and remove any which do not exist at parent level
if ( 0 !== strpos( $name, 'attribute_' ) || ! in_array( $name, $found_parent_attributes ) ) {
unset( $this->variation_data[ $name ] );
continue;
}
/**
* Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
* Attempt to get full version of the text attribute from the parent.
*/
if ( sanitize_title( $value[0] ) === $value[0] && version_compare( get_post_meta( $this->id, '_product_version', true ), '2.4.0', '<' ) ) {
$attributes = $this->parent->get_attributes();
foreach ( $attributes as $attribute ) {
if ( $name !== 'attribute_' . sanitize_title( $attribute['name'] ) ) {
continue;
}
$text_attributes = wc_get_text_attributes( $attribute['value'] );
foreach ( $text_attributes as $text_attribute ) {
if ( sanitize_title( $text_attribute ) === $value[0] ) {
$value[0] = $text_attribute;
}
}
}
}
$this->variation_data[ $name ] = $value[0];
}
return $this->variation_data;
} elseif ( 'variation_has_stock' === $key ) { } elseif ( 'variation_has_stock' === $key ) {
return $this->managing_stock(); return $this->managing_stock();
@ -211,7 +163,7 @@ class WC_Product_Variation extends WC_Product {
* @return string * @return string
*/ */
public function get_permalink( $cart_item = null ) { public function get_permalink( $cart_item = null ) {
return add_query_arg( array_filter( isset( $cart_item['variation'] ) ? $cart_item['variation'] : $this->variation_data ), get_permalink( $this->id ) ); return add_query_arg( array_map( 'urlencode', array_filter( isset( $cart_item['variation'] ) ? $cart_item['variation'] : $this->variation_data ) ), get_permalink( $this->id ) );
} }
/** /**

View File

@ -177,7 +177,8 @@ class WC_Gateway_Paypal_Request {
$this->delete_line_items(); $this->delete_line_items();
$this->add_line_item( $this->get_order_item_names( $order ), 1, $this->number_format( $order->get_total() - $this->round( $order->get_total_shipping() + $order->get_shipping_tax(), $order ), $order ), $order->get_order_number() ); $all_items_name = $this->get_order_item_names( $order );
$this->add_line_item( $all_items_name ? $all_items_name : __( 'Order', 'woocommerce' ), 1, $this->number_format( $order->get_total() - $this->round( $order->get_total_shipping() + $order->get_shipping_tax(), $order ), $order ), $order->get_order_number() );
$this->add_line_item( sprintf( __( 'Shipping via %s', 'woocommerce' ), ucwords( $order->get_shipping_method() ) ), 1, $this->number_format( $order->get_total_shipping() + $order->get_shipping_tax(), $order ) ); $this->add_line_item( sprintf( __( 'Shipping via %s', 'woocommerce' ), ucwords( $order->get_shipping_method() ) ), 1, $this->number_format( $order->get_total_shipping() + $order->get_shipping_tax(), $order ) );
$line_item_args = $this->get_line_items(); $line_item_args = $this->get_line_items();
@ -284,11 +285,11 @@ class WC_Gateway_Paypal_Request {
protected function add_line_item( $item_name, $quantity = 1, $amount = 0, $item_number = '' ) { protected function add_line_item( $item_name, $quantity = 1, $amount = 0, $item_number = '' ) {
$index = ( sizeof( $this->line_items ) / 4 ) + 1; $index = ( sizeof( $this->line_items ) / 4 ) + 1;
if ( ! $item_name || $amount < 0 || $index > 9 ) { if ( $amount < 0 || $index > 9 ) {
return false; return false;
} }
$this->line_items[ 'item_name_' . $index ] = html_entity_decode( wc_trim_string( $item_name, 127 ), ENT_NOQUOTES, 'UTF-8' ); $this->line_items[ 'item_name_' . $index ] = html_entity_decode( wc_trim_string( $item_name ? $item_name : __( 'Item', 'woocommerce' ), 127 ), ENT_NOQUOTES, 'UTF-8' );
$this->line_items[ 'quantity_' . $index ] = $quantity; $this->line_items[ 'quantity_' . $index ] = $quantity;
$this->line_items[ 'amount_' . $index ] = $amount; $this->line_items[ 'amount_' . $index ] = $amount;
$this->line_items[ 'item_number_' . $index ] = $item_number; $this->line_items[ 'item_number_' . $index ] = $item_number;

View File

@ -613,3 +613,59 @@ function _wc_save_product_price( $product_id, $regular_price, $sale_price = '',
update_post_meta( $product_id, '_sale_price_dates_to', '' ); update_post_meta( $product_id, '_sale_price_dates_to', '' );
} }
} }
/**
* Get attibutes/data for an individual variation from the database and maintain it's integrity.
* @since 2.4.0
* @param int $variation_id
* @return array
*/
function wc_get_product_variation_attributes( $variation_id ) {
// Build variation data from meta
$all_meta = get_post_meta( $variation_id );
$parent_id = wp_get_post_parent_id( $variation_id );
$parent_attributes = array_filter( (array) get_post_meta( $parent_id, '_product_attributes', true ) );
$found_parent_attributes = array();
$variation_attributes = array();
// Compare to parent variable product attributes and ensure they match
foreach ( $parent_attributes as $attribute_name => $options ) {
$attribute = 'attribute_' . sanitize_title( $attribute_name );
$found_parent_attributes[] = $attribute;
if ( ! array_key_exists( $attribute, $variation_attributes ) ) {
$variation_attributes[ $attribute ] = ''; // Add it - 'any' will be asumed
}
}
// Get the variation attributes from meta
foreach ( $all_meta as $name => $value ) {
// Only look at valid attribute meta, and also compare variation level attributes and remove any which do not exist at parent level
if ( 0 !== strpos( $name, 'attribute_' ) || ! in_array( $name, $found_parent_attributes ) ) {
unset( $variation_attributes[ $name ] );
continue;
}
/**
* Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
* Attempt to get full version of the text attribute from the parent.
*/
if ( sanitize_title( $value[0] ) === $value[0] && version_compare( get_post_meta( $parent_id, '_product_version', true ), '2.4.0', '<' ) ) {
foreach ( $parent_attributes as $attribute ) {
if ( $name !== 'attribute_' . sanitize_title( $attribute['name'] ) ) {
continue;
}
$text_attributes = wc_get_text_attributes( $attribute['value'] );
foreach ( $text_attributes as $text_attribute ) {
if ( sanitize_title( $text_attribute ) === $value[0] ) {
$value[0] = $text_attribute;
break;
}
}
}
}
$variation_attributes[ $name ] = $value[0];
}
return $variation_attributes;
}

View File

@ -1866,6 +1866,35 @@ if ( ! function_exists( 'woocommerce_output_auth_footer' ) ) {
} }
} }
if ( ! function_exists( 'woocommerce_single_variation' ) ) {
/**
* Output placeholders for the single variation.
*/
function woocommerce_single_variation() {
echo '<div class="single_variation"></div>';
}
}
if ( ! function_exists( 'woocommerce_single_variation_add_to_cart_button' ) ) {
/**
* Output the add to cart button for variations.
*/
function woocommerce_single_variation_add_to_cart_button() {
global $product;
?>
<div class="variations_button">
<?php woocommerce_quantity_input( array( 'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( $_POST['quantity'] ) : 1 ) ); ?>
<button type="submit" class="single_add_to_cart_button button alt"><?php echo esc_html( $product->single_add_to_cart_text() ); ?></button>
<input type="hidden" name="add-to-cart" value="<?php echo absint( $product->id ); ?>" />
<input type="hidden" name="product_id" value="<?php echo absint( $product->id ); ?>" />
<input type="hidden" name="variation_id" class="variation_id" value="" />
</div>
<?php
}
}
if ( ! function_exists( 'wc_dropdown_variation_attribute_options' ) ) { if ( ! function_exists( 'wc_dropdown_variation_attribute_options' ) ) {
/** /**

View File

@ -149,6 +149,8 @@ add_action( 'woocommerce_simple_add_to_cart', 'woocommerce_simple_add_to_cart',
add_action( 'woocommerce_grouped_add_to_cart', 'woocommerce_grouped_add_to_cart', 30 ); add_action( 'woocommerce_grouped_add_to_cart', 'woocommerce_grouped_add_to_cart', 30 );
add_action( 'woocommerce_variable_add_to_cart', 'woocommerce_variable_add_to_cart', 30 ); add_action( 'woocommerce_variable_add_to_cart', 'woocommerce_variable_add_to_cart', 30 );
add_action( 'woocommerce_external_add_to_cart', 'woocommerce_external_add_to_cart', 30 ); add_action( 'woocommerce_external_add_to_cart', 'woocommerce_external_add_to_cart', 30 );
add_action( 'woocommerce_single_variation', 'woocommerce_single_variation', 10 );
add_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20 );
/** /**
* Pagination after shop loops * Pagination after shop loops

View File

@ -50,7 +50,7 @@ class WC_Widget_Cart extends WC_Widget {
* @param array $instance * @param array $instance
*/ */
public function widget( $args, $instance ) { public function widget( $args, $instance ) {
if ( is_cart() || is_checkout() ) { if ( apply_filters( 'woocommerce_widget_cart_is_hidden', is_cart() || is_checkout() ) ) {
return; return;
} }

View File

@ -6,19 +6,22 @@
* @package WooCommerce/Templates * @package WooCommerce/Templates
* @version 2.4.0 * @version 2.4.0
*/ */
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
global $product, $post; global $product;
$attribute_keys = array_keys( $attributes );
do_action( 'woocommerce_before_add_to_cart_form' ); ?> do_action( 'woocommerce_before_add_to_cart_form' ); ?>
<form class="variations_form cart" method="post" enctype='multipart/form-data' data-product_id="<?php echo $post->ID; ?>" data-product_variations="<?php echo esc_attr( json_encode( $available_variations ) ) ?>"> <form class="variations_form cart" method="post" enctype='multipart/form-data' data-product_id="<?php echo absint( $product->id ); ?>" data-product_variations="<?php echo esc_attr( json_encode( $available_variations ) ) ?>">
<?php do_action( 'woocommerce_before_variations_form' ); ?> <?php do_action( 'woocommerce_before_variations_form' ); ?>
<?php if ( ! empty( $available_variations ) || false === $available_variations ) : ?> <?php if ( empty( $available_variations ) && false !== $available_variations ) : ?>
<p class="stock out-of-stock"><?php _e( 'This product is currently out of stock and unavailable.', 'woocommerce' ); ?></p>
<?php else : ?>
<table class="variations" cellspacing="0"> <table class="variations" cellspacing="0">
<tbody> <tbody>
<?php foreach ( $attributes as $attribute_name => $options ) : ?> <?php foreach ( $attributes as $attribute_name => $options ) : ?>
@ -26,44 +29,41 @@ do_action( 'woocommerce_before_add_to_cart_form' ); ?>
<td class="label"><label for="<?php echo sanitize_title( $attribute_name ); ?>"><?php echo wc_attribute_label( $attribute_name ); ?></label></td> <td class="label"><label for="<?php echo sanitize_title( $attribute_name ); ?>"><?php echo wc_attribute_label( $attribute_name ); ?></label></td>
<td class="value"> <td class="value">
<?php <?php
$selected = isset( $_REQUEST[ 'attribute_' . sanitize_title( $attribute_name ) ] ) ? $_REQUEST[ 'attribute_' . sanitize_title( $attribute_name ) ] : $product->get_variation_default_attribute( $attribute_name ); $selected = isset( $_REQUEST[ 'attribute_' . sanitize_title( $attribute_name ) ] ) ? wc_clean( $_REQUEST[ 'attribute_' . sanitize_title( $attribute_name ) ] ) : $product->get_variation_default_attribute( $attribute_name );
wc_dropdown_variation_attribute_options( array( 'options' => $options, 'attribute' => $attribute_name, 'product' => $product, 'selected' => $selected ) ); wc_dropdown_variation_attribute_options( array( 'options' => $options, 'attribute' => $attribute_name, 'product' => $product, 'selected' => $selected ) );
echo end( $attribute_keys ) === $attribute_name ? '<a class="reset_variations" href="#">' . __( 'Clear selection', 'woocommerce' ) . '</a>' : '';
?> ?>
</td> </td>
</tr> </tr>
<?php endforeach;?> <?php endforeach;?>
<tr class="woocommerce-reset-row">
<th>&nbsp;</th>
<td><a class="reset_variations" href="#"><?php _e( 'Clear selection', 'woocommerce' ); ?></a></td>
</tr>
</tbody> </tbody>
</table> </table>
<?php do_action( 'woocommerce_before_add_to_cart_button' ); ?> <?php do_action( 'woocommerce_before_add_to_cart_button' ); ?>
<div class="single_variation_wrap" style="display:none;"> <div class="single_variation_wrap" style="display:none;">
<?php do_action( 'woocommerce_before_single_variation' ); ?> <?php
/**
* woocommerce_before_single_variation Hook
*/
do_action( 'woocommerce_before_single_variation' );
<div class="single_variation"></div> /**
* woocommerce_single_variation hook. Used to output the cart button and placeholder for variation data.
* @since 2.4.0
* @hooked woocommerce_single_variation - 10 Empty div for variation data.
* @hooked woocommerce_single_variation_add_to_cart_button - 20 Qty and cart button.
*/
do_action( 'woocommerce_single_variation' );
<?php do_action( 'woocommerce_before_variations_button' ); ?> /**
<div class="variations_button"> * woocommerce_after_single_variation Hook
<?php woocommerce_quantity_input( array( 'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( $_POST['quantity'] ) : 1 ) ); ?> */
<button type="submit" class="single_add_to_cart_button button alt"><?php echo esc_html( $product->single_add_to_cart_text() ); ?></button> do_action( 'woocommerce_after_single_variation' );
</div> ?>
<?php do_action( 'woocommerce_after_variations_button' ); ?>
<input type="hidden" name="add-to-cart" value="<?php echo $product->id; ?>" />
<input type="hidden" name="product_id" value="<?php echo esc_attr( $post->ID ); ?>" />
<input type="hidden" name="variation_id" class="variation_id" value="" />
<?php do_action( 'woocommerce_after_single_variation' ); ?>
</div> </div>
<?php do_action( 'woocommerce_after_add_to_cart_button' ); ?> <?php do_action( 'woocommerce_after_add_to_cart_button' ); ?>
<?php else : ?>
<p class="stock out-of-stock"><?php _e( 'This product is currently out of stock and unavailable.', 'woocommerce' ); ?></p>
<?php endif; ?> <?php endif; ?>
<?php do_action( 'woocommerce_after_variations_form' ); ?> <?php do_action( 'woocommerce_after_variations_form' ); ?>