Merge branch 'master' into feature/network-order-widget

This commit is contained in:
Chris Marslender 2017-11-17 15:27:52 -07:00
commit 4d856955d9
No known key found for this signature in database
GPG Key ID: 5A3FF8E135EABA2C
23 changed files with 532 additions and 86 deletions

View File

@ -472,13 +472,13 @@ jQuery( function ( $ ) {
if ( value != null ) {
wc_meta_boxes_order_items.block();
var data = {
var data = $.extend( {}, wc_meta_boxes_order_items.get_taxable_address(), {
action : 'woocommerce_add_order_fee',
dataType: 'json',
order_id: woocommerce_admin_meta_boxes.post_id,
security: woocommerce_admin_meta_boxes.order_item_nonce,
amount : value
};
} );
$.post( woocommerce_admin_meta_boxes.ajax_url, data, function( response ) {
if ( response.success ) {
@ -543,12 +543,13 @@ jQuery( function ( $ ) {
wc_meta_boxes_order_items.block();
var data = {
var data = $.extend( {}, wc_meta_boxes_order_items.get_taxable_address(), {
order_id : woocommerce_admin_meta_boxes.post_id,
order_item_ids: order_item_id,
action : 'woocommerce_remove_order_item',
security : woocommerce_admin_meta_boxes.order_item_nonce
};
} );
// Check if items have changed, if so pass them through so we can save them before deleting.
if ( 'true' === $( 'button.cancel-action' ).attr( 'data-reload' ) ) {
data.items = $( 'table.woocommerce_order_items :input[name], .wc-order-totals-items :input[name]' ).serialize();
@ -607,39 +608,44 @@ jQuery( function ( $ ) {
return false;
},
get_taxable_address: function() {
var country = '';
var state = '';
var postcode = '';
var city = '';
if ( 'shipping' === woocommerce_admin_meta_boxes.tax_based_on ) {
country = $( '#_shipping_country' ).val();
state = $( '#_shipping_state' ).val();
postcode = $( '#_shipping_postcode' ).val();
city = $( '#_shipping_city' ).val();
}
if ( 'billing' === woocommerce_admin_meta_boxes.tax_based_on || ! country ) {
country = $( '#_billing_country' ).val();
state = $( '#_billing_state' ).val();
postcode = $( '#_billing_postcode' ).val();
city = $( '#_billing_city' ).val();
}
return {
country: country,
state: state,
postcode: postcode,
city: city
};
},
recalculate: function() {
if ( window.confirm( woocommerce_admin_meta_boxes.calc_totals ) ) {
wc_meta_boxes_order_items.block();
var country = '';
var state = '';
var postcode = '';
var city = '';
if ( 'shipping' === woocommerce_admin_meta_boxes.tax_based_on ) {
country = $( '#_shipping_country' ).val();
state = $( '#_shipping_state' ).val();
postcode = $( '#_shipping_postcode' ).val();
city = $( '#_shipping_city' ).val();
}
if ( 'billing' === woocommerce_admin_meta_boxes.tax_based_on || ! country ) {
country = $( '#_billing_country' ).val();
state = $( '#_billing_state' ).val();
postcode = $( '#_billing_postcode' ).val();
city = $( '#_billing_city' ).val();
}
var data = {
var data = $.extend( {}, wc_meta_boxes_order_items.get_taxable_address(), {
action: 'woocommerce_calc_line_taxes',
order_id: woocommerce_admin_meta_boxes.post_id,
items: $( 'table.woocommerce_order_items :input[name], .wc-order-totals-items :input[name]' ).serialize(),
country: country,
state: state,
postcode: postcode,
city: city,
security: woocommerce_admin_meta_boxes.calc_totals_nonce
};
} );
$.ajax({
url: woocommerce_admin_meta_boxes.ajax_url,

File diff suppressed because one or more lines are too long

View File

@ -1762,6 +1762,17 @@ class WC_Product extends WC_Abstract_Legacy_Product {
return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'Read more', 'woocommerce' ), $this );
}
/**
* Get the add to cart button text description - used in aria tags.
*
* @since 3.3.0
* @return string
*/
public function add_to_cart_description() {
/* translators: %s: Product title */
return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'Read more about “%s”', 'woocommerce' ), $this->get_name() ), $this );
}
/**
* Returns the main product image.
*

View File

@ -1265,8 +1265,14 @@ class WC_Admin_Setup_Wizard {
<form method="post" class="wc-wizard-payment-gateway-form">
<p>
<?php printf(
esc_html__(
'WooCommerce can accept both online and offline payments. <a href="%1$s" target="_blank">Additional payment methods</a> can be installed later.', 'woocommerce'
wp_kses(
__( 'WooCommerce can accept both online and offline payments. <a href="%1$s" target="_blank">Additional payment methods</a> can be installed later.', 'woocommerce' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
),
)
),
esc_url( admin_url( 'admin.php?page=wc-addons&view=payment-gateways' ) )
); ?>

View File

@ -1169,7 +1169,7 @@ class WC_REST_Orders_Controller extends WC_REST_Legacy_Orders_Controller {
),
'tax_class' => array(
'description' => __( 'Tax class of product.', 'woocommerce' ),
'type' => 'integer',
'type' => 'string',
'context' => array( 'view', 'edit' ),
),
'subtotal' => array(
@ -1254,7 +1254,7 @@ class WC_REST_Orders_Controller extends WC_REST_Legacy_Orders_Controller {
),
'price' => array(
'description' => __( 'Product price.', 'woocommerce' ),
'type' => 'string',
'type' => 'number',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),

View File

@ -1238,7 +1238,7 @@ class WC_REST_Orders_V1_Controller extends WC_REST_Posts_Controller {
),
'tax_class' => array(
'description' => __( 'Tax class of product.', 'woocommerce' ),
'type' => 'integer',
'type' => 'string',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),

View File

@ -913,9 +913,15 @@ class WC_AJAX {
}
try {
$order_id = absint( $_POST['order_id'] );
$amount = wc_clean( $_POST['amount'] );
$order = wc_get_order( $order_id );
$order_id = absint( $_POST['order_id'] );
$amount = wc_clean( $_POST['amount'] );
$order = wc_get_order( $order_id );
$calculate_tax_args = array(
'country' => strtoupper( wc_clean( $_POST['country'] ) ),
'state' => strtoupper( wc_clean( $_POST['state'] ) ),
'postcode' => strtoupper( wc_clean( $_POST['postcode'] ) ),
'city' => strtoupper( wc_clean( $_POST['city'] ) ),
);
if ( ! $order ) {
throw new exception( __( 'Invalid order', 'woocommerce' ) );
@ -936,7 +942,8 @@ class WC_AJAX {
$fee->set_name( sprintf( __( '%s fee', 'woocommerce' ), $formatted_amount ) );
$order->add_item( $fee );
$order->calculate_totals( true );
$order->calculate_taxes( $calculate_tax_args );
$order->calculate_totals( false );
$order->save();
ob_start();
@ -1084,9 +1091,15 @@ class WC_AJAX {
}
try {
$order_id = absint( $_POST['order_id'] );
$order_item_ids = $_POST['order_item_ids'];
$items = ( ! empty( $_POST['items'] ) ) ? $_POST['items'] : '';
$order_id = absint( $_POST['order_id'] );
$order_item_ids = $_POST['order_item_ids'];
$items = ( ! empty( $_POST['items'] ) ) ? $_POST['items']: '';
$calculate_tax_args = array(
'country' => strtoupper( wc_clean( $_POST['country'] ) ),
'state' => strtoupper( wc_clean( $_POST['state'] ) ),
'postcode' => strtoupper( wc_clean( $_POST['postcode'] ) ),
'city' => strtoupper( wc_clean( $_POST['city'] ) ),
);
if ( ! is_array( $order_item_ids ) && is_numeric( $order_item_ids ) ) {
$order_item_ids = array( $order_item_ids );
@ -1107,7 +1120,8 @@ class WC_AJAX {
}
$order = wc_get_order( $order_id );
$order->calculate_totals( true );
$order->calculate_taxes( $calculate_tax_args );
$order->calculate_totals( false );
ob_start();
include( 'admin/meta-boxes/views/html-order-items.php' );
@ -1325,15 +1339,30 @@ class WC_AJAX {
if ( $post_id > 0 ) {
$order = wc_get_order( $post_id );
$comment_id = $order->add_order_note( $note, $is_customer_note, true );
$note = wc_get_order_note( $comment_id );
echo '<li rel="' . esc_attr( $comment_id ) . '" class="note ';
if ( $is_customer_note ) {
echo 'customer-note';
}
echo '"><div class="note_content">';
echo wpautop( wptexturize( $note ) );
echo '</div><p class="meta"><a href="#" class="delete_note">' . __( 'Delete note', 'woocommerce' ) . '</a></p>';
echo '</li>';
$note_classes = array( 'note' );
$note_classes[] = $is_customer_note ? 'customer-note' : '';
$note_classes = apply_filters( 'woocommerce_order_note_class', array_filter( $note_classes ), $note );
?>
<li rel="<?php echo absint( $note->id ); ?>" class="<?php echo esc_attr( implode( ' ', $note_classes ) ); ?>">
<div class="note_content">
<?php echo wpautop( wptexturize( wp_kses_post( $note->content ) ) ); ?>
</div>
<p class="meta">
<abbr class="exact-date" title="<?php echo $note->date_created->date( 'y-m-d h:i:s' ); ?>">
<?php printf( __( 'added on %1$s at %2$s', 'woocommerce' ), $note->date_created->date_i18n( wc_date_format() ), $note->date_created->date_i18n( wc_time_format() ) ); ?>
</abbr>
<?php
if ( 'system' !== $note->added_by ) :
/* translators: %s: note author */
printf( ' ' . __( 'by %s', 'woocommerce' ), $note->added_by );
endif;
?>
<a href="#" class="delete_note" role="button"><?php _e( 'Delete note', 'woocommerce' ); ?></a>
</p>
</li>
<?php
}
wp_die();
}

View File

@ -558,15 +558,19 @@ class WC_Emails {
'order_id' => '',
) );
extract( $args );
if ( ! $product || ! $quantity || ! ( $order = wc_get_order( $order_id ) ) ) {
$order = wc_get_order( $args['order_id'] );
if (
! $args['product'] ||
! is_object( $args['product'] ) ||
! $args['quantity'] ||
! $order
) {
return;
}
$subject = sprintf( '[%s] %s', $this->get_blogname(), __( 'Product backorder', 'woocommerce' ) );
$message = sprintf( __( '%1$s units of %2$s have been backordered in order #%3$s.', 'woocommerce' ), $quantity, html_entity_decode( strip_tags( $product->get_formatted_name() ), ENT_QUOTES, get_bloginfo( 'charset' ) ), $order->get_order_number() );
$message = sprintf( __( '%1$s units of %2$s have been backordered in order #%3$s.', 'woocommerce' ), $args['quantity'], html_entity_decode( strip_tags( $args['product']->get_formatted_name() ), ENT_QUOTES, get_bloginfo( 'charset' ) ), $order->get_order_number() );
wp_mail(
apply_filters( 'woocommerce_email_recipient_backorder', get_option( 'woocommerce_stock_email_recipient' ), $args ),
apply_filters( 'woocommerce_email_subject_backorder', $subject, $args ),

View File

@ -87,16 +87,18 @@ class WC_Order_Item_Fee extends WC_Order_Item {
if ( 'non-taxable' === $tax_class ) {
continue;
}
$proportion = $tax_class_cost / $total_costs;
$cart_discount_proportion = $this->get_total() * $proportion;
$discount_taxes = wc_array_merge_recursive_numeric( $discount_taxes, WC_Tax::calc_tax( $cart_discount_proportion, WC_Tax::get_rates( $tax_class ) ) );
$proportion = $tax_class_cost / $total_costs;
$cart_discount_proportion = $this->get_total() * $proportion;
$calculate_tax_for['tax_class'] = $tax_class;
$tax_rates = WC_Tax::find_rates( $calculate_tax_for );
$discount_taxes = wc_array_merge_recursive_numeric( $discount_taxes, WC_Tax::calc_tax( $cart_discount_proportion, $tax_rates ) );
}
}
$this->set_taxes( array( 'total' => $discount_taxes ) );
} else {
$this->set_taxes( false );
}
do_action( 'woocommerce_order_item_fee_after_calculate_taxes', $this, $calculate_tax_for );
return true;

View File

@ -108,6 +108,9 @@ class WC_Post_Data {
foreach ( array_merge( $tt_ids, $old_tt_ids ) as $id ) {
delete_transient( 'wc_ln_count_' . md5( sanitize_key( $taxonomy ) . sanitize_key( $id ) ) );
}
if ( in_array( get_post_type( $object_id ), array( 'product', 'product_variation' ) ) ) {
self::delete_product_query_transients();
}
}
/**

View File

@ -180,4 +180,15 @@ class WC_Product_External extends WC_Product {
public function add_to_cart_text() {
return apply_filters( 'woocommerce_product_add_to_cart_text', $this->get_button_text() ? $this->get_button_text() : _x( 'Buy product', 'placeholder', 'woocommerce' ), $this );
}
/**
* Get the add to cart button text description - used in aria tags.
*
* @since 3.3.0
* @return string
*/
public function add_to_cart_description() {
/* translators: %s: Product title */
return apply_filters( 'woocommerce_product_add_to_cart_description', $this->get_button_text() ? $this->get_button_text() : sprintf( __( 'Buy &ldquo;%s&rdquo;', 'woocommerce' ), $this->get_name() ), $this );
}
}

View File

@ -43,6 +43,17 @@ class WC_Product_Grouped extends WC_Product {
return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'View products', 'woocommerce' ), $this );
}
/**
* Get the add to cart button text description - used in aria tags.
*
* @since 3.3.0
* @return string
*/
public function add_to_cart_description() {
/* translators: %s: Product title */
return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'View products in the &ldquo;%s&rdquo; group', 'woocommerce' ), $this->get_name() ), $this );
}
/**
* Returns whether or not the product is on sale.
*

View File

@ -55,4 +55,17 @@ class WC_Product_Simple extends WC_Product {
return apply_filters( 'woocommerce_product_add_to_cart_text', $text, $this );
}
/**
* Get the add to cart button text description - used in aria tags.
*
* @since 3.3.0
* @return string
*/
public function add_to_cart_description() {
/* translators: %s: Product title */
$text = $this->is_purchasable() && $this->is_in_stock() ? __( 'Add &ldquo;%s&rdquo; to your cart', 'woocommerce' ) : __( 'Read more about &ldquo;%s&rdquo;', 'woocommerce' );
return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( $text, $this->get_name() ), $this );
}
}

