Merge branch 'master' of github.com:woocommerce/woocommerce into add/unit-tests

This commit is contained in:
Gerhard Potgieter 2017-12-14 10:56:01 +02:00
commit 2f477887fb
15 changed files with 887 additions and 516 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -483,7 +483,8 @@ body {
}
}
.wc-wizard-service-item, .wc-wizard-services-list-toggle {
.wc-wizard-service-item,
.wc-wizard-services-list-toggle {
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
@ -560,6 +561,7 @@ body {
text-align: center;
cursor: pointer;
padding: 2em 0;
position: relative;
}
.wc-wizard-service-toggle {
@ -624,30 +626,31 @@ body {
}
}
// Toggle display a list of services
.wc-wizard-service-enable input {
visibility: hidden;
position: relative;
cursor: pointer;
&:before {
content: "\f347"; // down chevron
// Toggle display a list of services.
.wc-wizard-services-list-toggle {
.wc-wizard-service-enable::before {
content: "\f343"; // up chevron
font-family: "dashicons";
visibility: initial;
color: #666;
font-size: 25px;
margin-left: -5px; // center it
top: -6px;
margin-top: -7px;
margin-left: -5px;
position: absolute;
visibility: visible;
}
&.closed {
.wc-wizard-service-enable::before {
content: "\f347"; // down chevron
}
}
.wc-wizard-service-enable input {
visibility: hidden;
position: relative;
cursor: pointer;
}
}
.wc-wizard-service-enable input:checked {
&:before {
content: "\f343"; // up chevron
top: -7px;
}
}
.wc-wizard-services.manual .wc-wizard-service-item {
display: none;
}

View File

@ -1153,7 +1153,7 @@ class WC_Admin_Setup_Wizard {
'type' => 'email',
'value' => $user_email,
'placeholder' => __( 'Email address to receive payments', 'woocommerce' ),
'description' => __( "Enter your email address and we'll authenticate payments for you. To claim a payment, you'll need to have a PayPal Business account or create one later. WooCommerce Services and Jetpack will be installed and activated for you.", 'woocommerce' ),
'description' => __( "Enter your email address and we'll authenticate payments for you. WooCommerce Services and Jetpack will be installed and activated for you.", 'woocommerce' ),
'required' => true,
),
),
@ -1432,8 +1432,8 @@ class WC_Admin_Setup_Wizard {
<?php esc_html_e( 'Collect payments from customers offline.', 'woocommerce' ); ?>
</div>
<div class="wc-wizard-service-enable">
<input class="wc-wizard-service-list-toggle" id="wc-wizard-service-list-toggle" type="checkbox">
<label for="wc-wizard-service-list-toggle"></label>
<input class="wc-wizard-service-list-toggle" id="wc-wizard-service-list-toggle" type="checkbox">
<label for="wc-wizard-service-list-toggle"></label>
</div>
</li>
<?php foreach ( $manual_gateways as $gateway_id => $gateway ) :

View File

@ -1205,12 +1205,18 @@ class WC_Helper {
}
/**
* Add a note about available extension updates if Woo core has an update available.
* Various Helper-related admin notices.
*/
public static function admin_notices() {
if ( apply_filters( 'woocommerce_helper_suppress_admin_notices', false ) ) {
return;
}
$screen = get_current_screen();
$screen_id = $screen ? $screen->id : '';
self::_prompt_helper_connect( $screen_id );
if ( 'update-core' !== $screen_id ) {
return;
}
@ -1220,12 +1226,48 @@ class WC_Helper {
return;
}
// Add a note about available extension updates if Woo core has an update available.
$notice = self::_get_extensions_update_notice();
if ( ! empty( $notice ) ) {
echo '<div class="updated woocommerce-message"><p>' . $notice . '</p></div>';
}
}
/**
* Prompt a Helper connection if the user has WooCommerce.com extensions.
*/
private static function _prompt_helper_connect( $screen_id ) {
// Don't show the notice on the Helper screens.
if ( 'woocommerce_page_wc-addons' == $screen_id && ! empty( $_REQUEST['section'] ) && 'helper' == $_REQUEST['section'] ) {
return;
}
// We believe have an active connection.
$auth = WC_Helper_Options::get( 'auth' );
if ( ! empty( $auth['access_token'] ) ) {
return;
}
$active_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
if ( empty( $active_plugins ) ) {
return;
}
$woo_plugins = self::get_local_woo_plugins();
if ( empty( $woo_plugins ) ) {
return;
}
$active_woo_plugins = array_intersect_key( $woo_plugins, array_flip( $active_plugins ) );
if ( count( $active_woo_plugins ) > 0 ) {
/* translators: %s: helper screen url */
$notice = __( '<a href="%s">Connect your store</a> to WooCommerce.com to receive extensions updates and support.', 'woocommerce' );
$notice = sprintf( $notice, admin_url( 'admin.php?page=wc-addons&section=helper' ) );
echo '<div class="updated woocommerce-message"><p>' . $notice . '</p></div>';
}
}
/**
* Get an update notice if one or more Woo extensions has an update available.
*

View File

@ -17,7 +17,7 @@ if ( class_exists( 'WC_Admin_List_Table_Orders', false ) ) {
}
if ( ! class_exists( 'WC_Admin_List_Table', false ) ) {
include_once( 'abstract-class-wc-admin-list-table.php' );
include_once 'abstract-class-wc-admin-list-table.php';
}
/**
@ -57,7 +57,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
/**
* Define primary column.
*
* @return array
* @return string
*/
protected function get_primary_column() {
return 'order_number';
@ -153,7 +153,8 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
global $the_order;
if ( empty( $this->object ) || $this->object->get_id() !== $post_id ) {
$this->object = $the_order = wc_get_order( $post_id );
$this->object = wc_get_order( $post_id );
$the_order = $this->object;
}
}
@ -190,11 +191,13 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$approved_comments_count = absint( $comment_count['approved'] );
if ( $approved_comments_count ) {
$latest_notes = wc_get_order_notes( array(
'order_id' => $this->object->get_id(),
'limit' => 1,
'orderby' => 'date_created_gmt',
) );
$latest_notes = wc_get_order_notes(
array(
'order_id' => $this->object->get_id(),
'limit' => 1,
'orderby' => 'date_created_gmt',
)
);
$latest_note = current( $latest_notes );
@ -223,7 +226,11 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$order_timestamp = $this->object->get_date_created()->getTimestamp();
if ( $order_timestamp > strtotime( '-1 day', current_time( 'timestamp', true ) ) ) {
$show_date = sprintf( _x( '%s ago', '%s = human-readable time difference', 'woocommerce' ), human_time_diff( $this->object->get_date_created()->getTimestamp(), current_time( 'timestamp', true ) ) );
$show_date = sprintf(
/* translators: %s: human-readable time difference */
_x( '%s ago', '%s = human-readable time difference', 'woocommerce' ),
human_time_diff( $this->object->get_date_created()->getTimestamp(), current_time( 'timestamp', true ) )
);
} else {
$show_date = $this->object->get_date_created()->date_i18n( apply_filters( 'woocommerce_admin_order_date_format', __( 'M j, Y', 'woocommerce' ) ) );
}
@ -259,17 +266,17 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
if ( $this->object->has_status( array( 'pending', 'on-hold' ) ) ) {
$actions['processing'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=processing&order_id=' . $this->object->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Processing', 'woocommerce' ),
'action' => 'processing',
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=processing&order_id=' . $this->object->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Processing', 'woocommerce' ),
'action' => 'processing',
);
}
if ( $this->object->has_status( array( 'pending', 'on-hold', 'processing' ) ) ) {
$actions['complete'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=completed&order_id=' . $this->object->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Complete', 'woocommerce' ),
'action' => 'complete',
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=completed&order_id=' . $this->object->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Complete', 'woocommerce' ),
'action' => 'complete',
);
}
@ -286,12 +293,14 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
* Render columm: billing_address.
*/
protected function render_billing_address_column() {
if ( $address = $this->object->get_formatted_billing_address() ) {
$address = $this->object->get_formatted_billing_address();
if ( $address ) {
echo esc_html( preg_replace( '#<br\s*/?>#i', ', ', $address ) );
if ( $this->object->get_payment_method() ) {
/* translators: %s: payment method */
echo '<span class="description">' . sprintf( __( 'via %s', 'woocommerce' ), esc_html( $this->object->get_payment_method_title() ) ) . '</span>';
echo '<span class="description">' . sprintf( __( 'via %s', 'woocommerce' ), esc_html( $this->object->get_payment_method_title() ) ) . '</span>'; // WPCS: XSS ok.
}
} else {
echo '&ndash;';
@ -302,11 +311,13 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
* Render columm: shipping_address.
*/
protected function render_shipping_address_column() {
if ( $address = $this->object->get_formatted_shipping_address() ) {
$address = $this->object->get_formatted_shipping_address();
if ( $address ) {
echo '<a target="_blank" href="' . esc_url( $this->object->get_shipping_address_map_url() ) . '">' . esc_html( preg_replace( '#<br\s*/?>#i', ', ', $address ) ) . '</a>';
if ( $this->object->get_shipping_method() ) {
/* translators: %s: shipping method */
echo '<span class="description">' . sprintf( __( 'via %s', 'woocommerce' ), esc_html( $this->object->get_shipping_method() ) ) . '</span>';
echo '<span class="description">' . sprintf( __( 'via %s', 'woocommerce' ), esc_html( $this->object->get_shipping_method() ) ) . '</span>'; // WPCS: XSS ok.
}
} else {
echo '&ndash;';
@ -326,6 +337,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
<section class="wc-backbone-modal-main" role="main">
<header class="wc-backbone-modal-header">
<mark class="order-status status-{{ data.status }}"><span>{{ data.status_name }}</span></mark>
<?php /* translators: %s: order ID */ ?>
<h1><?php echo esc_html( sprintf( __( 'Order #%s', 'woocommerce' ), '{{ data.order_number }}' ) ); ?></h1>
<button class="modal-close modal-close-link dashicons dashicons-no-alt">
<span class="screen-reader-text"><?php esc_html_e( 'Close modal panel', 'woocommerce' ); ?></span>
@ -402,26 +414,30 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
* @return string
*/
public static function get_order_preview_item_html( $order ) {
$hidden_order_itemmeta = apply_filters( 'woocommerce_hidden_order_itemmeta', array(
'_qty',
'_tax_class',
'_product_id',
'_variation_id',
'_line_subtotal',
'_line_subtotal_tax',
'_line_total',
'_line_tax',
'method_id',
'cost',
) );
$hidden_order_itemmeta = apply_filters(
'woocommerce_hidden_order_itemmeta', array(
'_qty',
'_tax_class',
'_product_id',
'_variation_id',
'_line_subtotal',
'_line_subtotal_tax',
'_line_total',
'_line_tax',
'method_id',
'cost',
)
);
$line_items = apply_filters( 'woocommerce_admin_order_preview_line_items', $order->get_items(), $order );
$columns = apply_filters( 'woocommerce_admin_order_preview_line_item_columns', array(
'product' => __( 'Product', 'woocommerce' ),
'quantity' => __( 'Quantity', 'woocommerce' ),
'tax' => __( 'Tax', 'woocommerce' ),
'total' => __( 'Total', 'woocommerce' ),
), $order );
$columns = apply_filters(
'woocommerce_admin_order_preview_line_item_columns', array(
'product' => __( 'Product', 'woocommerce' ),
'quantity' => __( 'Quantity', 'woocommerce' ),
'tax' => __( 'Tax', 'woocommerce' ),
'total' => __( 'Total', 'woocommerce' ),
), $order
);
if ( ! wc_tax_enabled() ) {
unset( $columns['tax'] );
@ -457,7 +473,9 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$html .= '<div class="wc-order-item-sku">' . esc_html( $product_object->get_sku() ) . '</div>';
}
if ( $meta_data = $item->get_formatted_meta_data( '' ) ) {
$meta_data = $item->get_formatted_meta_data( '' );
if ( $meta_data ) {
$html .= '<table cellspacing="0" class="wc-order-item-meta">';
foreach ( $meta_data as $meta_id => $meta ) {
@ -478,7 +496,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
case 'total':
$html .= wc_price( $item->get_total(), array( 'currency' => $order->get_currency() ) );
break;
default :
default:
$html .= apply_filters( 'woocommerce_admin_order_preview_line_item_column_' . sanitize_key( $column ), '', $item, $item_id, $order );
break;
}
@ -508,25 +526,25 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
if ( $order->has_status( array( 'pending' ) ) ) {
$status_actions['on-hold'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=on-hold&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'On-hold', 'woocommerce' ),
'action' => 'on-hold',
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=on-hold&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'On-hold', 'woocommerce' ),
'action' => 'on-hold',
);
}
if ( $order->has_status( array( 'pending', 'on-hold' ) ) ) {
$status_actions['processing'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=processing&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Processing', 'woocommerce' ),
'action' => 'processing',
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=processing&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Processing', 'woocommerce' ),
'action' => 'processing',
);
}
if ( $order->has_status( array( 'pending', 'on-hold', 'processing' ) ) ) {
$status_actions['complete'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=completed&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Completed', 'woocommerce' ),
'action' => 'complete',
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_status&status=completed&order_id=' . $order->get_id() ), 'woocommerce-mark-order-status' ),
'name' => __( 'Completed', 'woocommerce' ),
'action' => 'complete',
);
}
@ -554,30 +572,39 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$payment_via = $order->get_payment_method_title();
$payment_method = $order->get_payment_method();
$payment_gateways = WC()->payment_gateways() ? WC()->payment_gateways->payment_gateways() : array();
$transaction_id = $order->get_transaction_id();
if ( $transaction_id = $order->get_transaction_id() ) {
if ( isset( $payment_gateways[ $payment_method ] ) && ( $url = $payment_gateways[ $payment_method ]->get_transaction_url( $order ) ) ) {
if ( $transaction_id ) {
$url = isset( $payment_gateways[ $payment_method ] ) ? $payment_gateways[ $payment_method ]->get_transaction_url( $order ) : false;
if ( $url ) {
$payment_via .= ' (<a href="' . esc_url( $url ) . '" target="_blank">' . esc_html( $transaction_id ) . '</a>)';
} else {
$payment_via .= ' (' . esc_html( $transaction_id ) . ')';
}
}
return apply_filters( 'woocommerce_admin_order_preview_get_order_details', array(
'data' => $order->get_data(),
'order_number' => $order->get_order_number(),
'item_html' => WC_Admin_List_Table_Orders::get_order_preview_item_html( $order ),
'actions_html' => WC_Admin_List_Table_Orders::get_order_preview_actions_html( $order ),
'ship_to_billing' => wc_ship_to_billing_address_only(),
'needs_shipping' => $order->needs_shipping_address(),
'formatted_billing_address' => ( $address = $order->get_formatted_billing_address() ) ? $address : __( 'N/A', 'woocommerce' ),
'formatted_shipping_address' => ( $address = $order->get_formatted_shipping_address() ) ? $address: __( 'N/A', 'woocommerce' ),
'shipping_address_map_url' => $order->get_shipping_address_map_url(),
'payment_via' => $payment_via,
'shipping_via' => $order->get_shipping_method(),
'status' => $order->get_status(),
'status_name' => wc_get_order_status_name( $order->get_status() ),
), $order );
$billing_address = $order->get_formatted_billing_address();
$shipping_address = $order->get_formatted_shipping_address();
return apply_filters(
'woocommerce_admin_order_preview_get_order_details', array(
'data' => $order->get_data(),
'order_number' => $order->get_order_number(),
'item_html' => WC_Admin_List_Table_Orders::get_order_preview_item_html( $order ),
'actions_html' => WC_Admin_List_Table_Orders::get_order_preview_actions_html( $order ),
'ship_to_billing' => wc_ship_to_billing_address_only(),
'needs_shipping' => $order->needs_shipping_address(),
'formatted_billing_address' => $billing_address ? $billing_address : __( 'N/A', 'woocommerce' ),
'formatted_shipping_address' => $shipping_address ? $shipping_address : __( 'N/A', 'woocommerce' ),
'shipping_address_map_url' => $order->get_shipping_address_map_url(),
'payment_via' => $payment_via,
'shipping_via' => $order->get_shipping_method(),
'status' => $order->get_status(),
'status_name' => wc_get_order_status_name( $order->get_status() ),
), $order
);
}
/**
@ -605,7 +632,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
}
$changed = 0;
$ids = array_map( 'absint', $ids );
$ids = array_map( 'absint', $ids );
foreach ( $ids as $id ) {
$order = wc_get_order( $id );
@ -614,12 +641,14 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$changed++;
}
$redirect_to = add_query_arg( array(
'post_type' => $this->list_table_type,
$report_action => true,
'changed' => $changed,
'ids' => join( ',', $ids ),
), $redirect_to );
$redirect_to = add_query_arg(
array(
'post_type' => $this->list_table_type,
$report_action => true,
'changed' => $changed,
'ids' => join( ',', $ids ),
), $redirect_to
);
return esc_url_raw( $redirect_to );
}
@ -669,10 +698,11 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
$user_id = '';
if ( ! empty( $_GET['_customer_user'] ) ) { // WPCS: input var ok.
$user_id = absint( $_GET['_customer_user'] ); // WPCS: input var ok, sanitization ok.
$user = get_user_by( 'id', $user_id );
/* translators: 1: user display name 2: user ID 3: user email */
$user_id = absint( $_GET['_customer_user'] ); // WPCS: input var ok, sanitization ok.
$user = get_user_by( 'id', $user_id );
$user_string = sprintf(
/* translators: 1: user display name 2: user ID 3: user email */
esc_html__( '%1$s (#%2$s &ndash; %3$s)', 'woocommerce' ),
$user->display_name,
absint( $user->ID ),

View File

@ -29,16 +29,17 @@ if ( ! class_exists( 'WP_Background_Process', false ) ) {
class WC_Background_Emailer extends WP_Background_Process {
/**
* @var string
*/
protected $action = 'wc_emailer';
/**
* Initiate new background process
* Initiate new background process.
*/
public function __construct() {
// Uses unique prefix per blog so each blog has separate queue.
$this->prefix = 'wp_' . get_current_blog_id();
$this->action = 'wc_emailer';
// Dispatch queue after shutdown.
add_action( 'shutdown', array( $this, 'dispatch_queue' ), 100 );
parent::__construct();
add_action( 'shutdown', array( $this, 'dispatch_queue' ) );
}
/**
@ -74,11 +75,40 @@ class WC_Background_Emailer extends WP_Background_Process {
return false;
}
/**
* Finishes replying to the client, but keeps the process running for further (async) code execution.
*
* @see https://core.trac.wordpress.org/ticket/41358 .
*/
protected function close_http_connection() {
// Only 1 PHP process can access a session object at a time, close this so the next request isn't kept waiting.
// @codingStandardsIgnoreStart
if ( session_id() ) {
session_write_close();
}
// @codingStandardsIgnoreEnd
wc_set_time_limit( 0 );
// fastcgi_finish_request is the cleanest way to send the response and keep the script running, but not every server has it.
if ( is_callable( 'fastcgi_finish_request' ) ) {
fastcgi_finish_request();
} else {
// Fallback: send headers and flush buffers.
if ( ! headers_sent() ) {
header( 'Connection: close' );
}
@ob_end_flush();
flush();
}
}
/**
* Save and run queue.
*/
public function dispatch_queue() {
if ( ! empty( $this->data ) ) {
$this->close_http_connection();
$this->save()->dispatch();
}
}

View File

@ -29,9 +29,15 @@ if ( ! class_exists( 'WP_Background_Process', false ) ) {
class WC_Background_Updater extends WP_Background_Process {
/**
* @var string
* Initiate new background process.
*/
protected $action = 'wc_updater';
public function __construct() {
// Uses unique prefix per blog so each blog has separate queue.
$this->prefix = 'wp_' . get_current_blog_id();
$this->action = 'wc_updater';
parent::__construct();
}
/**
* Dispatch updater.

View File

@ -157,7 +157,7 @@ class WC_Install {
WC_Admin_Notices::add_notice( 'update' );
}
if ( ! empty( $_GET['force_update_woocommerce'] ) ) {
do_action( 'wp_wc_updater_cron' );
do_action( 'wp_' . get_current_blog_id() . '_wc_updater_cron' );
wp_safe_redirect( admin_url( 'admin.php?page=wc-settings' ) );
exit;
}

View File

@ -19,11 +19,15 @@ if ( ! defined( 'ABSPATH' ) ) {
class WC_Regenerate_Images_Request extends WP_Background_Process {
/**
* Action to hook onto
*
* @var string
* Initiate new background process.
*/
protected $action = 'woocommerce_regenerate_images';
public function __construct() {
// Uses unique prefix per blog so each blog has separate queue.
$this->prefix = 'wp_' . get_current_blog_id();
$this->action = 'wc_regenerate_images';
parent::__construct();
}
/**
* Fires when the job should start

View File

@ -1759,7 +1759,52 @@ if ( ! function_exists( 'woocommerce_products_will_display' ) ) {
* @return bool
*/
function woocommerce_products_will_display() {
return 0 < wc_get_loop_prop( 'total', 0 );
$display_type = woocommerce_get_loop_display_mode();
return 0 < wc_get_loop_prop( 'total', 0 ) && $display_type !== 'subcategories';
}
}
if ( ! function_exists( 'woocommerce_get_loop_display_mode' ) ) {
/**
* See what is going to display in the loop.
*
* @since 3.3.0
* @return string Either products, subcategories, or both, based on current page.
*/
function woocommerce_get_loop_display_mode() {
// Only return products when filtering things.
if ( 1 < wc_get_loop_prop( 'current_page' ) || wc_get_loop_prop( 'is_search' ) || wc_get_loop_prop( 'is_filtered' ) ) {
return 'products';
}
$parent_id = 0;
$display_type = '';
if ( is_shop() ) {
$display_type = get_option( 'woocommerce_shop_page_display', '' );
} elseif ( is_product_category() ) {
$parent_id = get_queried_object_id();
$display_type = get_woocommerce_term_meta( $parent_id, 'display_type', true );
$display_type = '' === $display_type ? get_option( 'woocommerce_category_archive_display', '' ) : $display_type;
}
// Ensure valid value.
if ( '' === $display_type || ! in_array( $display_type, array( 'products', 'subcategories', 'both' ), true ) ) {
$display_type = 'products';
}
// If we're showing categories, ensure we actually have something to show.
if ( in_array( $display_type, array( 'subcategories', 'both' ), true ) ) {
$subcategories = woocommerce_get_product_subcategories( $parent_id );
if ( empty( $subcategories ) ) {
$display_type = 'products';
}
}
return $display_type;
}
}
@ -1773,28 +1818,13 @@ if ( ! function_exists( 'woocommerce_maybe_show_product_subcategories' ) ) {
* @return string
*/
function woocommerce_maybe_show_product_subcategories( $loop_html ) {
// Don't show when filtering, searching or when on page > 1.
if ( 1 < wc_get_loop_prop( 'current_page' ) || wc_get_loop_prop( 'is_search' ) || wc_get_loop_prop( 'is_filtered' ) ) {
return $loop_html;
}
$parent_id = 0;
$display_type = '';
// Check categories are enabled and see what level to query.
if ( is_shop() ) {
$display_type = get_option( 'woocommerce_shop_page_display', '' );
} elseif ( is_product_category() ) {
$parent_id = get_queried_object_id();
$display_type = get_woocommerce_term_meta( $parent_id, 'display_type', true );
$display_type = '' === $display_type ? get_option( 'woocommerce_category_archive_display', '' ) : $display_type;
}
$display_type = woocommerce_get_loop_display_mode();
// If displaying categories, append to the loop.
if ( '' !== $display_type ) {
if ( 'subcategories' === $display_type || 'both' === $display_type ) {
ob_start();
woocommerce_product_subcategories( array(
'parent_id' => $parent_id,
'parent_id' => is_product_category() ? get_queried_object_id() : 0,
) );
$loop_html .= ob_get_clean();
@ -1807,8 +1837,39 @@ if ( ! function_exists( 'woocommerce_maybe_show_product_subcategories' ) ) {
}
}
if ( ! function_exists( 'woocommerce_product_subcategories' ) ) {
if ( ! function_exists( 'woocommerce_get_product_subcategories' ) ) {
/**
* Get (and cache) product subcategories.
*
* @param int $parent_id Get subcategories of this ID.
* @return array
*/
function woocommerce_get_product_subcategories( $parent_id = 0 ) {
$parent_id = absint( $parent_id );
$product_categories = wp_cache_get( 'product-categories-' . $parent_id, 'product_cat' );
if ( false === $product_categories ) {
// NOTE: using child_of instead of parent - this is not ideal but due to a WP bug ( https://core.trac.wordpress.org/ticket/15626 ) pad_counts won't work.
$product_categories = get_categories( apply_filters( 'woocommerce_product_subcategories_args', array(
'parent' => $parent_id,
'menu_order' => 'ASC',
'hide_empty' => 0,
'hierarchical' => 1,
'taxonomy' => 'product_cat',
'pad_counts' => 1,
) ) );
wp_cache_set( 'product-categories-' . $parent_id, $product_categories, 'product_cat' );
}
if ( apply_filters( 'woocommerce_product_subcategories_hide_empty', true ) ) {
$product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' );
}
return $product_categories;
}
}
if ( ! function_exists( 'woocommerce_product_subcategories' ) ) {
/**
* Display product sub categories as thumbnails.
*
@ -1822,19 +1883,7 @@ if ( ! function_exists( 'woocommerce_product_subcategories' ) ) {
'parent_id' => 0,
) );
// NOTE: using child_of instead of parent - this is not ideal but due to a WP bug ( https://core.trac.wordpress.org/ticket/15626 ) pad_counts won't work.
$product_categories = get_categories( apply_filters( 'woocommerce_product_subcategories_args', array(
'parent' => $args['parent_id'],
'menu_order' => 'ASC',
'hide_empty' => 0,
'hierarchical' => 1,
'taxonomy' => 'product_cat',
'pad_counts' => 1,
) ) );
if ( apply_filters( 'woocommerce_product_subcategories_hide_empty', true ) ) {
$product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' );
}
$product_categories = woocommerce_get_product_subcategories( $args['parent_id'] );
if ( ! $product_categories ) {
return false;

View File

@ -49,7 +49,7 @@ do_action( 'woocommerce_before_main_content' );
</header>
<?php
if ( have_posts() ) :
if ( have_posts() ) {
/**
* Hook: woocommerce_before_shop_loop.
@ -62,18 +62,20 @@ if ( have_posts() ) :
woocommerce_product_loop_start();
while ( have_posts() ) :
the_post();
if ( wc_get_loop_prop( 'total' ) ) {
while ( have_posts() ) {
the_post();
/**
* Hook: woocommerce_shop_loop.
*
* @hooked WC_Structured_Data::generate_product_data() - 10
*/
do_action( 'woocommerce_shop_loop' );
/**
* Hook: woocommerce_shop_loop.
*
* @hooked WC_Structured_Data::generate_product_data() - 10
*/
do_action( 'woocommerce_shop_loop' );
wc_get_template_part( 'content', 'product' );
endwhile;
wc_get_template_part( 'content', 'product' );
}
}
woocommerce_product_loop_end();
@ -83,17 +85,14 @@ if ( have_posts() ) :
* @hooked woocommerce_pagination - 10
*/
do_action( 'woocommerce_after_shop_loop' );
else :
} else {
/**
* Hook: woocommerce_no_products_found.
*
* @hooked wc_no_products_found - 10
*/
do_action( 'woocommerce_no_products_found' );
endif;
}
/**
* Hook: woocommerce_after_main_content.

View File

@ -0,0 +1,68 @@
<?php
/**
* Test WP_Background_Process functionality
*
* A mock class for testing the WP_Background_Process functionality.
*
* @since 3.3
*/
class WC_Mock_Background_Process extends WP_Background_Process {
/**
* Constructor.
*/
public function __construct() {
// Uses unique prefix per blog so each blog has separate queue.
$this->prefix = 'wp_' . get_current_blog_id();
$this->action = 'wc_mock_background_process';
parent::__construct();
}
/**
* Fires when the job should start.
*
* @return void
*/
public function dispatch() {
parent::dispatch();
}
/**
* Return the identifier string.
*
* @return void
*/
public function get_identifier() {
return $this->identifier;
}
/**
* Returns whether queue is empty or not.
*
* @return boolean
*/
public function is_queue_empty() {
return parent::is_queue_empty();
}
/**
* Rerturns the batch data.
*
* @return void
*/
public function get_batch() {
return parent::get_batch();
}
/**
* Code to execute for each item in the queue
*
* @param mixed $item Queue item to iterate over.
* @return bool
*/
protected function task( $item ) {
// We sleep for 5 seconds to mimic a long running tast to complete some tests.
sleep( 5 );
update_option( $item['mock_key'], $item['mock_value'] );
return false;
}
}

View File

@ -0,0 +1,66 @@
<?php
/**
* WP_Background_Processing Tests.
*
* @package WooCommerce\Tests\Libraries
*/
/**
* Class Functions.
*
* @since 3.3
*/
class WC_Tests_Libraries_Background_Process extends WC_Unit_Test_Case {
/**
* Test the is_queue_empty function.
*
* @return void
*/
public function test_is_queue_empty() {
require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'class-wc-mock-background-process.php' );
$queue = new WC_Mock_Background_Process();
$this->assertEquals( true, $queue->is_queue_empty() );
$queue->push_to_queue( array(
'mock_key' => 'mock_value',
) );
$queue->save();
$this->assertEquals( false, $queue->is_queue_empty() );
}
/**
* Make sure the cron works.
*
* @return void
*/
public function test_schedule_cron_healthcheck() {
require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'class-wc-mock-background-process.php' );
$queue = new WC_Mock_Background_Process();
$this->assertArrayHasKey( 'wp_' . get_current_blog_id() . '_wc_mock_background_process_cron_interval', $queue->schedule_cron_healthcheck( array() ) );
}
/**
* Test prefix & action against identifier.
*/
public function test_identifier() {
require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'class-wc-mock-background-process.php' );
$queue = new WC_Mock_Background_Process();
$this->assertEquals( 'wp_' . get_current_blog_id() . '_wc_mock_background_process', $queue->get_identifier() );
}
/**
* Test to make sure a batch is returned.
*
* @return void
*/
public function test_get_batch() {
require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'class-wc-mock-background-process.php' );
$queue = new WC_Mock_Background_Process();
$queue->push_to_queue( array(
'mock_key' => 'mock_value',
) );
$queue->save();
$this->assertNotEmpty( $queue->get_batch() );
}
}