Resolving conflicts with migration branch

This commit is contained in:
Julia Amosova 2019-12-04 21:02:34 +00:00
commit 62607a918c
78 changed files with 4071 additions and 322 deletions

2
.gitattributes vendored
View File

@ -1,4 +1,5 @@
/.* export-ignore
bin export-ignore
CODE_OF_CONDUCT.md export-ignore
CHANGELOG.txt export-ignore
composer.* export-ignore
@ -9,3 +10,4 @@ phpcs.xml export-ignore
phpunit.* export-ignore
README.md export-ignore
tests export-ignore
renovate.json export-ignore

View File

@ -37,7 +37,10 @@ matrix:
- name: "E2E tests"
env: RUN_E2E=1
script:
- docker-compose up -d
- npm install
- npm run build
- docker-compose up -d
- travis_retry bash tests/bin/run-e2e-CI.sh
- name: "Unit tests code coverage"
php: 7.3
env: WP_VERSION=latest WP_MULTISITE=0 RUN_CODE_COVERAGE=1
@ -49,6 +52,8 @@ matrix:
allow_failures:
- php: 7.3
env: WP_VERSION=latest WP_MULTISITE=0 RUN_CODE_COVERAGE=1
- php: 7.2
env: WP_VERSION=latest WP_MULTISITE=0 RUN_E2E=1
before_script:
- export PATH="$HOME/.composer/vendor/bin:$PATH"
@ -71,7 +76,6 @@ before_script:
script:
- bash tests/bin/phpunit.sh
- bash tests/bin/phpcs.sh
- travis_retry bash tests/bin/run-e2e-CI.sh
after_script:
- bash tests/bin/travis.sh after

View File