View File

@ -60,6 +60,17 @@ class WC_Product_Variable extends WC_Product {
return apply_filters( 'woocommerce_product_add_to_cart_text', $this->is_purchasable() ? __( 'Select options', 'woocommerce' ) : __( 'Read more', 'woocommerce' ), $this );
}
/**
* Get the add to cart button text description - used in aria tags.
*
* @since 3.3.0
* @return string
*/
public function add_to_cart_description() {
/* translators: %s: Product title */
return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'Select options for &ldquo;%s&rdquo;', 'woocommerce' ), $this->get_name() ), $this );
}
/**
* Get an array of all sale and regular prices from all variations. This is used for example when displaying the price range at variable product level or seeing if the variable product is on sale.
*

View File

@ -50,6 +50,16 @@ class WC_Product_Variation extends WC_Product_Simple {
'purchase_note' => '',
);
/**
* Override the default constructor to set custom defaults.
*
* @param int|WC_Product|object $product Product to init.
*/
public function __construct( $product = 0 ) {
$this->data['tax_class'] = 'parent';
parent::__construct( $product );
}
/**
* Prefix for action and filter hooks on data.
*

View File

@ -0,0 +1,110 @@
<?php
/**
* All functionality to regenerate images in the background when settings change.
*
* @category Images
* @package WooCommerce/Classes
* @author Automattic
* @version 3.3.0
* @since 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Class that extends WP_Background_Process to process image regeneration in the background
*/
class WC_Regenerate_Images_Request extends WP_Background_Process {
/**
* Action to hook onto
*
* @var string
*/
protected $action = 'woocommerce_regenerate_images';
/**
* Fires when the job should start
*
* @return void
*/
public function dispatch() {
$log = wc_get_logger();
$log->info( __( 'Starting product image regeneration job.', 'woocommerce' ),
array(
'source' => 'wc-image-regeneration',
)
);
parent::dispatch();
}
/**
* Code to execute for each item in the queue
*
* @param mixed $item Queue item to iterate over.
* @return bool
*/
protected function task( $item ) {
if ( ! is_array( $item ) && ! isset( $item['attachment_id'] ) ) {
return false;
}
if ( ! function_exists( 'wp_crop_image' ) ) {
include( ABSPATH . 'wp-admin/includes/image.php' );
}
$attachment_id = absint( $item['attachment_id'] );
$attachment = get_post( $attachment_id );
if ( ! $attachment || 'attachment' !== $attachment->post_type || 'image/' !== substr( $attachment->post_mime_type, 0, 6 ) ) {
return false;
}
$log = wc_get_logger();
// translators: %s: ID of the attachment.
$log->info( sprintf( __( 'Regenerating images for attachment ID: %s', 'woocommerce' ), absint( $attachment->ID ) ),
array(
'source' => 'wc-image-regeneration',
)
);
$fullsizepath = get_attached_file( $attachment->ID );
// Check if the file exists, if not just remove item from queue.
if ( false === $fullsizepath || ! file_exists( $fullsizepath ) ) {
return false;
}
// This function will generate the new image sizes.
$metadata = wp_generate_attachment_metadata( $attachment->ID, $fullsizepath );
// If something went wrong lets just remove the item from the queue.
if ( is_wp_error( $metadata ) || empty( $metadata ) ) {
return false;
}
// Update the meta data with the new size values.
wp_update_attachment_metadata( $attachment->ID, $metadata );
// We made it till the end, now lets remove the item from the queue.
return false;
}
/**
* This runs once the job has completed all items on the queue.
*
* @return void
*/
protected function complete() {
parent::complete();
$log = wc_get_logger();
$log->info( __( 'Completed product image regeneration job.', 'woocommerce' ),
array(
'source' => 'wc-image-regeneration',
)
);
}
}

View File

@ -0,0 +1,210 @@
<?php
/**
* Regenerate Images Functionality
*
* All functionality pertaining to regenerating product images in realtime.
*
* @category Images
* @package WooCommerce/Classes
* @author Automattic
* @version 3.3.0
* @since 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Regenerate Images Class
*/
class WC_Regenerate_Images {
/**
* Background process to regenerate all images
*
* @var WC_Regenerate_Images_Request
*/
protected static $background_process;
/**
* Init function
*/
public static function init() {
include_once( WC_ABSPATH . 'includes/class-wc-regenerate-images-request.php' );
self::$background_process = new WC_Regenerate_Images_Request();
if ( apply_filters( 'woocommerce_resize_images', true ) && ! is_admin() ) {
// Action to handle on-the-fly image resizing.
add_action( 'wp_get_attachment_image_src', array( __CLASS__, 'maybe_resize_image' ), 10, 4 );
}
if ( apply_filters( 'woocommerce_background_image_regeneration', true ) ) {
// Actions to handle image generation when settings change.
add_action( 'update_option_woocommerce_thumbnail_cropping', array( __CLASS__, 'maybe_regenerate_images_option_update' ), 10, 3 );
add_action( 'update_option_woocommerce_thumbnail_image_width', array( __CLASS__, 'maybe_regenerate_images_option_update' ), 10, 3 );
add_action( 'update_option_woocommerce_single_image_width', array( __CLASS__, 'maybe_regenerate_images_option_update' ), 10, 3 );
add_action( 'after_switch_theme', array( __CLASS__, 'maybe_regenerate_image_theme_switch' ) );
}
}
/**
* Check if we should maybe generate a new image size if not already there.
*
* @param array $image Properties of the image.
* @param int $attachment_id Attachment ID.
* @param string|array $size Image size.
* @param bool $icon If icon or not.
* @return array
*/
public static function maybe_resize_image( $image, $attachment_id, $size, $icon ) {
$imagemeta = wp_get_attachment_metadata( $attachment_id );
if ( false === $imagemeta || empty( $imagemeta ) ) {
return $image;
}
$size_settings = wc_get_image_size( $size );
if ( isset( $imagemeta['sizes'][ $size ] ) ) {
if ( $imagemeta['sizes'][ $size ]['width'] !== $size_settings['width'] || $imagemeta['sizes'][ $size ]['height'] !== $size_settings['height'] ) {
$image = self::resize_and_return_image( $attachment_id, $image, $size, $icon );
}
} else {
$image = self::resize_and_return_image( $attachment_id, $image, $size, $icon );
}
return $image;
}
/**
* Regenerate the image according to the required size
*
* @param int $attachment_id Attachment ID.
* @param array $image Original Image.
* @param string $size Size to return for new URL.
* @param bool $icon If icon or not.
* @return string
*/
private static function resize_and_return_image( $attachment_id, $image, $size, $icon ) {
$attachment = get_post( $attachment_id );
if ( ! $attachment || 'attachment' !== $attachment->post_type || 'image/' !== substr( $attachment->post_mime_type, 0, 6 ) ) {
return $image;
}
if ( ! function_exists( 'wp_crop_image' ) ) {
include( ABSPATH . 'wp-admin/includes/image.php' );
}
$wp_uploads = wp_upload_dir( null, false );
$wp_uploads_dir = $wp_uploads['basedir'];
$wp_uploads_url = $wp_uploads['baseurl'];
$original_image_file_path = get_attached_file( $attachment->ID );
if ( ! file_exists( $original_image_file_path ) || ! getimagesize( $original_image_file_path ) ) {
return $image;
}
$info = pathinfo( $original_image_file_path );
$ext = $info['extension'];
list( $orig_w, $orig_h ) = getimagesize( $original_image_file_path );
// Get image size after cropping.
$image_size = wc_get_image_size( $size );
$dimensions = image_resize_dimensions( $orig_w, $orig_h, $image_size['width'], $image_size['height'], $image_size['crop'] );
if ( ! $dimensions || ! is_array( $dimensions ) ) {
return $image;
}
$dst_w = $dimensions[4];
$dst_h = $dimensions[5];
$suffix = "{$dst_w}x{$dst_h}";
$dst_rel_path = str_replace( '.' . $ext, '', $original_image_file_path );
$destfilename = "{$dst_rel_path}-{$suffix}.{$ext}";
// If the file is already there perhaps just load it.
if ( file_exists( $destfilename ) ) {
return array(
0 => str_replace( $wp_uploads_dir, $wp_uploads_url, $destfilename ),
1 => $image_size['width'],
2 => $image_size['height'],
);
}
// Lets resize the image if it does not exist yet.
$editor = wp_get_image_editor( $original_image_file_path );
if ( is_wp_error( $editor ) || is_wp_error( $editor->resize( $image_size['width'], $image_size['height'], $image_size['crop'] ) ) ) {
return $image;
}
$resized_file = $editor->save();
if ( ! is_wp_error( $resized_file ) ) {
$img_url = str_replace( $wp_uploads_dir, $wp_uploads_url, $resized_file['path'] );
return array(
0 => $img_url,
1 => $image_size['width'],
2 => $image_size['height'],
);
}
// Lets just add this here as a fallback.
return $image;
}
/**
* Check if we should regenerate the product images when options change.
*
* @param mixed $old_value Old option value.
* @param mixed $new_value New option value.
* @param string $option Option name.
*/
public static function maybe_regenerate_images_option_update( $old_value, $new_value, $option ) {
if ( $new_value === $old_value ) {
return;
}
self::queue_image_regeneration();
}
/**
* Check if we should generate images when new themes declares custom sizes
*
* @return void
*/
public static function maybe_regenerate_image_theme_switch() {
$theme_support = get_theme_support( 'woocommerce' );
$theme_support = is_array( $theme_support ) ? $theme_support[0] : false;
// Only queue image generation if the theme declares custom sizes via theme_support.
if ( is_array( $theme_support ) && ( isset( $theme_support['single_image_width'] ) || isset( $theme_support['thumbnail_image_width'] ) ) ) {
self::queue_image_regeneration();
}
}
/**
* Get list of images and queue them for regeneration
*
* @return void
*/
private static function queue_image_regeneration() {
global $wpdb;
// First lets cancel existing running queue to avoid running it more than once.
self::$background_process->cancel_process();
// Now lets find all product image attachments IDs and pop them onto the queue.
$images = $wpdb->get_results( // @codingStandardsIgnoreLine
"SELECT ID
FROM $wpdb->posts
WHERE post_type = 'attachment'
AND post_mime_type LIKE 'image/%'
ORDER BY ID DESC"
);
foreach ( $images as $image ) {
self::$background_process->push_to_queue( array(
'attachment_id' => $image->ID,
) );
}
// Lets dispatch the queue to start processing.
self::$background_process->save()->dispatch();
}
}
WC_Regenerate_Images::init();