@ -229,7 +229,6 @@ module.exports = function( grunt ) {
files: {
src: [
'**/*.php', // Include all files
'!includes/libraries/**', // Exclude libraries/
'!node_modules/**', // Exclude node_modules/
'!tests/**', // Exclude tests/
'!vendor/**', // Exclude vendor/

View File

@ -2,20 +2,20 @@
* WooCommerce CSS Variables
*/
$woocommerce: #a46497;
$green: #7ad03a;
$red: #a00;
$orange: #ffba00;
$blue: #2ea2cc;
$woocommerce: #a46497 !default;
$green: #7ad03a !default;
$red: #a00 !default;
$orange: #ffba00 !default;
$blue: #2ea2cc !default;
$primary: #a46497; // Primary color for buttons (alt)
$primarytext: desaturate(lighten($primary, 50%), 18%); // Text on primary color bg
$primary: #a46497 !default; // Primary color for buttons (alt)
$primarytext: desaturate(lighten($primary, 50%), 18%) !default; // Text on primary color bg
$secondary: desaturate(lighten($primary, 40%), 21%); // Secondary buttons
$secondarytext: desaturate(darken($secondary, 60%), 21%); // Text on secondary color bg
$secondary: desaturate(lighten($primary, 40%), 21%) !default; // Secondary buttons
$secondarytext: desaturate(darken($secondary, 60%), 21%) !default; // Text on secondary color bg
$highlight: adjust-hue($primary, 150deg); // Prices, In stock labels, sales flash
$highlightext: desaturate(lighten($highlight, 50%), 18%); // Text on highlight color bg
$highlight: adjust-hue($primary, 150deg) !default; // Prices, In stock labels, sales flash
$highlightext: desaturate(lighten($highlight, 50%), 18%) !default; // Text on highlight color bg
$contentbg: #fff; // Content BG - Tabs (active state)
$subtext: #767676; // small, breadcrumbs etc
$contentbg: #fff !default; // Content BG - Tabs (active state)
$subtext: #767676 !default; // small, breadcrumbs etc

View File

@ -579,6 +579,7 @@
}
#variable_product_options {
.form-row select {
max-width: 100%;
}
@ -636,6 +637,14 @@ mark.amount {
}
}
.branch-5-3 {
.woocommerce-help-tip {
font-size: 1.2em;
cursor: help;
}
}
h2 .woocommerce-help-tip {
margin-top: -5px;
margin-left: 0.25em;
@ -2158,6 +2167,22 @@ ul.wc_coupon_list_block {
}
}
.branch-5-3 {
.widefat {
.column-wc_actions {
a.button {
&::after {
margin-top: 2px;
}
}
}
}
}
.post-type-shop_order {
.tablenav .one-page .displaying-num {
@ -3035,7 +3060,6 @@ table.wc_input_table {
vertical-align: middle;
input {
width: auto;
padding: 0;
}
}
@ -4099,6 +4123,84 @@ img.help_tip {
}
}
.branch-5-3 {
.woocommerce {
h2.wc-table-list-header {
margin: 1em 0 0.35em 0;
}
input + .subsubsub {
margin: 8px 0 0;
}
table.form-table {
// Give regular settings inputs a standard width and padding.
textarea,
input[type="text"],
input[type="email"],
input[type="number"],
input[type="password"],
input[type="datetime"],
input[type="datetime-local"],
input[type="date"],
input[type="time"],
input[type="week"],
input[type="url"],
input[type="tel"],
input.regular-input {
padding: 0 8px;
@media only screen and (max-width: 782px) {
width: 100%;
}
}
select {
@media only screen and (max-width: 782px) {
width: 100%;
}
}
th label {
img.help_tip,
.woocommerce-help-tip {
margin: -7px -24px 0 0;
@media only screen and (max-width: 782px) {
right: auto;
margin-left: 5px;
}
}
}
.forminp-color {
font-size: 0;
}
.colorpickpreview {
padding: 0;
width: 30px;
height: 30px;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
font-size: 16px;
border-radius: 4px;
margin-right: 3px;
@media only screen and (max-width: 782px) {
float: left;
width: 40px;
height: 40px;
}
}
}
}
}
.woocommerce #tabs-wrap table a.remove {
margin-left: 4px;
}
@ -4183,7 +4285,7 @@ img.help_tip {
right: -8px;
padding: 2px;
display: none;
@media (max-width: 768px) {
display: block;
}
@ -4545,7 +4647,6 @@ img.help_tip {
.woocommerce_options_panel .checkbox,
.woocommerce_variable_attributes .checkbox {
width: auto;
margin: 4px 0 !important;
vertical-align: middle;
float: left;
@ -6593,6 +6694,180 @@ table.bar_chart {
min-width: 400px !important;
}
.branch-5-3 {
.select2-results {
.select2-results__option,
.select2-results__group {
&:focus {
outline: none;
}
}
}
.select2-dropdown {
border-color: #007cba;
&::after {
position: absolute;
left: 0;
right: 0;
height: 1px;
background: #fff;
content: "";
}
}
.select2-dropdown--below {
box-shadow: 0 0 0 1px #007cba, 0 2px 1px rgba(0, 0, 0, 0.1);
&::after {
top: -1px;
}
}
.select2-dropdown--above {
box-shadow: 0 0 0 1px #007cba, 0 -2px 1px rgba(0, 0, 0, 0.1);
&::after {
bottom: -1px;
}
}
.select2-container {
@media only screen and (max-width: 782px) {
font-size: 16px;
}
&:focus {
outline: none;
}
.select2-selection--single {
height: 30px;
border-color: #7e8993;
@media only screen and (max-width: 782px) {
height: 40px;
}
&:focus {
outline: none;
}
.select2-selection__rendered {
line-height: 28px;
@media only screen and (max-width: 782px) {
line-height: 38px;
}
&:hover {
color: #007cba;
}
}
.select2-selection__arrow {
right: 1px;
height: 28px;
width: 28px;
background: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E") no-repeat right 5px top 55%;
background-size: 16px 16px;
@media only screen and (max-width: 782px) {
height: 38px;
}
b {
display: none;
}
}
}
&.select2-container--focus .select2-selection--single,
&.select2-container--open .select2-selection--single,
&.select2-container--open .select2-selection--multiple {
border-color: #007cba;
box-shadow: 0 0 0 1px #007cba;
}
.select2-selection--multiple {
min-height: 30px;
border-color: #7e8993;
border-radius: 4px;
}
.select2-search--inline .select2-search__field {
padding: 0 0 0 3px;
min-height: 28px;
}
}
.woocommerce table.form-table .select2-container {
@media only screen and (max-width: 782px) {
min-width: 100% !important;
}
}
}
/**
* Select2 colors for built-in admin color themes.
*/
.branch-5-3 {
.admin-color {
$wp_admin_colors: (
blue: #096484,
coffee: #c7a589,
ectoplasm: #a3b745,
midnight: #e14d43,
ocean: #9ebaa0,
sunrise: #dd823b,
light: #04a4cc
);
@each $name, $color in $wp_admin_colors {
&-#{$name} {
.select2-dropdown {
border-color: $color;
}
.select2-dropdown--below {
box-shadow: 0 0 0 1px $color, 0 2px 1px rgba(0, 0, 0, 0.1);
}
.select2-dropdown--above {
box-shadow: 0 0 0 1px $color, 0 -2px 1px rgba(0, 0, 0, 0.1);
}
.select2-selection--single .select2-selection__rendered:hover {
color: $color;
}
.select2-container.select2-container--focus .select2-selection--single,
.select2-container.select2-container--open .select2-selection--single,
.select2-container.select2-container--open .select2-selection--multiple {
border-color: $color;
box-shadow: 0 0 0 1px $color;
}
.select2-container--default .select2-results__option--highlighted[aria-selected],
.select2-container--default .select2-results__option--highlighted[data-selected] {
background-color: $color;
}
}
}
}
}
.post-type-product .tablenav,
.post-type-shop_order .tablenav {

File diff suppressed because it is too large Load Diff

View File

@ -1159,6 +1159,14 @@ h3.jetpack-reasons {
}
}
.branch-5-3 {
.location-input {
margin: 0;
}
}
.address-step {
.select2 {
@ -1380,6 +1388,17 @@ p.jetpack-terms {
}
}
.branch-5-3 {
.wc-wizard-service-setting-stripe_create_account,
.wc-wizard-service-setting-ppec_paypal_reroute_requests {
.payment-checkbox-input {
margin-top: 3px;
}
}
}
.wc-wizard-service-setting-stripe_email,
.wc-wizard-service-setting-ppec_paypal_email {
margin-top: 0.75em;

View File

@ -88,6 +88,18 @@
event.data.variationForm.$form.find( '.single_add_to_cart_button' ).removeClass( 'wc-variation-selection-needed' ).addClass( 'disabled wc-variation-is-unavailable' );
event.data.variationForm.$form.find( '.woocommerce-variation-add-to-cart' ).removeClass( 'woocommerce-variation-add-to-cart-enabled' ).addClass( 'woocommerce-variation-add-to-cart-disabled' );
}
// If present, the media element library needs initialized on the variation description.
if ( wp.mediaelement ) {
event.data.variationForm.$form.find( '.wp-audio-shortcode, .wp-video-shortcode' )
.not( '.mejs-container' )
.filter(
function () {
return ! $( this ).parent().hasClass( 'mejs-mediaelement' );
}
)
.mediaelementplayer( wp.mediaelement.settings );
}
};
/**

View File

@ -78,6 +78,11 @@ abstract class WC_Widget extends WP_Widget {
* @return bool true if the widget is cached otherwise false
*/
public function get_cached_widget( $args ) {
// Don't get cache if widget_id doesn't exists.
if ( empty( $args['widget_id'] ) ) {
return false;
}
$cache = wp_cache_get( $this->get_widget_id_for_cache( $this->widget_id ), 'widget' );
if ( ! is_array( $cache ) ) {
@ -100,6 +105,11 @@ abstract class WC_Widget extends WP_Widget {
* @return string the content that was cached
*/
public function cache_widget( $args, $content ) {
// Don't set any cache if widget_id doesn't exist.
if ( empty( $args['widget_id'] ) ) {
return $content;
}
$cache = wp_cache_get( $this->get_widget_id_for_cache( $this->widget_id ), 'widget' );
if ( ! is_array( $cache ) ) {

View File

@ -488,7 +488,7 @@ class WC_Admin_Addons {
$back_admin_path = add_query_arg( array() );
return array(
'wccom-site' => site_url(),
'wccom-back' => esc_url( $back_admin_path ),
'wccom-back' => rawurlencode( $back_admin_path ),
'wccom-woo-version' => WC_VERSION,
'wccom-connect-nonce' => wp_create_nonce( 'connect' ),
);

View File

@ -95,7 +95,7 @@ class WC_Admin_API_Keys {
private static function table_list_output() {
global $wpdb, $keys_table_list;
echo '<h2>' . esc_html__( 'REST API', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced&section=keys&create-key=1' ) ) . '" class="add-new-h2">' . esc_html__( 'Add key', 'woocommerce' ) . '</a></h2>';
echo '<h2 class="wc-table-list-header">' . esc_html__( 'REST API', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced&section=keys&create-key=1' ) ) . '" class="add-new-h2">' . esc_html__( 'Add key', 'woocommerce' ) . '</a></h2>';
// Get the API keys count.
$count = $wpdb->get_var( "SELECT COUNT(key_id) FROM {$wpdb->prefix}woocommerce_api_keys WHERE 1 = 1;" );

View File

@ -1,17 +1,15 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Duplicate product functionality
*
* @author WooCommerce
* @category Admin
* @package WooCommerce/Admin
* @version 3.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( class_exists( 'WC_Admin_Duplicate_Product', false ) ) {
return new WC_Admin_Duplicate_Product();
}
@ -87,12 +85,10 @@ class WC_Admin_Duplicate_Product {
return;
}
if ( isset( $_GET['post'] ) ) {
$notify_url = wp_nonce_url( admin_url( 'edit.php?post_type=product&action=duplicate_product&post=' . absint( $_GET['post'] ) ), 'woocommerce-duplicate-product_' . $_GET['post'] );
?>
<div id="duplicate-action"><a class="submitduplicate duplication" href="<?php echo esc_url( $notify_url ); ?>"><?php esc_html_e( 'Copy to a new draft', 'woocommerce' ); ?></a></div>
<?php
}
$notify_url = wp_nonce_url( admin_url( 'edit.php?post_type=product&action=duplicate_product&post=' . absint( $post->ID ) ), 'woocommerce-duplicate-product_' . $post->ID );
?>
<div id="duplicate-action"><a class="submitduplicate duplication" href="<?php echo esc_url( $notify_url ); ?>"><?php esc_html_e( 'Copy to a new draft', 'woocommerce' ); ?></a></div>
<?php
}
/**
@ -111,7 +107,7 @@ class WC_Admin_Duplicate_Product {
if ( false === $product ) {
/* translators: %s: product id */
wp_die( sprintf( esc_html__( 'Product creation failed, could not find original product: %s', 'woocommerce' ), $product_id ) );
wp_die( sprintf( esc_html__( 'Product creation failed, could not find original product: %s', 'woocommerce' ), esc_html( $product_id ) ) );
}
$duplicate = $this->product_duplicate( $product );
@ -120,7 +116,7 @@ class WC_Admin_Duplicate_Product {
do_action( 'woocommerce_product_duplicate', $duplicate, $product );
wc_do_deprecated_action( 'woocommerce_duplicate_product', array( $duplicate->get_id(), $this->get_product_to_duplicate( $product_id ) ), '3.0', 'Use woocommerce_product_duplicate action instead.' );
// Redirect to the edit screen for the new draft page
// Redirect to the edit screen for the new draft page.
wp_redirect( admin_url( 'post.php?action=edit&post=' . $duplicate->get_id() ) );
exit;
}
@ -128,15 +124,20 @@ class WC_Admin_Duplicate_Product {
/**
* Function to create the duplicate of the product.
*
* @param WC_Product $product
* @return WC_Product
* @param WC_Product $product The product to duplicate.
* @return WC_Product The duplicate.
*/
public function product_duplicate( $product ) {
// Filter to allow us to unset/remove data we don't want to copy to the duplicate. @since 2.6
/**
* Filter to allow us to unset/remove data we don't want to copy to the duplicate.
*
* @since 2.6
*/
$meta_to_exclude = array_filter( apply_filters( 'woocommerce_duplicate_product_exclude_meta', array() ) );
$duplicate = clone $product;
$duplicate->set_id( 0 );
/* translators: %s contains the name of the original product. */
$duplicate->set_name( sprintf( esc_html__( '%s (Copy)', 'woocommerce' ), $duplicate->get_name() ) );
$duplicate->set_total_sales( 0 );
if ( '' !== $product->get_sku( 'edit' ) ) {
@ -153,7 +154,11 @@ class WC_Admin_Duplicate_Product {
$duplicate->delete_meta_data( $meta_key );
}
// This action can be used to modify the object further before it is created - it will be passed by reference. @since 3.0
/**
* This action can be used to modify the object further before it is created - it will be passed by reference.
*
* @since 3.0
*/
do_action( 'woocommerce_product_duplicate_before_save', $duplicate, $product );
// Save parent product.
@ -168,6 +173,12 @@ class WC_Admin_Duplicate_Product {
$child_duplicate->set_id( 0 );
$child_duplicate->set_date_created( null );
// If we wait and let the insertion generate the slug, we will see extreme performance degradation
// in the case where a product is used as a template. Every time the template is duplicated, each
// variation will query every consecutive slug until it finds an empty one. To avoid this, we can
// optimize the generation ourselves, avoiding the issue altogether.
$this->generate_unique_slug( $child_duplicate );
if ( '' !== $child->get_sku( 'edit' ) ) {
$child_duplicate->set_sku( wc_product_generate_unique_sku( 0, $child->get_sku( 'edit' ) ) );
}
@ -176,7 +187,11 @@ class WC_Admin_Duplicate_Product {
$child_duplicate->delete_meta_data( $meta_key );
}
// This action can be used to modify the object further before it is created - it will be passed by reference. @since 3.0
/**
* This action can be used to modify the object further before it is created - it will be passed by reference.
*
* @since 3.0
*/
do_action( 'woocommerce_product_duplicate_before_save', $child_duplicate, $child );
$child_duplicate->save();
@ -193,7 +208,7 @@ class WC_Admin_Duplicate_Product {
* Get a product from the database to duplicate.
*
* @deprecated 3.0.0
* @param mixed $id
* @param mixed $id The ID of the product to duplicate.
* @return object|bool
* @see duplicate_product
*/
@ -215,6 +230,44 @@ class WC_Admin_Duplicate_Product {
return $post;
}
/**
* Generates a unique slug for a given product. We do this so that we can override the
* behavior of wp_unique_post_slug(). The normal slug generation will run single
* select queries on every non-unique slug, resulting in very bad performance.
*
* @param WC_Product $product The product to generate a slug for.
* @since 3.9.0
*/
private function generate_unique_slug( $product ) {
global $wpdb;
// We want to remove the suffix from the slug so that we can find the maximum suffix using this root slug.
// This will allow us to find the next-highest suffix that is unique. While this does not support gap
// filling, this shouldn't matter for our use-case.
$root_slug = preg_replace( '/-[0-9]+$/', '', $product->get_slug() );
$results = $wpdb->get_results(
$wpdb->prepare( "SELECT post_name FROM $wpdb->posts WHERE post_name LIKE %s AND post_type IN ( 'product', 'product_variation' )", $root_slug . '%' )
);
// The slug is already unique!
if ( empty( $results ) ) {
return;
}
// Find the maximum suffix so we can ensure uniqueness.
$max_suffix = 1;
foreach ( $results as $result ) {
// Pull a numerical suffix off the slug after the last hyphen.
$suffix = intval( substr( $result->post_name, strrpos( $result->post_name, '-' ) + 1 ) );
if ( $suffix > $max_suffix ) {
$max_suffix = $suffix;
}
}
$product->set_slug( $root_slug . '-' . ( $max_suffix + 1 ) );
}
}
return new WC_Admin_Duplicate_Product();

View File

@ -706,7 +706,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
} elseif ( $description && in_array( $value['type'], array( 'checkbox' ), true ) ) {
$description = wp_kses_post( $description );
} elseif ( $description ) {
$description = '<span class="description">' . wp_kses_post( $description ) . '</span>';
$description = '<p class="description">' . wp_kses_post( $description ) . '</p>';
}
if ( $tooltip_html && in_array( $value['type'], array( 'checkbox' ), true ) ) {

View File

@ -580,7 +580,7 @@ class WC_Admin_Setup_Wizard {
printf(
wp_kses(
/* translators: %1$s: usage tracking help link */
__( 'Learn more about how usage tracking works, and how you\'ll be helping <a href="%1$s" target="_blank">here</a>.', 'woocommerce' ),
__( 'Learn more about how usage tracking works, and how you\'ll be helping in our <a href="%1$s" target="_blank">usage tracking documentation</a>.', 'woocommerce' ),
array(
'a' => array(
'href' => array(),
@ -700,7 +700,7 @@ class WC_Admin_Setup_Wizard {
public function run_deferred_actions() {
$this->close_http_connection();
foreach ( $this->deferred_actions as $action ) {
call_user_func_array( $action['func'], $action['args'] );
$action['func']( ...$action['args'] );
// Clear the background installation flag if this is a plugin.
if (

View File

@ -267,7 +267,7 @@ class WC_Admin_Webhooks {
private static function table_list_output() {
global $webhooks_table_list;
echo '<h2>' . esc_html__( 'Webhooks', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced&section=webhooks&edit-webhook=0' ) ) . '" class="add-new-h2">' . esc_html__( 'Add webhook', 'woocommerce' ) . '</a></h2>';
echo '<h2 class="wc-table-list-header">' . esc_html__( 'Webhooks', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced&section=webhooks&edit-webhook=0' ) ) . '" class="add-new-h2">' . esc_html__( 'Add webhook', 'woocommerce' ) . '</a></h2>';
// Get the webhooks count.
$data_store = WC_Data_Store::load( 'webhook' );

View File

@ -128,7 +128,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
}
// Invalidate caches.
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
WC_Cache_Helper::invalidate_cache_group( 'taxes' );
WC_Cache_Helper::get_transient_version( 'shipping', true );
// phpcs:enable WordPress.Security.NonceVerification.NoNonceVerification
}

View File

@ -64,7 +64,13 @@ $exporter = new WC_Product_CSV_Exporter();
<td>
<select id="woocommerce-exporter-category" class="woocommerce-exporter-category wc-enhanced-select" style="width:100%;" multiple data-placeholder="<?php esc_attr_e( 'Export all categories', 'woocommerce' ); ?>">
<?php
foreach ( get_categories( array( 'taxonomy' => 'product_cat' ) ) as $category ) {
$categories = get_categories(
array(
'taxonomy' => 'product_cat',
'hide_empty' => false,
)
);
foreach ( $categories as $category ) {
echo '<option value="' . esc_attr( $category->slug ) . '">' . esc_html( $category->name ) . '</option>';
}
?>

View File

@ -74,7 +74,7 @@ class WC_AJAX {
public static function do_wc_ajax() {
global $wp_query;
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( ! empty( $_GET['wc-ajax'] ) ) {
$wp_query->set( 'wc-ajax', sanitize_text_field( wp_unslash( $_GET['wc-ajax'] ) ) );
}
@ -396,7 +396,7 @@ class WC_AJAX {
public static function add_to_cart() {
ob_start();
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( ! isset( $_POST['product_id'] ) ) {
return;
}
@ -444,7 +444,7 @@ class WC_AJAX {
public static function remove_from_cart() {
ob_start();
// phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$cart_item_key = wc_clean( isset( $_POST['cart_item_key'] ) ? wp_unslash( $_POST['cart_item_key'] ) : '' );
if ( $cart_item_key && false !== WC()->cart->remove_cart_item( $cart_item_key ) ) {
@ -469,7 +469,7 @@ class WC_AJAX {
public static function get_variation() {
ob_start();
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( empty( $_POST['product_id'] ) ) {
wp_die();
}
@ -1144,7 +1144,7 @@ class WC_AJAX {
$order->set_billing_email( $user_email_arg );
}
$result = $order->apply_coupon( wc_format_coupon_code( wp_unslash( $_POST['coupon'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$result = $order->apply_coupon( wc_format_coupon_code( wp_unslash( $_POST['coupon'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( is_wp_error( $result ) ) {
throw new Exception( html_entity_decode( wp_strip_all_tags( $result->get_error_message() ) ) );
@ -1196,7 +1196,7 @@ class WC_AJAX {
throw new Exception( __( 'Invalid coupon', 'woocommerce' ) );
}
$order->remove_coupon( wc_format_coupon_code( wp_unslash( $_POST['coupon'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$order->remove_coupon( wc_format_coupon_code( wp_unslash( $_POST['coupon'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$order->calculate_taxes( $calculate_tax_args );
$order->calculate_totals( false );
@ -1717,7 +1717,7 @@ class WC_AJAX {
* Ajax request handling for categories ordering.
*/
public static function term_ordering() {
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( ! current_user_can( 'edit_products' ) || empty( $_POST['id'] ) ) {
wp_die( -1 );
}
@ -1750,7 +1750,7 @@ class WC_AJAX {
public static function product_ordering() {
global $wpdb;
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( ! current_user_can( 'edit_products' ) || empty( $_POST['id'] ) ) {
wp_die( -1 );
}
@ -1792,6 +1792,8 @@ class WC_AJAX {
$wpdb->update( $wpdb->posts, array( 'menu_order' => $menu_orders[ $sorting_id ] ), array( 'ID' => $sorting_id ) );
WC_Post_Data::delete_product_query_transients();
do_action( 'woocommerce_after_product_ordering', $sorting_id, $menu_orders );
wp_send_json( $menu_orders );
// phpcs:enable
@ -2536,7 +2538,7 @@ class WC_AJAX {
* Handle submissions from assets/js/settings-views-html-settings-tax.js Backbone model.
*/
public static function tax_rates_save_changes() {
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
// phpcs:disable WordPress.Security.NonceVerification.Missing
if ( ! isset( $_POST['wc_tax_nonce'], $_POST['changes'] ) ) {
wp_send_json_error( 'missing_fields' );
wp_die();
@ -2603,7 +2605,7 @@ class WC_AJAX {
}
}
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
WC_Cache_Helper::invalidate_cache_group( 'taxes' );
WC_Cache_Helper::get_transient_version( 'shipping', true );
wp_send_json_success(

View File

@ -94,7 +94,7 @@ class WC_Cache_Helper {
$prefix = wp_cache_get( 'wc_' . $group . '_cache_prefix', $group );
if ( false === $prefix ) {
$prefix = 1;
$prefix = microtime();
wp_cache_set( 'wc_' . $group . '_cache_prefix', $prefix, $group );
}
@ -107,7 +107,18 @@ class WC_Cache_Helper {
* @param string $group Group of cache to clear.
*/
public static function incr_cache_prefix( $group ) {
wp_cache_incr( 'wc_' . $group . '_cache_prefix', 1, $group );
wc_deprecated_function( 'WC_Cache_Helper::incr_cache_prefix', '3.9.0', 'WC_Cache_Helper::invalidate_cache_group' );
self::invalidate_cache_group( $group );
}
/**
* Invalidate cache group.
*
* @param string $group Group of cache to clear.
* @since 3.9.0
*/
public static function invalidate_cache_group( $group ) {
wp_cache_set( 'wc_' . $group . '_cache_prefix', microtime(), $group );
}
/**

View File

@ -202,8 +202,9 @@ class WC_Data_Store {
*/
public function __call( $method, $parameters ) {
if ( is_callable( array( $this->instance, $method ) ) ) {
$object = array_shift( $parameters );
return call_user_func_array( array( $this->instance, $method ), array_merge( array( &$object ), $parameters ) );
$object = array_shift( $parameters );
$parameters = array_merge( array( &$object ), $parameters );
return $this->instance->$method( ...$parameters );
}
}
}

View File

@ -118,8 +118,10 @@ class WC_Emails {
/**
* Queues transactional email so it's not sent in current request if enabled,
* otherwise falls back to send now.
*
* @param mixed ...$args Optional arguments.
*/
public static function queue_transactional_email() {
public static function queue_transactional_email( ...$args ) {
if ( is_a( self::$background_emailer, 'WC_Background_Emailer' ) ) {
self::$background_emailer->push_to_queue(
array(
@ -128,7 +130,7 @@ class WC_Emails {
)
);
} else {
call_user_func_array( array( __CLASS__, 'send_transactional_email' ), func_get_args() ); // phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsUsage.InParameterList
self::send_transactional_email( ...$args );
}
}

View File

@ -113,7 +113,7 @@ class WC_Order extends WC_Abstract_Order {
$this->set_transaction_id( $transaction_id );
}
if ( ! $this->get_date_paid( 'edit' ) ) {
$this->set_date_paid( current_time( 'timestamp', true ) );
$this->set_date_paid( time() );
}
$this->set_status( apply_filters( 'woocommerce_payment_complete_order_status', $this->needs_processing() ? 'processing' : 'completed', $this->get_id(), $this ) );
$this->save();
@ -292,11 +292,11 @@ class WC_Order extends WC_Abstract_Order {
if ( $this->has_status( $payment_completed_status ) ) {
// If payment complete status is reached, set paid now.
$this->set_date_paid( current_time( 'timestamp', true ) );
$this->set_date_paid( time() );
} elseif ( 'processing' === $payment_completed_status && $this->has_status( 'completed' ) ) {
// If payment complete status was processing, but we've passed that and still have no date, set it now.
$this->set_date_paid( current_time( 'timestamp', true ) );
$this->set_date_paid( time() );
}
}
}
@ -310,7 +310,7 @@ class WC_Order extends WC_Abstract_Order {
*/
protected function maybe_set_date_completed() {
if ( $this->has_status( 'completed' ) ) {
$this->set_date_completed( current_time( 'timestamp', true ) );
$this->set_date_completed( time() );
}
}
@ -371,6 +371,21 @@ class WC_Order extends WC_Abstract_Order {
do_action( 'woocommerce_order_status_' . $status_transition['from'] . '_to_' . $status_transition['to'], $this->get_id(), $this );
do_action( 'woocommerce_order_status_changed', $this->get_id(), $status_transition['from'], $status_transition['to'], $this );
// Work out if this was for a payment, and trigger a payment_status hook instead.
if (
in_array( $status_transition['from'], apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ) ), true )
&& in_array( $status_transition['to'], wc_get_is_paid_statuses(), true )
) {
/**
* Fires when the order progresses from a pending payment status to a paid one.
*
* @since 3.9.0
* @param int Order ID
* @param WC_Order Order object
*/
do_action( 'woocommerce_order_payment_status_changed', $this->get_id(), $this );
}
} else {
/* translators: %s: new order status */
$transition_note = sprintf( __( 'Order status set to %s.', 'woocommerce' ), wc_get_order_status_name( $status_transition['to'] ) );

View File

@ -462,7 +462,7 @@ class WC_Post_Data {
* @param string $meta_value Meta value.
*/
public static function flush_object_meta_cache( $meta_id, $object_id, $meta_key, $meta_value ) {
WC_Cache_Helper::incr_cache_prefix( 'object_' . $object_id );
WC_Cache_Helper::invalidate_cache_group( 'object_' . $object_id );
}
/**

View File

@ -302,7 +302,7 @@ class WC_Session_Handler extends WC_Session {
$wpdb->query( $wpdb->prepare( "DELETE FROM $this->_table WHERE session_expiry < %d", time() ) ); // @codingStandardsIgnoreLine.
if ( class_exists( 'WC_Cache_Helper' ) ) {
WC_Cache_Helper::incr_cache_prefix( WC_SESSION_CACHE_GROUP );
WC_Cache_Helper::invalidate_cache_group( WC_SESSION_CACHE_GROUP );
}
}

View File

@ -29,7 +29,6 @@ class WC_Structured_Data {
add_action( 'woocommerce_before_main_content', array( $this, 'generate_website_data' ), 30 );
add_action( 'woocommerce_breadcrumb', array( $this, 'generate_breadcrumblist_data' ), 10 );
add_action( 'woocommerce_single_product_summary', array( $this, 'generate_product_data' ), 60 );
add_action( 'woocommerce_review_meta', array( $this, 'generate_review_data' ), 20 );
add_action( 'woocommerce_email_order_details', array( $this, 'generate_order_data' ), 20, 3 );
// Output structured data.
@ -279,38 +278,41 @@ class WC_Structured_Data {
'reviewCount' => $product->get_review_count(),
);
// Markup most recent rating/review.
// Markup 5 most recent rating/review.
$comments = get_comments(
array(
'number' => 1,
'number' => 5,
'post_id' => $product->get_id(),
'status' => 'approve',
'post_status' => 'publish',
'post_type' => 'product',
'parent' => 0,
'meta_key' => 'rating',
'orderby' => 'meta_value_num',
'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
array(
'key' => 'rating',
'type' => 'NUMERIC',
'compare' => '>',
'value' => 0,
),
),
)
);
if ( $comments ) {
$markup['review'] = array();
foreach ( $comments as $comment ) {
$rating = get_comment_meta( $comment->comment_ID, 'rating', true );
if ( ! $rating ) {
continue;
}
$markup['review'] = array(
'@type' => 'Review',
'reviewRating' => array(
$markup['review'][] = array(
'@type' => 'Review',
'reviewRating' => array(
'@type' => 'Rating',
'ratingValue' => $rating,
'ratingValue' => get_comment_meta( $comment->comment_ID, 'rating', true ),
),
'author' => array(
'author' => array(
'@type' => 'Person',
'name' => get_comment_author( $comment->comment_ID ),
'name' => get_comment_author( $comment ),
),
'reviewBody' => get_comment_text( $comment ),
'datePublished' => get_comment_date( 'c', $comment ),
);
}
}

View File

@ -907,7 +907,7 @@ class WC_Tax {
}
wp_cache_delete( 'tax-rate-classes', 'taxes' );
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
WC_Cache_Helper::invalidate_cache_group( 'taxes' );
return (bool) $delete;
}
@ -1025,7 +1025,7 @@ class WC_Tax {
$tax_rate_id = $wpdb->insert_id;
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
WC_Cache_Helper::invalidate_cache_group( 'taxes' );
do_action( 'woocommerce_tax_rate_added', $tax_rate_id, $tax_rate );
@ -1082,7 +1082,7 @@ class WC_Tax {
)
);
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
WC_Cache_Helper::invalidate_cache_group( 'taxes' );
do_action( 'woocommerce_tax_rate_updated', $tax_rate_id, $tax_rate );
}
@ -1101,7 +1101,7 @@ class WC_Tax {
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE tax_rate_id = %d;", $tax_rate_id ) );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d;", $tax_rate_id ) );
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
WC_Cache_Helper::invalidate_cache_group( 'taxes' );
do_action( 'woocommerce_tax_rate_deleted', $tax_rate_id );
}
@ -1176,7 +1176,7 @@ class WC_Tax {
$wpdb->query( "INSERT INTO {$wpdb->prefix}woocommerce_tax_rate_locations ( location_code, tax_rate_id, location_type ) VALUES $sql;" ); // @codingStandardsIgnoreLine.
}
WC_Cache_Helper::incr_cache_prefix( 'taxes' );
WC_Cache_Helper::invalidate_cache_group( 'taxes' );
}
/**

View File

@ -528,8 +528,25 @@ class WC_Tracker {
$gross_total = 0;
}
$processing_gross_total = $wpdb->get_var(
"
SELECT
SUM( order_meta.meta_value ) AS 'gross_total'
FROM {$wpdb->prefix}posts AS orders
LEFT JOIN {$wpdb->prefix}postmeta AS order_meta ON order_meta.post_id = orders.ID
WHERE order_meta.meta_key = '_order_total'
AND orders.post_status = 'wc-processing'
GROUP BY order_meta.meta_key
"
);
if ( is_null( $processing_gross_total ) ) {
$processing_gross_total = 0;
}
return array(
'gross' => $gross_total,
'gross' => $gross_total,
'processing_gross' => $processing_gross_total,
);
}
@ -559,7 +576,25 @@ class WC_Tracker {
);
}
return $min_max;
$processing_min_max = $wpdb->get_row(
"
SELECT
MIN( post_date_gmt ) as 'processing_first', MAX( post_date_gmt ) as 'processing_last'
FROM {$wpdb->prefix}posts
WHERE post_type = 'shop_order'
AND post_status = 'wc-processing'
",
ARRAY_A
);
if ( is_null( $processing_min_max ) ) {
$processing_min_max = array(
'processing_first' => '-',
'processing_last' => '-',
);
}
return array_merge( $min_max, $processing_min_max );
}
}

View File

@ -473,7 +473,7 @@ final class WooCommerce {
* @since 3.3.0
*/
private function theme_support_includes() {
if ( wc_is_active_theme( array( 'twentynineteen', 'twentyseventeen', 'twentysixteen', 'twentyfifteen', 'twentyfourteen', 'twentythirteen', 'twentyeleven', 'twentytwelve', 'twentyten' ) ) ) {
if ( wc_is_active_theme( array( 'twentytwenty', 'twentynineteen', 'twentyseventeen', 'twentysixteen', 'twentyfifteen', 'twentyfourteen', 'twentythirteen', 'twentyeleven', 'twentytwelve', 'twentyten' ) ) ) {
switch ( get_template() ) {
case 'twentyten':
include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-ten.php';
@ -502,6 +502,9 @@ final class WooCommerce {
case 'twentynineteen':
include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-nineteen.php';
break;
case 'twentytwenty':
include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-twenty.php';
break;
}
}
}

View File

@ -842,10 +842,10 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
wc_delete_product_transients( $product->get_id() );
if ( $product->get_parent_id( 'edit' ) ) {
wc_delete_product_transients( $product->get_parent_id( 'edit' ) );
WC_Cache_Helper::incr_cache_prefix( 'product_' . $product->get_parent_id( 'edit' ) );
WC_Cache_Helper::invalidate_cache_group( 'product_' . $product->get_parent_id( 'edit' ) );
}
WC_Cache_Helper::invalidate_attribute_count( array_keys( $product->get_attributes() ) );
WC_Cache_Helper::incr_cache_prefix( 'product_' . $product->get_id() );
WC_Cache_Helper::invalidate_cache_group( 'product_' . $product->get_id() );
}
/*

View File

@ -35,7 +35,7 @@ class WC_Shipping_Zone_Data_Store extends WC_Data_Store_WP implements WC_Shippin
$zone->save_meta_data();
$this->save_locations( $zone );
$zone->apply_changes();
WC_Cache_Helper::incr_cache_prefix( 'shipping_zones' );
WC_Cache_Helper::invalidate_cache_group( 'shipping_zones' );
WC_Cache_Helper::get_transient_version( 'shipping', true );
}
@ -60,7 +60,7 @@ class WC_Shipping_Zone_Data_Store extends WC_Data_Store_WP implements WC_Shippin
$zone->save_meta_data();
$this->save_locations( $zone );
$zone->apply_changes();
WC_Cache_Helper::incr_cache_prefix( 'shipping_zones' );
WC_Cache_Helper::invalidate_cache_group( 'shipping_zones' );
WC_Cache_Helper::get_transient_version( 'shipping', true );
}
@ -132,7 +132,7 @@ class WC_Shipping_Zone_Data_Store extends WC_Data_Store_WP implements WC_Shippin
$zone->set_id( null );
WC_Cache_Helper::incr_cache_prefix( 'shipping_zones' );
WC_Cache_Helper::invalidate_cache_group( 'shipping_zones' );
WC_Cache_Helper::get_transient_version( 'shipping', true );
do_action( 'woocommerce_delete_shipping_zone', $zone_id );

View File

@ -60,7 +60,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
$webhook->apply_changes();
$this->delete_transients( $webhook->get_status( 'edit' ) );
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
WC_Cache_Helper::invalidate_cache_group( 'webhooks' );
do_action( 'woocommerce_new_webhook', $webhook_id, $webhook );
}
@ -157,7 +157,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
$this->delete_transients( 'all' );
}
wp_cache_delete( $webhook->get_id(), 'webhooks' );
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
WC_Cache_Helper::invalidate_cache_group( 'webhooks' );
if ( 'active' === $webhook->get_status() && ( $trigger || $webhook->get_pending_delivery() ) ) {
$webhook->deliver_ping();
@ -184,7 +184,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
); // WPCS: cache ok, DB call ok.
$this->delete_transients( 'all' );
WC_Cache_Helper::incr_cache_prefix( 'webhooks' );
WC_Cache_Helper::invalidate_cache_group( 'webhooks' );
do_action( 'woocommerce_webhook_deleted', $webhook->get_id(), $webhook );
}

View File

@ -261,7 +261,7 @@ class WC_Email extends WC_Settings_API {
*/
public function handle_multipart( $mailer ) {
if ( $this->sending && 'multipart' === $this->get_email_type() ) {
$mailer->AltBody = wordwrap( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
$mailer->AltBody = wordwrap( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
preg_replace( $this->plain_search, $this->plain_replace, wp_strip_all_tags( $this->get_content_plain() ) )
);
$this->sending = false;
@ -634,7 +634,7 @@ class WC_Email extends WC_Settings_API {
$message = apply_filters( 'woocommerce_mail_content', $this->style_inline( $message ) );
$mail_callback = apply_filters( 'woocommerce_mail_callback', 'wp_mail', $this );
$mail_callback_params = apply_filters( 'woocommerce_mail_callback_params', array( $to, $subject, $message, $headers, $attachments ), $this );
$return = call_user_func_array( $mail_callback, $mail_callback_params );
$return = $mail_callback( ...$mail_callback_params );
remove_filter( 'wp_mail_from', array( $this, 'get_from_address' ) );
remove_filter( 'wp_mail_from_name', array( $this, 'get_from_name' ) );

View File

@ -2023,7 +2023,7 @@ class WC_API_Products extends WC_API_Resource {
// Clear transients
delete_transient( 'wc_attribute_taxonomies' );
WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' );
WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
$this->server->send_status( 201 );
@ -2109,7 +2109,7 @@ class WC_API_Products extends WC_API_Resource {
// Clear transients
delete_transient( 'wc_attribute_taxonomies' );
WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' );
WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
return $this->get_product_attribute( $id );
} catch ( WC_API_Exception $e ) {
@ -2171,7 +2171,7 @@ class WC_API_Products extends WC_API_Resource {
// Clear transients
delete_transient( 'wc_attribute_taxonomies' );
WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' );
WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), 'product_attribute' ) );
} catch ( WC_API_Exception $e ) {

View File

@ -2577,7 +2577,7 @@ class WC_API_Products extends WC_API_Resource {
// Clear transients.
wp_schedule_single_event( time(), 'woocommerce_flush_rewrite_rules' );
delete_transient( 'wc_attribute_taxonomies' );
WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' );
WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
$this->server->send_status( 201 );
@ -2664,7 +2664,7 @@ class WC_API_Products extends WC_API_Resource {
// Clear transients.
wp_schedule_single_event( time(), 'woocommerce_flush_rewrite_rules' );
delete_transient( 'wc_attribute_taxonomies' );
WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' );
WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
return $this->get_product_attribute( $id );
} catch ( WC_API_Exception $e ) {
@ -2727,7 +2727,7 @@ class WC_API_Products extends WC_API_Resource {
// Clear transients.
wp_schedule_single_event( time(), 'woocommerce_flush_rewrite_rules' );
delete_transient( 'wc_attribute_taxonomies' );
WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' );
WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
return array( 'message' => sprintf( __( 'Deleted %s', 'woocommerce' ), 'product_attribute' ) );
} catch ( WC_API_Exception $e ) {

View File

@ -107,7 +107,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
* `_x` with some default (the package name)
*/
protected function translate( $text, $context = '' ) {
return _x( $text, $context, $this->package );
return $text;
}
/**
@ -462,7 +462,7 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
echo '</select>';
}
submit_button( $this->translate( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
submit_button( __( 'Filter', 'woocommerce' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
echo '</div>';
}
@ -561,7 +561,8 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
protected function display_header() {
echo '<h1 class="wp-heading-inline">' . esc_attr( $this->table_header ) . '</h1>';
if ( $this->get_request_search_query() ) {
echo '<span class="subtitle">' . esc_attr( $this->translate( sprintf( 'Search results for "%s"', $this->get_request_search_query() ) ) ) . '</span>';
/* translators: %s: search query */
echo '<span class="subtitle">' . esc_attr( sprintf( __( 'Search results for "%s"', 'woocommerce' ), $this->get_request_search_query() ) ) . '</span>';
}
echo '<hr class="wp-header-end">';
}
@ -651,6 +652,6 @@ abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
* Get the text to display in the search box on the list table.
*/
protected function get_search_box_placeholder() {
return $this->translate( 'Search' );
return __( 'Search', 'woocommerce' );
}
}

View File

@ -19,7 +19,7 @@ class ActionScheduler_InvalidActionException extends \InvalidArgumentException i
*/
public static function from_decoding_args( $action_id ) {
$message = sprintf(
__( 'Action [%s] has invalid arguments. It cannot be JSON decoded to an array.', 'action-scheduler' ),
__( 'Action [%s] has invalid arguments. It cannot be JSON decoded to an array.', 'woocommerce' ),
$action_id
);

View File

@ -86,20 +86,20 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
$this->logger = $logger;
$this->runner = $runner;
$this->table_header = __( 'Scheduled Actions', 'action-scheduler' );
$this->table_header = __( 'Scheduled Actions', 'woocommerce' );
$this->bulk_actions = array(
'delete' => __( 'Delete', 'action-scheduler' ),
'delete' => __( 'Delete', 'woocommerce' ),
);
$this->columns = array(
'hook' => __( 'Hook', 'action-scheduler' ),
'status' => __( 'Status', 'action-scheduler' ),
'args' => __( 'Arguments', 'action-scheduler' ),
'group' => __( 'Group', 'action-scheduler' ),
'recurrence' => __( 'Recurrence', 'action-scheduler' ),
'schedule' => __( 'Scheduled Date', 'action-scheduler' ),
'log_entries' => __( 'Log', 'action-scheduler' ),
'hook' => __( 'Hook', 'woocommerce' ),
'status' => __( 'Status', 'woocommerce' ),
'args' => __( 'Arguments', 'woocommerce' ),
'group' => __( 'Group', 'woocommerce' ),
'recurrence' => __( 'Recurrence', 'woocommerce' ),
'schedule' => __( 'Scheduled Date', 'woocommerce' ),
'log_entries' => __( 'Log', 'woocommerce' ),
);
$this->sort_by = array(
@ -119,19 +119,19 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
if ( empty( $request_status ) ) {
$this->sort_by[] = 'status';
} elseif ( in_array( $request_status, array( 'in-progress', 'failed' ) ) ) {
$this->columns += array( 'claim_id' => __( 'Claim ID', 'action-scheduler' ) );
$this->columns += array( 'claim_id' => __( 'Claim ID', 'woocommerce' ) );
$this->sort_by[] = 'claim_id';
}
$this->row_actions = array(
'hook' => array(
'run' => array(
'name' => __( 'Run', 'action-scheduler' ),
'desc' => __( 'Process the action now as if it were run as part of a queue', 'action-scheduler' ),
'name' => __( 'Run', 'woocommerce' ),
'desc' => __( 'Process the action now as if it were run as part of a queue', 'woocommerce' ),
),
'cancel' => array(
'name' => __( 'Cancel', 'action-scheduler' ),
'desc' => __( 'Cancel the action now to avoid it being run in future', 'action-scheduler' ),
'name' => __( 'Cancel', 'woocommerce' ),
'desc' => __( 'Cancel the action now to avoid it being run in future', 'woocommerce' ),
'class' => 'cancel trash',
),
),
@ -140,31 +140,31 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
self::$time_periods = array(
array(
'seconds' => YEAR_IN_SECONDS,
'names' => _n_noop( '%s year', '%s years', 'action-scheduler' ),
'names' => _n_noop( '%s year', '%s years', 'woocommerce' ),
),
array(
'seconds' => MONTH_IN_SECONDS,
'names' => _n_noop( '%s month', '%s months', 'action-scheduler' ),
'names' => _n_noop( '%s month', '%s months', 'woocommerce' ),
),
array(
'seconds' => WEEK_IN_SECONDS,
'names' => _n_noop( '%s week', '%s weeks', 'action-scheduler' ),
'names' => _n_noop( '%s week', '%s weeks', 'woocommerce' ),
),
array(
'seconds' => DAY_IN_SECONDS,
'names' => _n_noop( '%s day', '%s days', 'action-scheduler' ),
'names' => _n_noop( '%s day', '%s days', 'woocommerce' ),
),
array(
'seconds' => HOUR_IN_SECONDS,
'names' => _n_noop( '%s hour', '%s hours', 'action-scheduler' ),
'names' => _n_noop( '%s hour', '%s hours', 'woocommerce' ),
),
array(
'seconds' => MINUTE_IN_SECONDS,
'names' => _n_noop( '%s minute', '%s minutes', 'action-scheduler' ),
'names' => _n_noop( '%s minute', '%s minutes', 'woocommerce' ),
),
array(
'seconds' => 1,
'names' => _n_noop( '%s second', '%s seconds', 'action-scheduler' ),
'names' => _n_noop( '%s second', '%s seconds', 'woocommerce' ),
),
);
@ -191,7 +191,7 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
private static function human_interval( $interval, $periods_to_include = 2 ) {
if ( $interval <= 0 ) {
return __( 'Now!', 'action-scheduler' );
return __( 'Now!', 'woocommerce' );
}
$output = '';
@ -204,7 +204,7 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
if ( ! empty( $output ) ) {
$output .= ' ';
}
$output .= sprintf( _n( self::$time_periods[ $time_period_index ]['names'][0], self::$time_periods[ $time_period_index ]['names'][1], $periods_in_interval, 'action-scheduler' ), $periods_in_interval );
$output .= sprintf( _n( self::$time_periods[ $time_period_index ]['names'][0], self::$time_periods[ $time_period_index ]['names'][1], $periods_in_interval, 'woocommerce' ), $periods_in_interval );
$seconds_remaining -= $periods_in_interval * self::$time_periods[ $time_period_index ]['seconds'];
$periods_included++;
}
@ -224,15 +224,15 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
$recurrence = $action->get_schedule();
if ( $recurrence->is_recurring() ) {
if ( method_exists( $recurrence, 'interval_in_seconds' ) ) {
return sprintf( __( 'Every %s', 'action-scheduler' ), self::human_interval( $recurrence->interval_in_seconds() ) );
return sprintf( __( 'Every %s', 'woocommerce' ), self::human_interval( $recurrence->interval_in_seconds() ) );
}
if ( method_exists( $recurrence, 'get_recurrence' ) ) {
return sprintf( __( 'Cron %s', 'action-scheduler' ), $recurrence->get_recurrence() );
return sprintf( __( 'Cron %s', 'woocommerce' ), $recurrence->get_recurrence() );
}
}
return __( 'Non-repeating', 'action-scheduler' );
return __( 'Non-repeating', 'woocommerce' );
}
/**
@ -318,7 +318,7 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
if ( $this->store->get_claim_count() >= $this->runner->get_allowed_concurrent_batches() ) {
$this->admin_notices[] = array(
'class' => 'updated',
'message' => sprintf( __( 'Maximum simultaneous batches already in progress (%s queues). No actions will be processed until the current batches are complete.', 'action-scheduler' ), $this->store->get_claim_count() ),
'message' => sprintf( __( 'Maximum simultaneous batches already in progress (%s queues). No actions will be processed until the current batches are complete.', 'woocommerce' ), $this->store->get_claim_count() ),
);
}
@ -333,18 +333,18 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
$class = 'updated';
switch ( $notification['row_action_type'] ) {
case 'run' :
$action_message_html = sprintf( __( 'Successfully executed action: %s', 'action-scheduler' ), $action_hook_html );
$action_message_html = sprintf( __( 'Successfully executed action: %s', 'woocommerce' ), $action_hook_html );
break;
case 'cancel' :
$action_message_html = sprintf( __( 'Successfully canceled action: %s', 'action-scheduler' ), $action_hook_html );
$action_message_html = sprintf( __( 'Successfully canceled action: %s', 'woocommerce' ), $action_hook_html );
break;
default :
$action_message_html = sprintf( __( 'Successfully processed change for action: %s', 'action-scheduler' ), $action_hook_html );
$action_message_html = sprintf( __( 'Successfully processed change for action: %s', 'woocommerce' ), $action_hook_html );
break;
}
} else {
$class = 'error';
$action_message_html = sprintf( __( 'Could not process change for action: "%s" (ID: %d). Error: %s', 'action-scheduler' ), $action_hook_html, esc_html( $notification['action_id'] ), esc_html( $notification['error_message'] ) );
$action_message_html = sprintf( __( 'Could not process change for action: "%s" (ID: %d). Error: %s', 'woocommerce' ), $action_hook_html, esc_html( $notification['action_id'] ), esc_html( $notification['error_message'] ) );
}
$action_message_html = apply_filters( 'action_scheduler_admin_notice_html', $action_message_html, $action, $notification );
@ -389,9 +389,9 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
$schedule_display_string .= '<br/>';
if ( gmdate( 'U' ) > $next_timestamp ) {
$schedule_display_string .= sprintf( __( ' (%s ago)', 'action-scheduler' ), self::human_interval( gmdate( 'U' ) - $next_timestamp ) );
$schedule_display_string .= sprintf( __( ' (%s ago)', 'woocommerce' ), self::human_interval( gmdate( 'U' ) - $next_timestamp ) );
} else {
$schedule_display_string .= sprintf( __( ' (%s)', 'action-scheduler' ), self::human_interval( $next_timestamp - gmdate( 'U' ) ) );
$schedule_display_string .= sprintf( __( ' (%s)', 'woocommerce' ), self::human_interval( $next_timestamp - gmdate( 'U' ) ) );
}
return $schedule_display_string;
@ -528,6 +528,6 @@ class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
* Get the text to display in the search box on the list table.
*/
protected function get_search_box_button_text() {
return __( 'Search hook, args and claim ID', 'action-scheduler' );
return __( 'Search hook, args and claim ID', 'woocommerce' );
}
}

View File

@ -59,44 +59,44 @@ abstract class ActionScheduler_Logger {
}
public function log_stored_action( $action_id ) {
$this->log( $action_id, __( 'action created', 'action-scheduler' ) );
$this->log( $action_id, __( 'action created', 'woocommerce' ) );
}
public function log_canceled_action( $action_id ) {
$this->log( $action_id, __( 'action canceled', 'action-scheduler' ) );
$this->log( $action_id, __( 'action canceled', 'woocommerce' ) );
}
public function log_started_action( $action_id ) {
$this->log( $action_id, __( 'action started', 'action-scheduler' ) );
$this->log( $action_id, __( 'action started', 'woocommerce' ) );
}
public function log_completed_action( $action_id ) {
$this->log( $action_id, __( 'action complete', 'action-scheduler' ) );
$this->log( $action_id, __( 'action complete', 'woocommerce' ) );
}
public function log_failed_action( $action_id, Exception $exception ) {
$this->log( $action_id, sprintf( __( 'action failed: %s', 'action-scheduler' ), $exception->getMessage() ) );
$this->log( $action_id, sprintf( __( 'action failed: %s', 'woocommerce' ), $exception->getMessage() ) );
}
public function log_timed_out_action( $action_id, $timeout ) {
$this->log( $action_id, sprintf( __( 'action timed out after %s seconds', 'action-scheduler' ), $timeout ) );
$this->log( $action_id, sprintf( __( 'action timed out after %s seconds', 'woocommerce' ), $timeout ) );
}
public function log_unexpected_shutdown( $action_id, $error ) {
if ( ! empty( $error ) ) {
$this->log( $action_id, sprintf( __( 'unexpected shutdown: PHP Fatal error %s in %s on line %s', 'action-scheduler' ), $error['message'], $error['file'], $error['line'] ) );
$this->log( $action_id, sprintf( __( 'unexpected shutdown: PHP Fatal error %s in %s on line %s', 'woocommerce' ), $error['message'], $error['file'], $error['line'] ) );
}
}
public function log_reset_action( $action_id ) {
$this->log( $action_id, __( 'action reset', 'action_scheduler' ) );
$this->log( $action_id, __( 'action reset', 'woocommerce' ) );
}
public function log_ignored_action( $action_id ) {
$this->log( $action_id, __( 'action ignored', 'action-scheduler' ) );
$this->log( $action_id, __( 'action ignored', 'woocommerce' ) );
}
public function log_failed_fetch_action( $action_id ) {
$this->log( $action_id, __( 'There was a failure fetching this action', 'action-scheduler' ) );
$this->log( $action_id, __( 'There was a failure fetching this action', 'woocommerce' ) );
}
}

View File

@ -107,7 +107,7 @@ class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
public function add_wp_cron_schedule( $schedules ) {
$schedules['every_minute'] = array(
'interval' => 60, // in seconds
'display' => __( 'Every minute' ),
'display' => __( 'Every minute', 'woocommerce' ),
);
return $schedules;

View File

@ -149,7 +149,7 @@ abstract class ActionScheduler_Store {
protected function get_scheduled_date_string( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
$next = null === $scheduled_date ? $action->get_schedule()->next() : $scheduled_date;
if ( ! $next ) {
throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'woocommerce' ) );
}
$next->setTimezone( new DateTimeZone( 'UTC' ) );
@ -166,7 +166,7 @@ abstract class ActionScheduler_Store {
protected function get_scheduled_date_string_local( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
$next = null === $scheduled_date ? $action->get_schedule()->next() : $scheduled_date;
if ( ! $next ) {
throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'woocommerce' ) );
}
ActionScheduler_TimezoneHelper::set_local_timezone( $next );
@ -178,11 +178,11 @@ abstract class ActionScheduler_Store {
*/
public function get_status_labels() {
return array(
self::STATUS_COMPLETE => __( 'Complete', 'action-scheduler' ),
self::STATUS_PENDING => __( 'Pending', 'action-scheduler' ),
self::STATUS_RUNNING => __( 'In-progress', 'action-scheduler' ),
self::STATUS_FAILED => __( 'Failed', 'action-scheduler' ),
self::STATUS_CANCELED => __( 'Canceled', 'action-scheduler' ),
self::STATUS_COMPLETE => __( 'Complete', 'woocommerce' ),
self::STATUS_PENDING => __( 'Pending', 'woocommerce' ),
self::STATUS_RUNNING => __( 'In-progress', 'woocommerce' ),
self::STATUS_FAILED => __( 'Failed', 'woocommerce' ),
self::STATUS_CANCELED => __( 'Canceled', 'woocommerce' ),
);
}

View File

@ -28,7 +28,7 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null ) {
if ( ! ( defined( 'WP_CLI' ) && WP_CLI ) ) {
/* translators: %s php class name */
throw new Exception( sprintf( __( 'The %s class can only be run within WP CLI.', 'action-scheduler' ), __CLASS__ ) );
throw new Exception( sprintf( __( 'The %s class can only be run within WP CLI.', 'woocommerce' ), __CLASS__ ) );
}
parent::__construct( $store, $monitor, $cleaner );
@ -56,9 +56,9 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
$too_many = $claim_count >= $this->get_allowed_concurrent_batches();
if ( $too_many ) {
if ( $force ) {
WP_CLI::warning( __( 'There are too many concurrent batches, but the run is forced to continue.', 'action-scheduler' ) );
WP_CLI::warning( __( 'There are too many concurrent batches, but the run is forced to continue.', 'woocommerce' ) );
} else {
WP_CLI::error( __( 'There are too many concurrent batches.', 'action-scheduler' ) );
WP_CLI::error( __( 'There are too many concurrent batches.', 'woocommerce' ) );
}
}
@ -89,7 +89,7 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
protected function setup_progress_bar() {
$count = count( $this->actions );
$this->progress_bar = \WP_CLI\Utils\make_progress_bar(
sprintf( _n( 'Running %d action', 'Running %d actions', $count, 'action-scheduler' ), number_format_i18n( $count ) ),
sprintf( _n( 'Running %d action', 'Running %d actions', $count, 'woocommerce' ), number_format_i18n( $count ) ),
$count
);
}
@ -106,7 +106,7 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
foreach ( $this->actions as $action_id ) {
// Error if we lost the claim.
if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $this->claim->get_id() ) ) ) {
WP_CLI::warning( __( 'The claim has been lost. Aborting current batch.', 'action-scheduler' ) );
WP_CLI::warning( __( 'The claim has been lost. Aborting current batch.', 'woocommerce' ) );
break;
}
@ -132,7 +132,7 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
*/
public function before_execute( $action_id ) {
/* translators: %s refers to the action ID */
WP_CLI::log( sprintf( __( 'Started processing action %s', 'action-scheduler' ), $action_id ) );
WP_CLI::log( sprintf( __( 'Started processing action %s', 'woocommerce' ), $action_id ) );
}
/**
@ -149,7 +149,7 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
$action = $this->store->fetch_action( $action_id );
}
/* translators: %s refers to the action ID */
WP_CLI::log( sprintf( __( 'Completed processing action %s with hook: %s', 'action-scheduler' ), $action_id, $action->get_hook() ) );
WP_CLI::log( sprintf( __( 'Completed processing action %s with hook: %s', 'woocommerce' ), $action_id, $action->get_hook() ) );
}
/**
@ -164,7 +164,7 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
public function action_failed( $action_id, $exception ) {
WP_CLI::error(
/* translators: %1$s refers to the action ID, %2$s refers to the Exception message */
sprintf( __( 'Error processing action %1$s: %2$s', 'action-scheduler' ), $action_id, $exception->getMessage() ),
sprintf( __( 'Error processing action %1$s: %2$s', 'woocommerce' ), $action_id, $exception->getMessage() ),
false
);
}
@ -176,11 +176,12 @@ class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRu
*/
protected function stop_the_insanity( $sleep_time = 0 ) {
if ( 0 < $sleep_time ) {
WP_CLI::warning( sprintf( 'Stopped the insanity for %d %s', $sleep_time, _n( 'second', 'seconds', $sleep_time ) ) );
/* translators: 1: sleep time 2: time unit */
WP_CLI::warning( sprintf( __( 'Stopped the insanity for %$1d %$2s', 'woocommerce' ), $sleep_time, _n( 'second', 'seconds', $sleep_time, 'woocommerce' ) ) );
sleep( $sleep_time );
}
WP_CLI::warning( __( 'Attempting to reduce used memory...', 'action-scheduler' ) );
WP_CLI::warning( __( 'Attempting to reduce used memory...', 'woocommerce' ) );
/**
* @var $wpdb \wpdb

View File

@ -84,7 +84,7 @@ class ActionScheduler_WPCLI_Scheduler_command extends WP_CLI_Command {
WP_CLI::log(
sprintf(
/* translators: %d refers to how many scheduled taks were found to run */
_n( 'Found %d scheduled task', 'Found %d scheduled tasks', $total, 'action-scheduler' ),
_n( 'Found %d scheduled task', 'Found %d scheduled tasks', $total, 'woocommerce' ),
number_format_i18n( $total )
)
);
@ -101,7 +101,7 @@ class ActionScheduler_WPCLI_Scheduler_command extends WP_CLI_Command {
WP_CLI::log(
sprintf(
/* translators: %d refers to the total number of batches executed */
_n( '%d batch executed.', '%d batches executed.', $batches_completed, 'action-scheduler' ),
_n( '%d batch executed.', '%d batches executed.', $batches_completed, 'woocommerce' ),
number_format_i18n( $batches_completed )
)
);
@ -120,7 +120,7 @@ class ActionScheduler_WPCLI_Scheduler_command extends WP_CLI_Command {
WP_CLI::error(
sprintf(
/* translators: %s refers to the exception error message. */
__( 'There was an error running the action scheduler: %s', 'action-scheduler' ),
__( 'There was an error running the action scheduler: %s', 'woocommerce' ),
$e->getMessage()
)
);
@ -137,7 +137,7 @@ class ActionScheduler_WPCLI_Scheduler_command extends WP_CLI_Command {
WP_CLI::success(
sprintf(
/* translators: %d refers to the total number of taskes completed */
_n( '%d scheduled task completed.', '%d scheduled tasks completed.', $actions_completed, 'action-scheduler' ),
_n( '%d scheduled task completed.', '%d scheduled tasks completed.', $actions_completed, 'woocommerce' ),
number_format_i18n( $actions_completed )
)
);

View File

@ -97,14 +97,14 @@ class ActionScheduler_wcSystemStatus {
<table class="wc_status_table widefat" cellspacing="0">
<thead>
<tr>
<th colspan="5" data-export-label="Action Scheduler"><h2><?php esc_html_e( 'Action Scheduler', 'action-scheduler' ); ?><?php echo wc_help_tip( esc_html__( 'This section shows scheduled action counts.', 'action-scheduler' ) ); ?></h2></th>
<th colspan="5" data-export-label="Action Scheduler"><h2><?php esc_html_e( 'Action Scheduler', 'woocommerce' ); ?><?php echo wc_help_tip( esc_html__( 'This section shows scheduled action counts.', 'woocommerce' ) ); ?></h2></th>
</tr>
<tr>
<td><strong><?php esc_html_e( 'Action Status', 'action-scheduler' ); ?></strong></td>
<td><strong><?php esc_html_e( 'Action Status', 'woocommerce' ); ?></strong></td>
<td class="help">&nbsp;</td>
<td><strong><?php esc_html_e( 'Count', 'action-scheduler' ); ?></strong></td>
<td><strong><?php esc_html_e( 'Oldest Scheduled Date', 'action-scheduler' ); ?></strong></td>
<td><strong><?php esc_html_e( 'Newest Scheduled Date', 'action-scheduler' ); ?></strong></td>
<td><strong><?php esc_html_e( 'Count', 'woocommerce' ); ?></strong></td>
<td><strong><?php esc_html_e( 'Oldest Scheduled Date', 'woocommerce' ); ?></strong></td>
<td><strong><?php esc_html_e( 'Newest Scheduled Date', 'woocommerce' ); ?></strong></td>
</tr>
</thead>
<tbody>

View File

@ -30,7 +30,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
do_action( 'action_scheduler_stored_action', $post_id );
return $post_id;
} catch ( Exception $e ) {
throw new RuntimeException( sprintf( __('Error saving action: %s', 'action-scheduler'), $e->getMessage() ), 0 );
throw new RuntimeException( sprintf( __('Error saving action: %s', 'woocommerce'), $e->getMessage() ), 0 );
}
}
@ -54,7 +54,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
if ( is_wp_error($post_id) || empty($post_id) ) {
throw new RuntimeException(__('Unable to save action.', 'action-scheduler'));
throw new RuntimeException(__('Unable to save action.', 'woocommerce'));
}
return $post_id;
}
@ -275,7 +275,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
throw new InvalidArgumentException(__('Invalid schedule. Cannot save action.', 'action-scheduler'));
throw new InvalidArgumentException(__('Invalid schedule. Cannot save action.', 'woocommerce'));
}
$query = wp_parse_args( $query, array(
@ -448,7 +448,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
public function cancel_action( $action_id ) {
$post = get_post($action_id);
if ( empty($post) || ($post->post_type != self::POST_TYPE) ) {
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
do_action( 'action_scheduler_canceled_action', $action_id );
add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
@ -459,7 +459,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
public function delete_action( $action_id ) {
$post = get_post($action_id);
if ( empty($post) || ($post->post_type != self::POST_TYPE) ) {
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
do_action( 'action_scheduler_deleted_action', $action_id );
wp_delete_post($action_id, TRUE);
@ -485,7 +485,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
public function get_date_gmt( $action_id ) {
$post = get_post($action_id);
if ( empty($post) || ($post->post_type != self::POST_TYPE) ) {
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
if ( $post->post_status == 'publish' ) {
return as_get_datetime_object($post->post_modified_gmt);
@ -597,7 +597,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
// Run the query and gather results.
$rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) );
if ( $rows_affected === false ) {
throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'woocommerce' ) );
}
return (int) $rows_affected;
@ -617,7 +617,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
protected function get_actions_by_group( $group, $limit, DateTime $date ) {
// Ensure the group exists before continuing.
if ( ! term_exists( $group, self::GROUP_TAXONOMY )) {
throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'woocommerce' ), $group ) );
}
// Set up a query for post IDs to use later.
@ -678,7 +678,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
$sql = $wpdb->prepare( $sql, array( $claim->get_id() ) );
$result = $wpdb->query($sql);
if ( $result === false ) {
throw new RuntimeException( sprintf( __('Unable to unlock claim %s. Database error.', 'action-scheduler'), $claim->get_id() ) );
throw new RuntimeException( sprintf( __('Unable to unlock claim %s. Database error.', 'woocommerce'), $claim->get_id() ) );
}
}
@ -692,7 +692,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
$sql = $wpdb->prepare( $sql, $action_id, self::POST_TYPE );
$result = $wpdb->query($sql);
if ( $result === false ) {
throw new RuntimeException( sprintf( __('Unable to unlock claim on action %s. Database error.', 'action-scheduler'), $action_id ) );
throw new RuntimeException( sprintf( __('Unable to unlock claim on action %s. Database error.', 'woocommerce'), $action_id ) );
}
}
@ -703,7 +703,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
$sql = $wpdb->prepare( $sql, self::STATUS_FAILED, $action_id, self::POST_TYPE );
$result = $wpdb->query($sql);
if ( $result === false ) {
throw new RuntimeException( sprintf( __('Unable to mark failure on action %s. Database error.', 'action-scheduler'), $action_id ) );
throw new RuntimeException( sprintf( __('Unable to mark failure on action %s. Database error.', 'woocommerce'), $action_id ) );
}
}
@ -727,7 +727,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
$status = $this->get_post_column( $action_id, 'post_status' );
if ( $status === null ) {
throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'woocommerce' ) );
}
return $this->get_action_status_by_post_status( $status );
@ -755,7 +755,7 @@ class ActionScheduler_wpPostStore extends ActionScheduler_Store {
public function mark_complete( $action_id ) {
$post = get_post($action_id);
if ( empty($post) || ($post->post_type != self::POST_TYPE) ) {
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'woocommerce'), $action_id));
}
add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );

View File

@ -33,8 +33,8 @@ class ActionScheduler_wpPostStore_PostStatusRegistrar {
*/
protected function post_status_failed_labels() {
$labels = array(
'label' => _x( 'Failed', 'post' ),
'label_count' => _n_noop( 'Failed <span class="count">(%s)</span>', 'Failed <span class="count">(%s)</span>' ),
'label' => _x( 'Failed', 'post', 'woocommerce' ),
'label_count' => _n_noop( 'Failed <span class="count">(%s)</span>', 'Failed <span class="count">(%s)</span>', 'woocommerce' ),
);
return apply_filters( 'action_scheduler_post_status_failed_labels', $labels );
@ -47,11 +47,10 @@ class ActionScheduler_wpPostStore_PostStatusRegistrar {
*/
protected function post_status_running_labels() {
$labels = array(
'label' => _x( 'In-Progress', 'post' ),
'label_count' => _n_noop( 'In-Progress <span class="count">(%s)</span>', 'In-Progress <span class="count">(%s)</span>' ),
'label' => _x( 'In-Progress', 'post', 'woocommerce' ),
'label_count' => _n_noop( 'In-Progress <span class="count">(%s)</span>', 'In-Progress <span class="count">(%s)</span>', 'woocommerce' ),
);
return apply_filters( 'action_scheduler_post_status_running_labels', $labels );
}
}

View File

@ -30,9 +30,9 @@ class ActionScheduler_wpPostStore_PostTypeRegistrar {
'name' => __( 'Scheduled Actions', 'woocommerce' ),
'singular_name' => __( 'Scheduled Action', 'woocommerce' ),
'menu_name' => _x( 'Scheduled Actions', 'Admin menu name', 'woocommerce' ),
'add_new' => __( 'Add', 'action-scheduler' ),
'add_new' => __( 'Add', 'woocommerce' ),
'add_new_item' => __( 'Add New Scheduled Action', 'woocommerce' ),
'edit' => __( 'Edit', 'action-scheduler' ),
'edit' => __( 'Edit', 'woocommerce' ),
'edit_item' => __( 'Edit Scheduled Action', 'woocommerce' ),
'new_item' => __( 'New Scheduled Action', 'woocommerce' ),
'view' => __( 'View Action', 'woocommerce' ),
@ -47,4 +47,4 @@ class ActionScheduler_wpPostStore_PostTypeRegistrar {
return $args;
}
}

View File

@ -11,7 +11,7 @@ class ActionScheduler_wpPostStore_TaxonomyRegistrar {
protected function taxonomy_args() {
$args = array(
'label' => __('Action Group', 'action-scheduler'),
'label' => __('Action Group', 'woocommerce'),
'public' => false,
'hierarchical' => false,
'show_admin_column' => true,
@ -23,4 +23,3 @@ class ActionScheduler_wpPostStore_TaxonomyRegistrar {
return $args;
}
}

View File

@ -179,7 +179,7 @@ class WC_Shortcode_Products {
'post_status' => 'publish',
'ignore_sticky_posts' => true,
'no_found_rows' => false === wc_string_to_bool( $this->attributes['paginate'] ),
'orderby' => empty( $_GET['orderby'] ) ? $this->attributes['orderby'] : wc_clean( wp_unslash( $_GET['orderby'] ) ), // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
'orderby' => empty( $_GET['orderby'] ) ? $this->attributes['orderby'] : wc_clean( wp_unslash( $_GET['orderby'] ) ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended
);
$orderby_value = explode( '-', $query_args['orderby'] );

View File

@ -0,0 +1,105 @@
<?php
/**
* Twenty Twenty support.
*
* @since 3.8.1
* @package WooCommerce/Classes
*/
defined( 'ABSPATH' ) || exit;
/**
* WC_Twenty_Twenty class.
*/
class WC_Twenty_Twenty {
/**
* Theme init.
*/
public static function init() {
// Change WooCommerce wrappers.
remove_action( 'woocommerce_before_main_content', 'woocommerce_output_content_wrapper', 10 );
remove_action( 'woocommerce_after_main_content', 'woocommerce_output_content_wrapper_end', 10 );
add_action( 'woocommerce_before_main_content', array( __CLASS__, 'output_content_wrapper' ), 10 );
add_action( 'woocommerce_after_main_content', array( __CLASS__, 'output_content_wrapper_end' ), 10 );
// This theme doesn't have a traditional sidebar.
remove_action( 'woocommerce_sidebar', 'woocommerce_get_sidebar', 10 );
// Enqueue theme compatibility styles.
add_filter( 'woocommerce_enqueue_styles', array( __CLASS__, 'enqueue_styles' ) );
// Register theme features.
add_theme_support( 'wc-product-gallery-zoom' );
add_theme_support( 'wc-product-gallery-lightbox' );
add_theme_support( 'wc-product-gallery-slider' );
add_theme_support(
'woocommerce',
array(
'thumbnail_image_width' => 450,
'single_image_width' => 600,
)
);
// Background color change.
add_action( 'after_setup_theme', array( __CLASS__, 'set_white_background' ), 10 );
}
/**
* Open the Twenty Twenty wrapper.
*/
public static function output_content_wrapper() {
echo '<section id="primary" class="content-area">';
echo '<main id="main" class="site-main">';
}
/**
* Close the Twenty Twenty wrapper.
*/
public static function output_content_wrapper_end() {
echo '</main>';
echo '</section>';
}
/**
* Set background color to white if it's default, otherwise don't touch it.
*/
public static function set_white_background() {
$background = sanitize_hex_color_no_hash( get_theme_mod( 'background_color' ) );
$background_default = 'f5efe0';
// Don't change user's choice of background color.
if ( ! empty( $background ) && $background !== $background_default ) {
return;
}
// In case default background is found, change it to white.
set_theme_mod( 'background_color', 'fff' );
}
/**
* Enqueue CSS for this theme.
*
* @param array $styles Array of registered styles.
* @return array
*/
public static function enqueue_styles( $styles ) {
unset( $styles['woocommerce-general'] );
$styles['woocommerce-general'] = array(
'src' => str_replace( array( 'http:', 'https:' ), '', WC()->plugin_url() ) . '/assets/css/twenty-twenty.css',
'deps' => '',
'version' => WC_VERSION,
'media' => 'all',
'has_rtl' => true,
);
return apply_filters( 'woocommerce_twenty_twenty_styles', $styles );
}
}
WC_Twenty_Twenty::init();

View File

@ -611,7 +611,7 @@ function wc_create_attribute( $args ) {
// Clear cache and flush rewrite rules.
wp_schedule_single_event( time(), 'woocommerce_flush_rewrite_rules' );
delete_transient( 'wc_attribute_taxonomies' );
WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' );
WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
return $id;
}
@ -701,7 +701,7 @@ function wc_delete_attribute( $id ) {
do_action( 'woocommerce_attribute_deleted', $id, $name, $taxonomy );
wp_schedule_single_event( time(), 'woocommerce_flush_rewrite_rules' );
delete_transient( 'wc_attribute_taxonomies' );
WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' );
WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
return true;
}

View File

@ -1826,7 +1826,7 @@ function wc_print_r( $expression, $return = false ) {
foreach ( $alternatives as $alternative ) {
if ( function_exists( $alternative['func'] ) ) {
$res = call_user_func_array( $alternative['func'], $alternative['args'] );
$res = $alternative['func']( ...$alternative['args'] );
if ( $return ) {
return $res;
}

View File

@ -136,9 +136,12 @@ function wc_print_notices( $return = false ) {
foreach ( $notice_types as $notice_type ) {
if ( wc_notice_count( $notice_type ) > 0 ) {
wc_get_template( "notices/{$notice_type}.php", array(
'messages' => array_filter( $all_notices[ $notice_type ] ),
) );
wc_get_template(
"notices/{$notice_type}.php",
array(
'messages' => array_filter( $all_notices[ $notice_type ] ),
)
);
}
}
@ -165,9 +168,12 @@ function wc_print_notice( $message, $notice_type = 'success' ) {
$message = apply_filters( 'woocommerce_add_message', $message );
}
wc_get_template( "notices/{$notice_type}.php", array(
'messages' => array( apply_filters( 'woocommerce_add_' . $notice_type, $message ) ),
) );
wc_get_template(
"notices/{$notice_type}.php",
array(
'messages' => array( apply_filters( 'woocommerce_add_' . $notice_type, $message ) ),
)
);
}
/**
@ -217,14 +223,20 @@ function wc_add_wp_error_notices( $errors ) {
* @return string
*/
function wc_kses_notice( $message ) {
return wp_kses( $message,
array_replace_recursive( // phpcs:ignore PHPCompatibility.PHP.NewFunctions.array_replace_recursiveFound
wp_kses_allowed_html( 'post' ),
array(
'a' => array(
'tabindex' => true,
),
)
$allowed_tags = array_replace_recursive(
wp_kses_allowed_html( 'post' ),
array(
'a' => array(
'tabindex' => true,
),
)
);
/**
* Kses notice allowed tags.
*
* @since 3.9.0
* @param array[]|string $allowed_tags An array of allowed HTML elements and attributes, or a context name such as 'post'.
*/
return wp_kses( $message, apply_filters( 'woocommerce_kses_notice_allowed_tags', $allowed_tags ) );
}

View File

@ -464,7 +464,7 @@ function wc_delete_shop_order_transients( $order = 0 ) {
WC_Cache_Helper::get_transient_version( 'orders', true );
// Do the same for regular cache.
WC_Cache_Helper::incr_cache_prefix( 'orders' );
WC_Cache_Helper::invalidate_cache_group( 'orders' );
do_action( 'woocommerce_delete_shop_order_transients', $order_id );
}

View File

@ -104,7 +104,7 @@ function wc_delete_order_item( $item_id ) {
function wc_update_order_item_meta( $item_id, $meta_key, $meta_value, $prev_value = '' ) {
$data_store = WC_Data_Store::load( 'order-item' );
if ( $data_store->update_metadata( $item_id, $meta_key, $meta_value, $prev_value ) ) {
WC_Cache_Helper::incr_cache_prefix( 'object_' . $item_id ); // Invalidate cache.
WC_Cache_Helper::invalidate_cache_group( 'object_' . $item_id ); // Invalidate cache.
return true;
}
return false;
@ -126,7 +126,7 @@ function wc_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = fal
$meta_id = $data_store->add_metadata( $item_id, $meta_key, $meta_value, $unique );
if ( $meta_id ) {
WC_Cache_Helper::incr_cache_prefix( 'object_' . $item_id ); // Invalidate cache.
WC_Cache_Helper::invalidate_cache_group( 'object_' . $item_id ); // Invalidate cache.
return $meta_id;
}
return 0;
@ -146,7 +146,7 @@ function wc_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = fal
function wc_delete_order_item_meta( $item_id, $meta_key, $meta_value = '', $delete_all = false ) {
$data_store = WC_Data_Store::load( 'order-item' );
if ( $data_store->delete_metadata( $item_id, $meta_key, $meta_value, $delete_all ) ) {
WC_Cache_Helper::incr_cache_prefix( 'object_' . $item_id ); // Invalidate cache.
WC_Cache_Helper::invalidate_cache_group( 'object_' . $item_id ); // Invalidate cache.
return true;
}
return false;

View File

@ -715,7 +715,7 @@ function wc_get_product_attachment_props( $attachment_id = null, $product = fals
);
$attachment = get_post( $attachment_id );
if ( $attachment ) {
if ( $attachment && 'attachment' === $attachment->post_type ) {
$props['title'] = wp_strip_all_tags( $attachment->post_title );
$props['caption'] = wp_strip_all_tags( $attachment->post_excerpt );
$props['url'] = wp_get_attachment_url( $attachment_id );

View File

@ -253,11 +253,10 @@ function wc_product_dropdown_categories( $args = array() ) {
*
* Previously used by wc_product_dropdown_categories, but wp_dropdown_categories has been fixed in core.
*
* @param mixed ...$args Variable number of parameters to be passed to the walker.
* @return mixed
*/
function wc_walk_category_dropdown_tree() {
$args = func_get_args();
function wc_walk_category_dropdown_tree( ...$args ) {
if ( ! class_exists( 'WC_Product_Cat_Dropdown_Walker', false ) ) {
include_once WC()->plugin_path() . '/includes/walkers/class-wc-product-cat-dropdown-walker.php';
}
@ -269,7 +268,7 @@ function wc_walk_category_dropdown_tree() {
$walker = $args[2]['walker'];
}
return call_user_func_array( array( &$walker, 'walk' ), $args );
return $walker->walk( ...$args );
}
/**

View File

@ -674,7 +674,7 @@ function wc_update_220_attributes() {
}
delete_transient( 'wc_attribute_taxonomies' );
WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' );
WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
}
/**

View File

@ -15,6 +15,13 @@ defined( 'ABSPATH' ) || exit;
*/
class WC_WCCOM_Site_Installer {
/**
* Error message returned install_package if the folder already exists.
*
* @var string
*/
private static $folder_exists = 'folder_exists';
/**
* Default state.
*
@ -240,6 +247,7 @@ class WC_WCCOM_Site_Installer {
case 'get_product_info':
$state_steps[ $product_id ]['download_url'] = $result['download_url'];
$state_steps[ $product_id ]['product_type'] = $result['product_type'];
$state_steps[ $product_id ]['product_name'] = $result['product_name'];
break;
case 'download_product':
$state_steps[ $product_id ]['download_path'] = $result;
@ -249,6 +257,12 @@ class WC_WCCOM_Site_Installer {
break;
case 'move_product':
$state_steps[ $product_id ]['installed_path'] = $result['destination'];
if ( $result[ self::$folder_exists ] ) {
$state_steps[ $product_id ]['warning'] = array(
'message' => self::$folder_exists,
'plugin_info' => self::get_plugin_info( $state_steps[ $product_id ]['installed_path'] ),
);
}
break;
}
}
@ -287,6 +301,7 @@ class WC_WCCOM_Site_Installer {
$result = json_decode( wp_remote_retrieve_body( $request ), true );
$product_info['product_type'] = $result['_product_type'];
$product_info['product_name'] = $result['name'];
if ( ! empty( $result['_wporg_product'] ) && ! empty( $result['download_link'] ) ) {
// For wporg product, download is set already from info response.
@ -369,7 +384,18 @@ class WC_WCCOM_Site_Installer {
),
);
return $upgrader->install_package( $package );
$result = $upgrader->install_package( $package );
/**
* If install package returns error 'folder_exists' threat as success.
*/
if ( is_wp_error( $result ) && array_key_exists( self::$folder_exists, $result->errors ) ) {
return array(
self::$folder_exists => true,
'destination' => $result->error_data[ self::$folder_exists ],
);
}
return $result;
}
/**
@ -511,4 +537,41 @@ class WC_WCCOM_Site_Installer {
return false;
}
/**
* Get plugin info
*
* @since 3.9.0
* @param string $dir Directory name of the plugin.
* @return bool|array
*/
private static function get_plugin_info( $dir ) {
$plugin_folder = basename( $dir );
if ( ! function_exists( 'get_plugins' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$plugins = get_plugins();
$related_plugins = array_filter(
$plugins,
function( $key ) use ( $plugin_folder ) {
return strpos( $key, $plugin_folder . '/' ) === 0;
},
ARRAY_FILTER_USE_KEY
);
if ( 1 === count( $related_plugins ) ) {
$plugin_key = array_keys( $related_plugins )[0];
$plugin_data = $plugins[ $plugin_key ];
return array(
'name' => $plugin_data['Name'],
'version' => $plugin_data['Version'],
'active' => is_plugin_active( $plugin_key ),
);
}
return false;
}
}

View File

@ -15,6 +15,8 @@ defined( 'ABSPATH' ) || exit;
*/
class WC_WCCOM_Site {
const AUTH_ERROR_FILTER_NAME = 'wccom_auth_error';
/**
* Load the WCCOM site class.
*
@ -53,23 +55,78 @@ class WC_WCCOM_Site {
$auth_header = self::get_authorization_header();
if ( empty( $auth_header ) ) {
add_filter(
self::AUTH_ERROR_FILTER_NAME,
function() {
return new WP_Error(
WC_REST_WCCOM_Site_Installer_Errors::NO_AUTH_HEADER_CODE,
WC_REST_WCCOM_Site_Installer_Errors::NO_AUTH_HEADER_MESSAGE,
array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::NO_AUTH_HEADER_HTTP_CODE )
);
}
);
return false;
}
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$request_auth = trim( $auth_header );
if ( stripos( $request_auth, 'Bearer ' ) !== 0 ) {
add_filter(
self::AUTH_ERROR_FILTER_NAME,
function() {
return new WP_Error(
WC_REST_WCCOM_Site_Installer_Errors::INVALID_AUTH_HEADER_CODE,
WC_REST_WCCOM_Site_Installer_Errors::INVALID_AUTH_HEADER_MESSAGE,
array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::INVALID_AUTH_HEADER_HTTP_CODE )
);
}
);
return false;
}
if ( empty( $_SERVER['HTTP_X_WOO_SIGNATURE'] ) ) {
add_filter(
self::AUTH_ERROR_FILTER_NAME,
function() {
return new WP_Error(
WC_REST_WCCOM_Site_Installer_Errors::NO_SIGNATURE_HEADER_CODE,
WC_REST_WCCOM_Site_Installer_Errors::NO_SIGNATURE_HEADER_MESSAGE,
array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::NO_SIGNATURE_HEADER_HTTP_CODE )
);
}
);
return false;
}
require_once WC_ABSPATH . 'includes/admin/helper/class-wc-helper-options.php';
$access_token = trim( substr( $request_auth, 7 ) );
$site_auth = WC_Helper_Options::get( 'auth' );
if ( empty( $site_auth['access_token'] ) || ! hash_equals( $access_token, $site_auth['access_token'] ) ) {
if ( empty( $site_auth['access_token'] ) ) {
add_filter(
self::AUTH_ERROR_FILTER_NAME,
function() {
return new WP_Error(
WC_REST_WCCOM_Site_Installer_Errors::SITE_NOT_CONNECTED_CODE,
WC_REST_WCCOM_Site_Installer_Errors::SITE_NOT_CONNECTED_MESSAGE,
array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::SITE_NOT_CONNECTED_HTTP_CODE )
);
}
);
return false;
}
if ( ! hash_equals( $access_token, $site_auth['access_token'] ) ) {
add_filter(
self::AUTH_ERROR_FILTER_NAME,
function() {
return new WP_Error(
WC_REST_WCCOM_Site_Installer_Errors::INVALID_TOKEN_CODE,
WC_REST_WCCOM_Site_Installer_Errors::INVALID_TOKEN_MESSAGE,
array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::INVALID_TOKEN_HTTP_CODE )
);
}
);
return false;
}
@ -77,11 +134,31 @@ class WC_WCCOM_Site {
$signature = trim( $_SERVER['HTTP_X_WOO_SIGNATURE'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( ! self::verify_wccom_request( $body, $signature, $site_auth['access_token_secret'] ) ) {
add_filter(
self::AUTH_ERROR_FILTER_NAME,
function() {
return new WP_Error(
WC_REST_WCCOM_Site_Installer_Errors::REQUEST_VERIFICATION_FAILED_CODE,
WC_REST_WCCOM_Site_Installer_Errors::REQUEST_VERIFICATION_FAILED_MESSAGE,
array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::REQUEST_VERIFICATION_FAILED_HTTP_CODE )
);
}
);
return false;
}
$user = get_user_by( 'id', $site_auth['user_id'] );
if ( ! $user ) {
add_filter(
self::AUTH_ERROR_FILTER_NAME,
function() {
return new WP_Error(
WC_REST_WCCOM_Site_Installer_Errors::USER_NOT_FOUND_CODE,
WC_REST_WCCOM_Site_Installer_Errors::USER_NOT_FOUND_MESSAGE,
array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::USER_NOT_FOUND_HTTP_CODE )
);
}
);
return false;
}
@ -166,6 +243,7 @@ class WC_WCCOM_Site {
* @return array Registered namespaces.
*/
public static function register_rest_namespace( $namespaces ) {
require_once WC_ABSPATH . 'includes/wccom-site/rest-api/class-wc-rest-wccom-site-installer-errors.php';
require_once WC_ABSPATH . 'includes/wccom-site/rest-api/endpoints/class-wc-rest-wccom-site-installer-controller.php';
$namespaces['wccom-site/v1'] = array(

View File

@ -0,0 +1,80 @@
<?php
/**
* WCCOM Site Installer Errors Class
*
* @package WooCommerce\WooCommerce_Site\Rest_Api
* @since 3.9.0
*/
defined( 'ABSPATH' ) || exit;
/**
* WCCOM Site Installer Errors Class
*
* Stores data for errors, returned by installer API.
*/
class WC_REST_WCCOM_Site_Installer_Errors {
/**
* Not unauthenticated generic error
*/
const NOT_AUTHENTICATED_CODE = 'not_authenticated';
const NOT_AUTHENTICATED_MESSAGE = 'Authentication required';
const NOT_AUTHENTICATED_HTTP_CODE = 401;
/**
* No Authorization header
*/
const NO_AUTH_HEADER_CODE = 'no_auth_header';
const NO_AUTH_HEADER_MESSAGE = 'No header "Authorization" present';
const NO_AUTH_HEADER_HTTP_CODE = 400;
/**
* Authorization header invalid
*/
const INVALID_AUTH_HEADER_CODE = 'no_auth_header';
const INVALID_AUTH_HEADER_MESSAGE = 'Header "Authorization" is invalid';
const INVALID_AUTH_HEADER_HTTP_CODE = 400;
/**
* No Signature header
*/
const NO_SIGNATURE_HEADER_CODE = 'no_signature_header';
const NO_SIGNATURE_HEADER_MESSAGE = 'No header "X-Woo-Signature" present';
const NO_SIGNATURE_HEADER_HTTP_CODE = 400;
/**
* Site not connected to WooCommerce.com
*/
const SITE_NOT_CONNECTED_CODE = 'site_not_connnected';
const SITE_NOT_CONNECTED_MESSAGE = 'Site not connected to WooCommerce.com';
const SITE_NOT_CONNECTED_HTTP_CODE = 401;
/**
* Provided access token is not valid
*/
const INVALID_TOKEN_CODE = 'invalid_token';
const INVALID_TOKEN_MESSAGE = 'Invalid access token provided';
const INVALID_TOKEN_HTTP_CODE = 401;
/**
* Request verification by provided signature failed
*/
const REQUEST_VERIFICATION_FAILED_CODE = 'request_verification_failed';
const REQUEST_VERIFICATION_FAILED_MESSAGE = 'Request verification by signature failed';
const REQUEST_VERIFICATION_FAILED_HTTP_CODE = 400;
/**
* User doesn't exist
*/
const USER_NOT_FOUND_CODE = 'user_not_found';
const USER_NOT_FOUND_MESSAGE = 'Token owning user not found';
const USER_NOT_FOUND_HTTP_CODE = 401;
/**
* No permissions error
*/
const NO_PERMISSION_CODE = 'forbidden';
const NO_PERMISSION_MESSAGE = 'You do not have permission to install plugin or theme';
const NO_PERMISSION_HTTP_CODE = 403;
}

View File

@ -69,8 +69,25 @@ class WC_REST_WCCOM_Site_Installer_Controller extends WC_REST_Controller {
* @return bool|WP_Error
*/
public function check_permission( $request ) {
if ( ! current_user_can( 'install_plugins' ) || ! current_user_can( 'install_themes' ) ) {
return new WP_Error( 'woocommerce_rest_cannot_install_product', __( 'You do not have permission to install plugin or theme', 'woocommerce' ), array( 'status' => 401 ) );
$current_user = wp_get_current_user();
if ( empty( $current_user ) || ( $current_user instanceof WP_User && ! $current_user->exists() ) ) {
return apply_filters(
WC_WCCOM_Site::AUTH_ERROR_FILTER_NAME,
new WP_Error(
WC_REST_WCCOM_Site_Installer_Errors::NOT_AUTHENTICATED_CODE,
WC_REST_WCCOM_Site_Installer_Errors::NOT_AUTHENTICATED_MESSAGE,
array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::NOT_AUTHENTICATED_HTTP_CODE )
)
);
}
if ( ! user_can( $current_user, 'install_plugins' ) || ! user_can( $current_user, 'install_themes' ) ) {
return new WP_Error(
WC_REST_WCCOM_Site_Installer_Errors::NO_PERMISSION_CODE,
WC_REST_WCCOM_Site_Installer_Errors::NO_PERMISSION_MESSAGE,
array( 'status' => WC_REST_WCCOM_Site_Installer_Errors::NO_PERMISSION_HTTP_CODE )
);
}
return true;

View File

@ -193,7 +193,7 @@ class WC_Widget_Products extends WC_Widget {
echo wp_kses_post( apply_filters( 'woocommerce_before_widget_product_list', '<ul class="product_list_widget">' ) );
$template_args = array(
'widget_id' => $args['widget_id'],
'widget_id' => isset( $args['widget_id'] ) ? $args['widget_id'] : $this->widget_id,
'show_rating' => true,
);

View File

@ -88,7 +88,7 @@ class WC_Widget_Recently_Viewed extends WC_Widget {
echo wp_kses_post( apply_filters( 'woocommerce_before_widget_product_list', '<ul class="product_list_widget">' ) );
$template_args = array(
'widget_id' => $args['widget_id'],
'widget_id' => isset( $args['widget_id'] ) ? $args['widget_id'] : $this->widget_id,
);
while ( $r->have_posts() ) {

View File

@ -79,7 +79,7 @@ class WC_Widget_Top_Rated_Products extends WC_Widget {
echo wp_kses_post( apply_filters( 'woocommerce_before_widget_product_list', '<ul class="product_list_widget">' ) );
$template_args = array(
'widget_id' => $args['widget_id'],
'widget_id' => isset( $args['widget_id'] ) ? $args['widget_id'] : $this->widget_id,
'show_rating' => true,
);

68
package-lock.json generated
View File

@ -3967,13 +3967,13 @@
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
},
"autoprefixer": {
"version": "9.7.2",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.2.tgz",
"integrity": "sha512-LCAfcdej1182uVvPOZnytbq61AhnOZ/4JelDaJGDeNwewyU1AMaNthcHsyz1NRjTmd2FkurMckLWfkHg3Z//KA==",
"version": "9.7.3",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.3.tgz",
"integrity": "sha512-8T5Y1C5Iyj6PgkPSFd0ODvK9DIleuPKUPYniNxybS47g2k2wFgLZ46lGQHlBuGKIAEV8fbCDfKCCRS1tvOgc3Q==",
"dev": true,
"requires": {
"browserslist": "^4.7.3",
"caniuse-lite": "^1.0.30001010",
"browserslist": "^4.8.0",
"caniuse-lite": "^1.0.30001012",
"chalk": "^2.4.2",
"normalize-range": "^0.1.2",
"num2fraction": "^1.2.2",
@ -3982,26 +3982,26 @@
},
"dependencies": {
"browserslist": {
"version": "4.7.3",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.3.tgz",
"integrity": "sha512-jWvmhqYpx+9EZm/FxcZSbUZyDEvDTLDi3nSAKbzEkyWvtI0mNSmUosey+5awDW1RUlrgXbQb5A6qY1xQH9U6MQ==",
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.0.tgz",
"integrity": "sha512-HYnxc/oLRWvJ3TsGegR0SRL/UDnknGq2s/a8dYYEO+kOQ9m9apKoS5oiathLKZdh/e9uE+/J3j92qPlGD/vTqA==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30001010",
"electron-to-chromium": "^1.3.306",
"node-releases": "^1.1.40"
"caniuse-lite": "^1.0.30001012",
"electron-to-chromium": "^1.3.317",
"node-releases": "^1.1.41"
}
},
"caniuse-lite": {
"version": "1.0.30001011",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001011.tgz",
"integrity": "sha512-h+Eqyn/YA6o6ZTqpS86PyRmNWOs1r54EBDcd2NTwwfsXQ8re1B38SnB+p2RKF8OUsyEIjeDU8XGec1RGO/wYCg==",
"version": "1.0.30001013",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001013.tgz",
"integrity": "sha512-hOAXaWKuq/UVFgYawxIOdPdyMQdYcwOCDOjnZcKn7wCgFUrhP7smuNZjGLuJlPSgE6aRA4cRJ+bGSrhtEt7ZAg==",
"dev": true
},
"electron-to-chromium": {
"version": "1.3.311",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.311.tgz",
"integrity": "sha512-7GH6RKCzziLzJ9ejmbiBEdzHZsc6C3eRpav14dmRfTWMpNgMqpP1ukw/FU/Le2fR+ep642naq7a23xNdmh2s+A==",
"version": "1.3.322",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz",
"integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==",
"dev": true
},
"node-releases": {
@ -6167,9 +6167,9 @@
}
},
"eslint": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.7.0.tgz",
"integrity": "sha512-dQpj+PaHKHfXHQ2Imcw5d853PTvkUGbHk/MR68KQUl98EgKDCdh4vLRH1ZxhqeQjQFJeg8fgN0UwmNhN3l8dDQ==",
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.7.2.tgz",
"integrity": "sha512-qMlSWJaCSxDFr8fBPvJM9kJwbazrhNcBU3+DszDW1OlEwKBBRWsJc7NJFelvwQpanHCR14cOLD41x8Eqvo3Nng==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
@ -6616,9 +6616,9 @@
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
},
"fast-glob": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.0.tgz",
"integrity": "sha512-TrUz3THiq2Vy3bjfQUB2wNyPdGBeGmdjbzzBLhfHN4YFurYptCKwGq/TfiRavbGywFRzY6U2CdmQ1zmsY5yYaw==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.1.tgz",
"integrity": "sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==",
"dev": true,
"requires": {
"@nodelib/fs.stat": "^2.0.2",
@ -8337,9 +8337,9 @@
}
},
"grunt-rtlcss": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/grunt-rtlcss/-/grunt-rtlcss-2.0.1.tgz",
"integrity": "sha1-6eYc5DdAY5f546Sxv2aeR+cf/MM=",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/grunt-rtlcss/-/grunt-rtlcss-2.0.2.tgz",
"integrity": "sha512-WbI2thnwlF04N+xvJu+NxqEaCyPuLyar196SYhEQFZ2EJHkOS8YYE+Zkh+X9cWhwAtKp7ZEpR/IKXcyQggOIsQ==",
"dev": true,
"requires": {
"chalk": "^1.0.0",
@ -11361,9 +11361,9 @@
"dev": true
},
"lint-staged": {
"version": "9.4.3",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.4.3.tgz",
"integrity": "sha512-PejnI+rwOAmKAIO+5UuAZU9gxdej/ovSEOAY34yMfC3OS4Ac82vCBPzAWLReR9zCPOMqeVwQRaZ3bUBpAsaL2Q==",
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.5.0.tgz",
"integrity": "sha512-nawMob9cb/G1J98nb8v3VC/E8rcX1rryUYXVZ69aT9kde6YWX+uvNOEHY5yf2gcWcTJGiD0kqXmCnS3oD75GIA==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
@ -14434,15 +14434,15 @@
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA=="
},
"rtlcss": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-2.4.0.tgz",
"integrity": "sha512-hdjFhZ5FCI0ABOfyXOMOhBtwPWtANLCG7rOiOcRf+yi5eDdxmDjqBruWouEnwVdzfh/TWF6NNncIEsigOCFZOA==",
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-2.4.1.tgz",
"integrity": "sha512-pOY30CIGvvQTW1iBfxO6Ry6/J/C4U7fcOhtF0pm5fNgwmJXOtx5gib6czFmWyp1KXN/6rbMRsTZwWlAridxBTQ==",
"dev": true,
"requires": {
"chalk": "^2.3.0",
"chalk": "^2.4.2",
"findup": "^0.1.5",
"mkdirp": "^0.5.1",
"postcss": "^6.0.14",
"postcss": "^6.0.23",
"strip-json-comments": "^2.0.0"
},
"dependencies": {

View File

@ -25,7 +25,7 @@
"@babel/preset-env": "^7.5.5",
"@babel/register": "^7.5.5",
"@wordpress/e2e-test-utils": "^2.2.0",
"autoprefixer": "9.7.2",
"autoprefixer": "9.7.3",
"babel-eslint": "10.0.3",
"chai": "4.2.0",
"chai-as-promised": "7.1.1",
@ -33,7 +33,7 @@
"eslint-plugin-jest": "22.13.6",
"config": "3.2.4",
"cross-env": "6.0.3",
"eslint": "6.7.0",
"eslint": "6.7.2",
"eslint-config-wpcalypso": "5.0.0",
"github-contributors-list": "https://github.com/woocommerce/github-contributors-list/tarball/master",
"grunt": "1.0.4",
@ -48,7 +48,7 @@
"grunt-phpcs": "0.4.0",
"grunt-postcss": "0.9.0",
"grunt-prompt": "1.3.3",
"grunt-rtlcss": "2.0.1",
"grunt-rtlcss": "2.0.2",
"grunt-sass": "3.1.0",
"grunt-shell": "3.0.1",
"grunt-stylelint": "0.12.0",
@ -57,7 +57,7 @@
"istanbul": "1.0.0-alpha.2",
"jest": "24.8.0",
"jest-puppeteer": "4.3.0",
"lint-staged": "9.4.3",
"lint-staged": "9.5.0",
"mocha": "6.2.2",
"node-sass": "4.13.0",
"prettier": "github:automattic/calypso-prettier#c56b4251",

View File

@ -2,7 +2,7 @@
Contributors: automattic, mikejolley, jameskoster, claudiosanches, kloon, rodrigosprimo, peterfabian1000, vedjain
Tags: ecommerce, e-commerce, store, sales, sell, shop, cart, checkout, downloadable, downloads, payments, paypal, storefront, stripe, woo commerce, woo
Requires at least: 4.9
Tested up to: 5.2
Tested up to: 5.3
Requires PHP: 5.6
Stable tag: 3.8.0
License: GPLv3

View File

@ -48,7 +48,6 @@ if ( ! defined( 'ABSPATH' ) ) {
* The woocommerce_review_meta hook.
*
* @hooked woocommerce_review_display_meta - 10
* @hooked WC_Structured_Data::generate_review_data() - 20
*/
do_action( 'woocommerce_review_meta', $comment );

View File

@ -1,5 +1,4 @@
#!/usr/bin/env bash
if [[ ${RUN_E2E} == 1 ]]; then
npm install
npm run test:e2e
fi
echo "Waiting for 5 minutes for the Docker container to start...";
sleep 300;
npm run test:e2e;

View File

@ -1,6 +1,8 @@
/** @format */
module.exports = {
// Required for the logged out and logged in tests so they don't share app state/token.
browserContext: 'incognito',
launch: {
// Required for the logged out and logged in tests so they don't share app state/token.
browserContext: 'incognito',
}
};

View File

@ -0,0 +1,81 @@
/**
* @format
*/
/**
* Internal dependencies
*/
import { createSimpleProduct } from '../../utils/components';
import { CustomerFlow, StoreOwnerFlow } from '../../utils/flows';
import { uiUnblocked } from '../../utils';
describe( 'Cart page', () => {
beforeAll( async () => {
await StoreOwnerFlow.login();
await createSimpleProduct();
await StoreOwnerFlow.logout();
} );
it( 'should displays no item in the cart', async () => {
await CustomerFlow.goToCart();
await expect( page ).toMatchElement( '.cart-empty', { text: 'Your cart is currently empty.' } );
} );
it( 'should add the product to the cart when "Add to cart" is clicked', async () => {
await CustomerFlow.goToShop();
await CustomerFlow.addToCartFromShopPage( 'Simple product' );
await CustomerFlow.goToCart();
await CustomerFlow.productIsInCart( 'Simple product' );
} );
it( 'should increase item qty when "Add to cart" of the same product is clicked', async () => {
await CustomerFlow.goToShop();
await CustomerFlow.addToCartFromShopPage( 'Simple product' );
await CustomerFlow.goToCart();
await CustomerFlow.productIsInCart( 'Simple product', 2 );
} );
it( 'should update qty when updated via qty input', async () => {
await CustomerFlow.goToCart();
await CustomerFlow.setCartQuantity( 'Simple product', 4 );
await expect( page ).toClick( 'button', { text: 'Update cart' } );
await uiUnblocked();
await CustomerFlow.productIsInCart( 'Simple product', 4 );
} );
it( 'should remove the item from the cart when remove is clicked', async () => {
await CustomerFlow.goToCart();
await CustomerFlow.removeFromCart( 'Simple product' );
await uiUnblocked();
await expect( page ).toMatchElement( '.cart-empty', { text: 'Your cart is currently empty.' } );
} );
it( 'should update subtotal in cart totals when adding product to the cart', async () => {
await CustomerFlow.goToShop();
await CustomerFlow.addToCartFromShopPage( 'Simple product' );
await CustomerFlow.goToCart();
await CustomerFlow.productIsInCart( 'Simple product', 1 );
await expect( page ).toMatchElement( '.cart-subtotal .amount', { text: '$9.99' } );
await CustomerFlow.setCartQuantity( 'Simple product', 2 );
await expect( page ).toClick( 'button', { text: 'Update cart' } );
await uiUnblocked();
await expect( page ).toMatchElement( '.cart-subtotal .amount', { text: '$19.98' } );
} );
it( 'should go to the checkout page when "Proceed to Checkout" is clicked', async () => {
await CustomerFlow.goToCart();
await Promise.all( [
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
expect( page ).toClick( '.checkout-button', { text: 'Proceed to checkout' } ),
] );
await expect( page ).toMatchElement( '#order_review' );
} );
} );

View File

@ -0,0 +1,46 @@
/**
* @format
*/
/**
* Internal dependencies
*/
import { CustomerFlow, StoreOwnerFlow } from '../../utils/flows';
describe( 'My account page', () => {
it( 'allows customer to login', async () => {
await StoreOwnerFlow.logout();
await CustomerFlow.login();
await expect( page ).toMatch( 'Hello' );
await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Dashboard' } );
await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Orders' } );
await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Downloads' } );
await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Addresses' } );
await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Account details' } );
await expect( page ).toMatchElement( '.woocommerce-MyAccount-navigation-link', { text: 'Logout' } );
} );
it( 'allows customer to see orders', async () => {
await CustomerFlow.goToOrders();
await expect( page.url() ).toMatch( 'my-account/orders' );
await expect( page ).toMatchElement( 'h1', { text: 'Orders' } );
} );
it( 'allows customer to see downloads', async () => {
await CustomerFlow.goToDownloads();
expect( page.url() ).toMatch( 'my-account/downloads' );
await expect( page ).toMatchElement( 'h1', { text: 'Downloads' } );
} );
it( 'allows customer to see addresses', async () => {
await CustomerFlow.goToAddresses();
expect( page.url() ).toMatch( 'my-account/edit-address' );
await expect( page ).toMatchElement( 'h1', { text: 'Addresses' } );
} );
it( 'allows customer to see account details', async () => {
await CustomerFlow.goToAccountDetails();
expect( page.url() ).toMatch( 'my-account/edit-account' );
await expect( page ).toMatchElement( 'h1', { text: 'Account details' } );
} );
} );

View File

@ -2,6 +2,11 @@
* @format
*/
/**
* External dependencies
*/
import { pressKeyWithModifier } from '@wordpress/e2e-test-utils';
/**
* Internal dependencies
*/
@ -21,11 +26,16 @@ const WP_ADMIN_NEW_PRODUCT = baseUrl + 'wp-admin/post-new.php?post_type=product'
const WP_ADMIN_WC_SETTINGS = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab=';
const WP_ADMIN_PERMALINK_SETTINGS = baseUrl + 'wp-admin/options-permalink.php';
const SHOP_PAGE = baseUrl + 'shop/';
const SHOP_PAGE = baseUrl + 'shop';
const SHOP_PRODUCT_PAGE = baseUrl + '?p=';
const SHOP_CART_PAGE = baseUrl + 'cart/';
const SHOP_CART_PAGE = baseUrl + 'cart';
const SHOP_CHECKOUT_PAGE = baseUrl + 'checkout/';
const SHOP_MY_ACCOUNT_PAGE = baseUrl + 'my-account/';
const MY_ACCOUNT_ORDERS = baseUrl + 'my-account/orders';
const MY_ACCOUNT_DOWNLOADS = baseUrl + 'my-account/downloads';
const MY_ACCOUNT_ADDRESSES = baseUrl + 'my-account/edit-address';
const MY_ACCOUNT_ACCOUNT_DETAILS = baseUrl + 'my-account/edit-account';
const getProductColumnExpression = ( productTitle ) => (
'td[@class="product-name" and ' +
@ -85,12 +95,28 @@ const CustomerFlow = {
} );
},
removeFromCart: async ( productTitle ) => {
const cartItemXPath = getCartItemExpression( productTitle );
const removeItemXPath = cartItemXPath + '//' + getRemoveExpression();
goToOrders: async () => {
await page.goto( MY_ACCOUNT_ORDERS, {
waitUntil: 'networkidle0',
} );
},
const [ removeButton ] = await page.$x( removeItemXPath );
await removeButton.click();
goToDownloads: async () => {
await page.goto( MY_ACCOUNT_DOWNLOADS, {
waitUntil: 'networkidle0',
} );
},
goToAddresses: async () => {
await page.goto( MY_ACCOUNT_ADDRESSES, {
waitUntil: 'networkidle0',
} );
},
goToAccountDetails: async () => {
await page.goto( MY_ACCOUNT_ACCOUNT_DETAILS, {
waitUntil: 'networkidle0',
} );
},
goToProduct: async ( postID ) => {
@ -126,6 +152,22 @@ const CustomerFlow = {
} );
},
login: async () => {
await page.goto(SHOP_MY_ACCOUNT_PAGE, {
waitUntil: 'networkidle0',
} );
await expect(page.title()).resolves.toMatch('My account');
await page.type('#username', config.get('users.customer.username'));
await page.type('#password', config.get('users.customer.password'));
await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle0' }),
page.click('button[name="login"]'),
] );
},
productIsInCart: async ( productTitle, quantity = null ) => {
const cartItemArgs = quantity ? { qty: quantity } : {};
const cartItemXPath = getCartItemExpression( productTitle, cartItemArgs );
@ -181,8 +223,26 @@ const CustomerFlow = {
await expect( page ).toFill( '#shipping_postcode', postcode );
},
removeFromCart: async ( productTitle ) => {
const cartItemXPath = getCartItemExpression(productTitle);
const removeItemXPath = cartItemXPath + '//' + getRemoveExpression();
const [removeButton] = await page.$x(removeItemXPath);
await removeButton.click();
},
setCartQuantity: async ( productTitle, quantityValue ) => {
const cartItemXPath = getCartItemExpression( productTitle );
const quantityInputXPath = cartItemXPath + '//' + getQtyInputExpression();
const [ quantityInput ] = await page.$x( quantityInputXPath );
await quantityInput.focus();
await pressKeyWithModifier( 'primary', 'a' );
await quantityInput.type( quantityValue.toString() );
},
};
const StoreOwnerFlow = {
login: async () => {
await page.goto( WP_ADMIN_LOGIN, {

View File

@ -1,16 +1,22 @@
<?php
/**
* Dummy WC data stores used to test data store functionality.
*
* @package WooCommerce\Tests\Framework
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// phpcs:disable Squiz.Commenting
/**
* WC Dummy Data Store: CPT.
*
* Used to test swapping out data stores.
*
* @version 3.0.0
* @category Class
* @author WooThemes
*/
class WC_Dummy_Data_Store_CPT implements WC_Object_Data_Store_Interface {
public function create( &$data ) { }
@ -21,6 +27,15 @@ class WC_Dummy_Data_Store_CPT implements WC_Object_Data_Store_Interface {
public function delete_meta( &$data, $meta ) { }
public function add_meta( &$data, $meta ) { }
public function update_meta( &$data, $meta ) { }
/**
* Method used to test WC_Data_Store::__call().
*
* @return array
*/
public function custom_method( $first_param, $second_param, $third_param ) {
return array( $first_param, $second_param, $third_param );
}
}
/**
@ -29,8 +44,6 @@ class WC_Dummy_Data_Store_CPT implements WC_Object_Data_Store_Interface {
* Used to test swapping out data stores.
*
* @version 3.0.0
* @category Class
* @author WooThemes
*/
class WC_Dummy_Data_Store_Custom_Table implements WC_Object_Data_Store_Interface {
public function create( &$data ) { }
@ -42,3 +55,5 @@ class WC_Dummy_Data_Store_Custom_Table implements WC_Object_Data_Store_Interface
public function add_meta( &$data, $meta ) { }
public function update_meta( &$data, $meta ) { }
}
// phpcs:enable

View File

@ -224,7 +224,7 @@ class WC_Helper_Product {
// Make sure caches are clean.
delete_transient( 'wc_attribute_taxonomies' );
WC_Cache_Helper::incr_cache_prefix( 'woocommerce-attributes' );
WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
// These are exported as labels, so convert the label to a name if possible first.
$attribute_labels = wp_list_pluck( wc_get_attribute_taxonomies(), 'attribute_label', 'attribute_name' );

View File

@ -51,6 +51,6 @@ class WC_Helper_Shipping_Zones {
$wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_methods;" );
$wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_locations;" );
$wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_shipping_zones;" );
WC_Cache_Helper::incr_cache_prefix( 'shipping_zones' );
WC_Cache_Helper::invalidate_cache_group( 'shipping_zones' );
}
}

View File

@ -0,0 +1,110 @@
<?php
/**
* Unit tests for the admin product duplication class.
*
* @package WooCommerce\Tests\Admin
*/
/**
* WC_Tests_Admin_Duplicate_Product tests.
*
* @package WooCommerce\Tests\Admin
* @since 3.9.0
*/
class WC_Tests_Admin_Duplicate_Product extends WC_Unit_Test_Case {
/**
* Test duplication of a simple product.
*/
public function test_simple_product_duplication() {
$product = WC_Helper_Product::create_simple_product();
$duplicate = ( new WC_Admin_Duplicate_Product() )->product_duplicate( $product );
$this->assertNotEquals( $product->get_id(), $duplicate->get_id() );
$this->assertEquals( $product->get_name() . ' (Copy)', $duplicate->get_name() );
$this->assertEquals( 'draft', $duplicate->get_status() );
$this->assertDuplicateWasReset( $duplicate );
}
/**
* Test duplication of a variable product.
*/
public function test_variable_product_duplication() {
$product = WC_Helper_Product::create_variation_product();
$duplicate = ( new WC_Admin_Duplicate_Product() )->product_duplicate( $product );
$this->assertNotEquals( $product->get_id(), $duplicate->get_id() );
$this->assertEquals( $product->get_name() . ' (Copy)', $duplicate->get_name() );
$this->assertEquals( 'draft', $duplicate->get_status() );
$this->assertDuplicateWasReset( $duplicate );
$product_children = $product->get_children();
$duplicate_children = $duplicate->get_children();
$child_count = count( $product_children );
$this->assertEquals( $child_count, count( $duplicate_children ) );
for ( $i = 0; $i < $child_count; $i++ ) {
$product_child = wc_get_product( $product_children[ $i ] );
$duplicate_child = wc_get_product( $duplicate_children[ $i ] );
$this->assertNotEquals( $product_child->get_id(), $duplicate_child->get_id() );
$this->assertEquals( $product_child->get_name() . ' (Copy)', $duplicate_child->get_name() );
$this->assertEquals( 'publish', $duplicate_child->get_status() );
$this->assertDuplicateWasReset( $duplicate_child );
}
}
/**
* Tests that the unique slugs generated by variation duplication are correct.
*/
public function test_variable_product_duplication_unique_slug_generation() {
$product = WC_Helper_Product::create_variation_product();
// We just want to make sure each successive duplication has the correct slugs.
$slug_matches = array(
array(
'dummy-variable-product-small-2',
'dummy-variable-product-large-2',
'dummy-variable-product-3',
'dummy-variable-product-4',
),
array(
'dummy-variable-product-small-3',
'dummy-variable-product-large-3',
'dummy-variable-product-5',
'dummy-variable-product-6',
),
array(
'dummy-variable-product-small-4',
'dummy-variable-product-large-4',
'dummy-variable-product-7',
'dummy-variable-product-8',
),
);
foreach ( $slug_matches as $slug_match ) {
$duplicate = ( new WC_Admin_Duplicate_Product() )->product_duplicate( $product );
$duplicate_children = $duplicate->get_children();
$this->assertEquals( 4, count( $duplicate_children ) );
foreach ( $slug_match as $key => $slug ) {
$child = wc_get_product( $duplicate_children[ $key ] );
$this->assertEquals( $slug, $child->get_slug() );
}
}
}
/**
* Asserts that the product was correctly reset after duplication.
*
* @param WC_Product $duplicate The duplicate product to evaluate.
*/
private function assertDuplicateWasReset( $duplicate ) {
$this->assertEquals( 0, $duplicate->get_total_sales() );
$this->assertEquals( array(), $duplicate->get_rating_counts() );
$this->assertEquals( 0, $duplicate->get_average_rating() );
$this->assertEquals( 0, $duplicate->get_rating_count() );
}
}

View File

@ -1,7 +1,13 @@
<?php
/**
* Data Store Tests
* Data Store tests
*
* @package WooCommerce\Tests\Product
*/
/**
* Class for Data Store tests
*
* @since 3.0.0
*/
class WC_Tests_Data_Store extends WC_Unit_Test_Case {
@ -12,9 +18,9 @@ class WC_Tests_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_invalid_store_throws_exception() {
public function test_invalid_store_throws_exception() {
try {
$product_store = new WC_Data_Store( 'bogus' );
new WC_Data_Store( 'bogus' );
} catch ( Exception $e ) {
$this->assertEquals( $e->getMessage(), 'Invalid data store.' );
return;
@ -27,9 +33,9 @@ class WC_Tests_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_invalid_store_load_throws_exception() {
public function test_invalid_store_load_throws_exception() {
try {
$product_store = WC_Data_Store::load( 'does-not-exist' );
WC_Data_Store::load( 'does-not-exist' );
} catch ( Exception $e ) {
$this->assertEquals( $e->getMessage(), 'Invalid data store.' );
return;
@ -42,7 +48,7 @@ class WC_Tests_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_store_swap() {
public function test_store_swap() {
$this->load_dummy_store();
$store = new WC_Data_Store( 'dummy' );
@ -61,12 +67,25 @@ class WC_Tests_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function test_store_sub_type() {
public function test_store_sub_type() {
$this->load_dummy_store();
$store = WC_Data_Store::load( 'dummy-sub' );
$this->assertEquals( 'WC_Dummy_Data_Store_CPT', $store->get_current_class_name() );
}
/**
* Test WC_Data_Store::__call().
*/
public function test_data_store_method_overloading() {
$this->load_dummy_store();
$store = WC_Data_Store::load( 'dummy-sub' );
$this->assertEquals(
array( 'first param', 'second param', 'third param' ),
$store->custom_method( 'first param', 'second param', 'third param', 'asdfsdf' )
);
}
/* Helper Functions. */
/**
@ -74,7 +93,7 @@ class WC_Tests_Data_Store extends WC_Unit_Test_Case {
*
* @since 3.0.0
*/
function load_dummy_store() {
private function load_dummy_store() {
include_once dirname( dirname( dirname( __FILE__ ) ) ) . '/framework/class-wc-dummy-data-store.php';
add_filter( 'woocommerce_data_stores', array( $this, 'add_dummy_data_store' ) );
}
@ -82,9 +101,11 @@ class WC_Tests_Data_Store extends WC_Unit_Test_Case {
/**
* Adds a default class for the 'dummy' data store.
*
* @param array $stores Loaded data stores.
* @return array Modified list of data stores.
* @since 3.0.0
*/
function add_dummy_data_store( $stores ) {
public function add_dummy_data_store( $stores ) {
$stores['dummy'] = 'WC_Dummy_Data_Store_CPT';
return $stores;
}
@ -92,18 +113,11 @@ class WC_Tests_Data_Store extends WC_Unit_Test_Case {
/**
* Helper function/filter to swap out the default dummy store for a different one.
*
* @param string $store Data store class name.
* @return string New data store class name.
* @since 3.0.0
*/
function set_dummy_store( $store ) {
public function set_dummy_store( $store ) {
return 'WC_Dummy_Data_Store_Custom_Table';
}
/**
* Helper function/filter to swap out the 'dummy' store for the default one.
*
* @since 3.0.0
*/
function set_default_product_store( $store ) {
return 'WC_Dummy_Data_Store_CPT';
}
}