View File

@ -16,7 +16,6 @@ if ( ! defined( 'ABSPATH' ) ) {
* Main WooCommerce Class.
*
* @class WooCommerce
* @version 3.3.0
*/
final class WooCommerce {
@ -237,13 +236,13 @@ final class WooCommerce {
*/
private function is_request( $type ) {
switch ( $type ) {
case 'admin' :
case 'admin':
return is_admin();
case 'ajax' :
case 'ajax':
return defined( 'DOING_AJAX' );
case 'cron' :
case 'cron':
return defined( 'DOING_CRON' );
case 'frontend' :
case 'frontend':
return ( ! is_admin() || defined( 'DOING_AJAX' ) ) && ! defined( 'DOING_CRON' );
}
}
@ -320,11 +319,11 @@ final class WooCommerce {
include_once( WC_ABSPATH . 'includes/class-wc-emails.php' );
include_once( WC_ABSPATH . 'includes/class-wc-data-exception.php' );
include_once( WC_ABSPATH . 'includes/class-wc-query.php' );
include_once( WC_ABSPATH . 'includes/class-wc-meta-data.php' ); // Meta data internal object
include_once( WC_ABSPATH . 'includes/class-wc-meta-data.php' ); // Meta data internal object.
include_once( WC_ABSPATH . 'includes/class-wc-order-factory.php' ); // Order factory.
include_once( WC_ABSPATH . 'includes/class-wc-order-query.php' ); // Order query.
include_once( WC_ABSPATH . 'includes/class-wc-product-factory.php' ); // Product factory.
include_once( WC_ABSPATH . 'includes/class-wc-product-query.php' ); // Product query
include_once( WC_ABSPATH . 'includes/class-wc-product-query.php' ); // Product query.
include_once( WC_ABSPATH . 'includes/class-wc-payment-tokens.php' ); // Payment tokens controller.
include_once( WC_ABSPATH . 'includes/class-wc-shipping-zone.php' );
include_once( WC_ABSPATH . 'includes/gateways/class-wc-payment-gateway-cc.php' ); // CC Payment Gateway.
@ -338,6 +337,7 @@ final class WooCommerce {
include_once( WC_ABSPATH . 'includes/class-wc-background-emailer.php' );
include_once( WC_ABSPATH . 'includes/class-wc-discounts.php' );
include_once( WC_ABSPATH . 'includes/class-wc-cart-totals.php' );
include_once( WC_ABSPATH . 'includes/class-wc-regenerate-images.php' ); // Image regeneration class.
/**
* Data stores - used to store and retrieve CRUD object data from the database.
@ -409,28 +409,28 @@ final class WooCommerce {
if ( $this->is_active_theme( array( 'twentyseventeen', 'twentysixteen', 'twentyfifteen', 'twentyfourteen', 'twentythirteen', 'twentyeleven', 'twentytwelve', 'twentyten' ) ) ) {
switch ( get_template() ) {
case 'twentyten' :
case 'twentyten':
include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-ten.php' );
break;
case 'twentyeleven' :
case 'twentyeleven':
include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-eleven.php' );
break;
case 'twentytwelve' :
case 'twentytwelve':
include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-twelve.php' );
break;
case 'twentythirteen' :
case 'twentythirteen':
include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-thirteen.php' );
break;
case 'twentyfourteen' :
case 'twentyfourteen':
include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-fourteen.php' );
break;
case 'twentyfifteen' :
case 'twentyfifteen':
include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-fifteen.php' );
break;
case 'twentysixteen' :
case 'twentysixteen':
include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-sixteen.php' );
break;
case 'twentyseventeen' :
case 'twentyseventeen':
include_once( WC_ABSPATH . 'includes/theme-support/class-wc-twenty-seventeen.php' );
break;
}
@ -558,7 +558,7 @@ final class WooCommerce {
*/
private function add_image_sizes() {
$thumbnail = wc_get_image_size( 'thumbnail' );
$single = wc_get_image_size( 'single' );
$single = wc_get_image_size( 'single' );
add_image_size( 'woocommerce_thumbnail', $thumbnail['width'], $thumbnail['height'], $thumbnail['crop'] );
add_image_size( 'woocommerce_single', $single['width'], $single['height'], $single['crop'] );
@ -641,12 +641,12 @@ final class WooCommerce {
return;
}
if ( false === ( $webhooks = get_transient( 'woocommerce_webhook_ids' ) ) ) {
if ( false === ( $webhooks = get_transient( 'woocommerce_webhook_ids' ) ) ) { // @codingStandardsIgnoreLine
$webhooks = get_posts( array(
'fields' => 'ids',
'post_type' => 'shop_webhook',
'post_status' => 'publish',
'posts_per_page' => -1,
'posts_per_page' => -1, // @codingStandardsIgnoreLine
) );
set_transient( 'woocommerce_webhook_ids', $webhooks );
}

View File

@ -63,9 +63,12 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
'post_type' => 'product_variation',
'orderby' => array( 'menu_order' => 'ASC', 'ID' => 'ASC' ),
'fields' => 'ids',
'post_status' => 'publish',
'post_status' => array( 'publish', 'private' ),
'numberposts' => -1,
);
$visible_only_args['post_status'] = 'publish';
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
$visible_only_args['tax_query'][] = array(
'taxonomy' => 'product_visibility',

View File

@ -508,6 +508,8 @@ class WC_Shortcode_Products {
update_meta_cache( 'post', $products_ids );
update_object_term_cache( $products_ids, 'product' );
$original_post = $GLOBALS['post'];
do_action( "woocommerce_shortcode_before_{$this->type}_loop", $this->attributes );
woocommerce_product_loop_start();
@ -527,15 +529,17 @@ class WC_Shortcode_Products {
remove_action( 'woocommerce_product_is_visible', array( $this, 'set_product_as_visible' ) );
}
$GLOBALS['post'] = $original_post; // WPCS: override ok.
woocommerce_product_loop_end();
do_action( "woocommerce_shortcode_after_{$this->type}_loop", $this->attributes );
wp_reset_postdata();
} else {
do_action( "woocommerce_shortcode_{$this->type}_loop_no_results", $this->attributes );
}
woocommerce_reset_loop();
wp_reset_postdata();
return '<div class="' . esc_attr( implode( ' ', $classes ) ) . '">' . ob_get_clean() . '</div>';
}

View File

@ -686,7 +686,7 @@ function wc_get_image_size( $image_size ) {
'crop' => isset( $image_size[2] ) ? $image_size[2] : 1,
);
$image_size = $size['width'] . '_' . $size['height'];
} elseif ( in_array( $image_size, array( 'single', 'shop_single' ), true ) ) {
} elseif ( in_array( $image_size, array( 'single', 'shop_single', 'woocommerce_single' ), true ) ) {
// If the theme supports woocommerce, take image sizes from that definition.
if ( isset( $theme_support[ 'single_image_width' ] ) ) {
$size['width'] = $theme_support[ 'single_image_width' ];
@ -696,7 +696,7 @@ function wc_get_image_size( $image_size ) {
$size['height'] = 9999999999;
$size['crop'] = 0;
$image_size = 'single';
} elseif ( in_array( $image_size, array( 'thumbnail', 'shop_thumbnail', 'shop_catalog' ), true ) ) {
} elseif ( in_array( $image_size, array( 'thumbnail', 'shop_thumbnail', 'shop_catalog', 'woocommerce_thumbnail' ), true ) ) {
// If the theme supports woocommerce, take image sizes from that definition.
if ( isset( $theme_support[ 'thumbnail_image_width' ] ) ) {
$size['width'] = $theme_support[ 'thumbnail_image_width' ];

View File

@ -38,12 +38,13 @@
"grunt-phpcs": "~0.4.0",
"grunt-postcss": "~0.8.0",
"grunt-rtlcss": "~2.0.1",
"grunt-shell": "~2.1.0",
"grunt-sass": "~2.0.0",
"grunt-shell": "~2.1.0",
"grunt-stylelint": "~0.8.0",
"grunt-wp-i18n": "~1.0.0",
"istanbul": "^1.0.0-alpha",
"mocha": "^3.0.2",
"stylelint": "^7.8.0",
"wc-e2e-page-objects": "0.4.0"
},
"engines": {

View File

@ -13,7 +13,7 @@
* @see https://docs.woocommerce.com/document/template-structure/
* @author WooThemes
* @package WooCommerce/Templates
* @version 3.0.0
* @version 3.3.0
*/
if ( ! defined( 'ABSPATH' ) ) {
@ -22,13 +22,14 @@ if ( ! defined( 'ABSPATH' ) ) {
global $product;
echo apply_filters( 'woocommerce_loop_add_to_cart_link',
sprintf( '<a rel="nofollow" href="%s" data-quantity="%s" data-product_id="%s" data-product_sku="%s" class="%s">%s</a>',
echo apply_filters( 'woocommerce_loop_add_to_cart_link', // WPCS: XSS ok.
sprintf( '<a rel="nofollow" href="%s" data-quantity="%s" data-product_id="%s" data-product_sku="%s" class="%s" aria-label="%s">%s</a>',
esc_url( $product->add_to_cart_url() ),
esc_attr( isset( $quantity ) ? $quantity : 1 ),
esc_attr( $product->get_id() ),
esc_attr( $product->get_sku() ),
esc_attr( isset( $class ) ? $class : 'button' ),
esc_attr( $product->add_to_cart_description() ),
esc_html( $product->add_to_cart_text() )
),
$product );