plugin updates
This commit is contained in:
@@ -264,7 +264,7 @@ class WC_Admin_Marketplace_Promotions {
|
||||
&& $promotion['menu_item_id'] === $menu_item['id']
|
||||
) {
|
||||
$bubble_text = $promotion['content'][ self::$locale ] ?? ( $promotion['content']['en_US'] ?? __( 'Sale', 'woocommerce' ) );
|
||||
$menu_items[ $index ]['title'] = $menu_item['title'] . self::append_bubble( $bubble_text );
|
||||
$menu_items[ $index ]['title'] = self::append_bubble( $menu_item['title'], $bubble_text );
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -274,26 +274,21 @@ class WC_Admin_Marketplace_Promotions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the markup for a menu item bubble with a given text and optional additional attributes.
|
||||
* Return the markup for a menu item bubble with a given text.
|
||||
*
|
||||
* @param string $bubble_text Text of bubble.
|
||||
* @param array $attributes Optional. Additional attributes for the bubble, such as class or style.
|
||||
* @param string $menu_item_text Text of menu item we want to change.
|
||||
* @param string $bubble_text Text of bubble.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function append_bubble( $bubble_text, $attributes = array() ) {
|
||||
$default_attributes = array(
|
||||
'class' => 'awaiting-mod update-plugins remaining-tasks-badge woocommerce-task-list-remaining-tasks-badge',
|
||||
'style' => '',
|
||||
);
|
||||
private static function append_bubble( string $menu_item_text, string $bubble_text ): string {
|
||||
// Strip out update count bubble added by Marketplace::get_marketplace_update_count_html.
|
||||
$menu_item_text = preg_replace( '|<span class="update-plugins count-[\d]+">[A-z0-9 <>="-]+</span>|', '', $menu_item_text );
|
||||
|
||||
$attributes = wp_parse_args( $attributes, $default_attributes );
|
||||
$class_attr = ! empty( $attributes['class'] ) ? sprintf( 'class="%s"', esc_attr( $attributes['class'] ) ) : '';
|
||||
$style_attr = ! empty( $attributes['style'] ) ? sprintf( 'style="%s"', esc_attr( $attributes['style'] ) ) : '';
|
||||
|
||||
$bubble_html = sprintf( ' <span %s %s>%s</span>', $class_attr, $style_attr, esc_html( $bubble_text ) );
|
||||
|
||||
return $bubble_html;
|
||||
return $menu_item_text
|
||||
. '<span class="awaiting-mod update-plugins remaining-tasks-badge woocommerce-task-list-remaining-tasks-badge">'
|
||||
. esc_html( $bubble_text )
|
||||
. '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,7 @@ use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
|
||||
use Automattic\WooCommerce\Internal\Utilities\Users;
|
||||
use Automattic\WooCommerce\Internal\Utilities\WebhookUtil;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
@@ -217,7 +218,7 @@ class WC_Admin_Notices {
|
||||
* or if the Legacy REST API extension is installed, and remove the notice about Legacy webhooks
|
||||
* if no such webhooks exist anymore or if the Legacy REST API extension is installed.
|
||||
*
|
||||
* TODO: Change this method in WooCommerce 9.0 so that the notice gets removed if the Legacy REST API extension is installed and active.
|
||||
* TODO: Change this method in WooCommerce 9.0 so that the notice get removed if the Legacy REST API extension is installed and active.
|
||||
*/
|
||||
private static function maybe_remove_legacy_api_removal_notice() {
|
||||
$plugin_is_active = is_plugin_active( 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php' );
|
||||
@@ -229,6 +230,11 @@ class WC_Admin_Notices {
|
||||
if ( self::has_notice( 'legacy_webhooks_unsupported_in_woo_90' ) && ( $plugin_is_active || 0 === wc_get_container()->get( WebhookUtil::class )->get_legacy_webhooks_count() ) ) {
|
||||
self::remove_notice( 'legacy_webhooks_unsupported_in_woo_90' );
|
||||
}
|
||||
|
||||
if ( self::has_notice( 'legacy_rest_api_is_incompatible_with_hpos' ) &&
|
||||
! ( 'yes' === get_option( 'woocommerce_api_enabled' ) && 'yes' === get_option( CustomOrdersTableController::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION ) ) ) {
|
||||
self::remove_notice( 'legacy_rest_api_is_incompatible_with_hpos' );
|
||||
}
|
||||
}
|
||||
|
||||
// phpcs:enable Generic.Commenting.Todo.TaskFound
|
||||
|
||||
@@ -57,6 +57,9 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
$settings[] = include __DIR__ . '/settings/class-wc-settings-accounts.php';
|
||||
$settings[] = include __DIR__ . '/settings/class-wc-settings-emails.php';
|
||||
$settings[] = include __DIR__ . '/settings/class-wc-settings-integrations.php';
|
||||
if ( \Automattic\WooCommerce\Admin\Features\Features::is_enabled( 'launch-your-store' ) ) {
|
||||
$settings[] = include __DIR__ . '/settings/class-wc-settings-site-visibility.php';
|
||||
}
|
||||
$settings[] = include __DIR__ . '/settings/class-wc-settings-advanced.php';
|
||||
|
||||
self::$settings = apply_filters( 'woocommerce_get_settings_pages', $settings );
|
||||
|
||||
@@ -50,6 +50,8 @@ class WC_Helper_Admin {
|
||||
$installed_products
|
||||
);
|
||||
|
||||
$woo_connect_notice_type = WC_Helper_Updater::get_woo_connect_notice_type();
|
||||
|
||||
$settings['wccomHelper'] = array(
|
||||
'isConnected' => WC_Helper::is_site_connected(),
|
||||
'connectURL' => self::get_connection_url(),
|
||||
@@ -63,6 +65,7 @@ class WC_Helper_Admin {
|
||||
'wooUpdateManagerInstallUrl' => WC_Woo_Update_Manager_Plugin::generate_install_url(),
|
||||
'wooUpdateManagerPluginSlug' => WC_Woo_Update_Manager_Plugin::WOO_UPDATE_MANAGER_SLUG,
|
||||
'wooUpdateCount' => WC_Helper_Updater::get_updates_count_based_on_site_status(),
|
||||
'woocomConnectNoticeType' => $woo_connect_notice_type,
|
||||
);
|
||||
|
||||
return $settings;
|
||||
|
||||
@@ -33,7 +33,7 @@ class WC_Helper_Updater {
|
||||
* Add the hook for modifying default WPCore update notices on the plugins management page.
|
||||
*/
|
||||
public static function add_hook_for_modifying_update_notices() {
|
||||
if ( ! WC_Woo_Update_Manager_Plugin::is_plugin_active() ) {
|
||||
if ( ! WC_Woo_Update_Manager_Plugin::is_plugin_active() || ! WC_Helper::is_site_connected() ) {
|
||||
add_action( 'load-plugins.php', array( __CLASS__, 'setup_update_plugins_messages' ), 11 );
|
||||
}
|
||||
}
|
||||
@@ -155,12 +155,47 @@ class WC_Helper_Updater {
|
||||
* @return void.
|
||||
*/
|
||||
public static function setup_update_plugins_messages() {
|
||||
$is_site_connected = WC_Helper::is_site_connected();
|
||||
foreach ( WC_Helper::get_local_woo_plugins() as $plugin ) {
|
||||
$filename = $plugin['_filename'];
|
||||
add_action( 'in_plugin_update_message-' . $filename, array( __CLASS__, 'add_install_marketplace_plugin_message' ), 10, 2 );
|
||||
if ( $is_site_connected ) {
|
||||
add_action( 'in_plugin_update_message-' . $filename, array( __CLASS__, 'add_install_marketplace_plugin_message' ), 10, 2 );
|
||||
} else {
|
||||
add_action( 'in_plugin_update_message-' . $filename, array( __CLASS__, 'add_connect_woocom_plugin_message' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs on in_plugin_update_message-{file-name}, show a message to connect to woocommerce.com for unconnected stores
|
||||
*
|
||||
* @return void.
|
||||
*/
|
||||
public static function add_connect_woocom_plugin_message() {
|
||||
$connect_page_url = add_query_arg(
|
||||
array(
|
||||
'page' => 'wc-admin',
|
||||
'tab' => 'my-subscriptions',
|
||||
'path' => rawurlencode( '/extensions' ),
|
||||
),
|
||||
admin_url( 'admin.php' )
|
||||
);
|
||||
|
||||
printf(
|
||||
wp_kses(
|
||||
/* translators: 1: Woo Update Manager plugin install URL */
|
||||
__( ' <a href="%1$s" class="woocommerce-connect-your-store">Connect your store</a> to woocommerce.com to update.', 'woocommerce' ),
|
||||
array(
|
||||
'a' => array(
|
||||
'href' => array(),
|
||||
'class' => array(),
|
||||
),
|
||||
)
|
||||
),
|
||||
esc_url( $connect_page_url ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs on in_plugin_update_message-{file-name}, show a message to install the Woo Marketplace plugin, on plugin update notification,
|
||||
* if the Woo Marketplace plugin isn't already installed.
|
||||
@@ -404,6 +439,9 @@ class WC_Helper_Updater {
|
||||
* @return array Update data for each requested product.
|
||||
*/
|
||||
private static function _update_check( $payload ) {
|
||||
if ( empty( $payload ) ) {
|
||||
return array();
|
||||
}
|
||||
ksort( $payload );
|
||||
$hash = md5( wp_json_encode( $payload ) );
|
||||
|
||||
@@ -422,13 +460,22 @@ class WC_Helper_Updater {
|
||||
'errors' => array(),
|
||||
);
|
||||
|
||||
$request = WC_Helper_API::post(
|
||||
'update-check',
|
||||
array(
|
||||
'body' => wp_json_encode( array( 'products' => $payload ) ),
|
||||
'authenticated' => true,
|
||||
)
|
||||
);
|
||||
if ( WC_Helper::is_site_connected() ) {
|
||||
$request = WC_Helper_API::post(
|
||||
'update-check',
|
||||
array(
|
||||
'body' => wp_json_encode( array( 'products' => $payload ) ),
|
||||
'authenticated' => true,
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$request = WC_Helper_API::post(
|
||||
'update-check-public',
|
||||
array(
|
||||
'body' => wp_json_encode( array( 'products' => $payload ) ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( wp_remote_retrieve_response_code( $request ) !== 200 ) {
|
||||
$data['errors'][] = 'http-error';
|
||||
@@ -503,7 +550,7 @@ class WC_Helper_Updater {
|
||||
*/
|
||||
public static function get_updates_count_based_on_site_status() {
|
||||
if ( ! WC_Helper::is_site_connected() ) {
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
$count = self::get_updates_count() ?? 0;
|
||||
@@ -514,6 +561,45 @@ class WC_Helper_Updater {
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of woo connect notice to be shown in the WC Settings and Marketplace pages.
|
||||
* - If a store is connected to woocommerce.com or has no installed woo plugins, return 'none'.
|
||||
* - If a store has installed woo plugins but no updates, return 'short'.
|
||||
* - If a store has an installed woo plugin with update, return 'long'.
|
||||
*
|
||||
* @return string The notice type, 'none', 'short', or 'long'.
|
||||
*/
|
||||
public static function get_woo_connect_notice_type() {
|
||||
if ( WC_Helper::is_site_connected() ) {
|
||||
return 'none';
|
||||
}
|
||||
|
||||
$woo_plugins = WC_Helper::get_local_woo_plugins();
|
||||
|
||||
if ( empty( $woo_plugins ) ) {
|
||||
return 'none';
|
||||
}
|
||||
|
||||
$update_data = self::get_update_data();
|
||||
|
||||
if ( empty( $update_data ) ) {
|
||||
return 'short';
|
||||
}
|
||||
|
||||
// Scan local plugins.
|
||||
foreach ( $woo_plugins as $plugin ) {
|
||||
if ( empty( $update_data[ $plugin['_product_id'] ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( version_compare( $plugin['Version'], $update_data[ $plugin['_product_id'] ]['version'], '<' ) ) {
|
||||
return 'long';
|
||||
}
|
||||
}
|
||||
|
||||
return 'short';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the updates count markup.
|
||||
*
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* @package WooCommerce\Admin
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Admin\Features\Features;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
|
||||
@@ -217,11 +217,6 @@ class WC_Settings_General extends WC_Settings_Page {
|
||||
'id' => 'general_options',
|
||||
),
|
||||
|
||||
array(
|
||||
'id' => 'wc_settings_general_site_visibility_slotfill',
|
||||
'type' => 'slotfill_placeholder',
|
||||
),
|
||||
|
||||
array(
|
||||
'title' => __( 'Currency options', 'woocommerce' ),
|
||||
'type' => 'title',
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/**
|
||||
* WooCommerce site visibility settings
|
||||
*
|
||||
* @package WooCommerce\Admin
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Settings for API.
|
||||
*/
|
||||
if ( class_exists( 'WC_Settings_Site_Visibility', false ) ) {
|
||||
return new WC_Settings_Site_Visibility();
|
||||
}
|
||||
|
||||
/**
|
||||
* WC_Settings_Advanced.
|
||||
*/
|
||||
class WC_Settings_Site_Visibility extends WC_Settings_Page {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->id = 'site-visibility';
|
||||
$this->label = __( 'Site visibility', 'woocommerce' );
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get settings for the default section.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_settings_for_default_section() {
|
||||
$settings =
|
||||
array(
|
||||
array(
|
||||
'id' => 'wc_settings_site_visibility_slotfill',
|
||||
'type' => 'slotfill_placeholder',
|
||||
),
|
||||
);
|
||||
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new WC_Settings_Site_Visibility();
|
||||
@@ -741,11 +741,6 @@ if ( 0 < $mu_plugins_count ) :
|
||||
<td><?php echo $settings['enforce_approved_download_dirs'] ? '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>' : '<mark class="no">–</mark>'; ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td data-export-label="HPOS feature screen enabled"><?php esc_html_e( 'HPOS feature screen enabled:', 'woocommerce' ); ?></td>
|
||||
<td class="help"><?php echo wc_help_tip( esc_html__( 'Is HPOS feature screen enabled?', 'woocommerce' ) ); ?></td>
|
||||
<td><?php echo $settings['HPOS_feature_screen_enabled'] ? '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>' : '<mark class="no">–</mark>'; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td data-export-label="HPOS feature enabled"><?php esc_html_e( 'HPOS enabled:', 'woocommerce' ); ?></td>
|
||||
<td class="help"><?php echo wc_help_tip( esc_html__( 'Is HPOS enabled?', 'woocommerce' ) ); ?></td>
|
||||
|
||||
@@ -1050,11 +1050,11 @@ class WC_Checkout {
|
||||
return;
|
||||
}
|
||||
|
||||
// Store Order ID in session so it can be re-used after payment failure.
|
||||
// Store Order ID in session, so it can be re-used after payment failure.
|
||||
WC()->session->set( 'order_awaiting_payment', $order_id );
|
||||
|
||||
// We save the session early because if the payment gateway hangs
|
||||
// the request will never finish, thus the session data will neved be saved,
|
||||
// the request will never finish, thus the session data will never be saved,
|
||||
// and this can lead to duplicate orders if the user submits the order again.
|
||||
WC()->session->save_data();
|
||||
|
||||
@@ -1073,6 +1073,7 @@ class WC_Checkout {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Using wp_send_json will gracefully handle any problem encoding data.
|
||||
wp_send_json( $result );
|
||||
}
|
||||
}
|
||||
@@ -1287,6 +1288,7 @@ class WC_Checkout {
|
||||
* since it could be empty see:
|
||||
* https://github.com/woocommerce/woocommerce/issues/24631
|
||||
*/
|
||||
|
||||
if ( apply_filters( 'woocommerce_cart_needs_payment', $order->needs_payment(), WC()->cart ) ) {
|
||||
$this->process_order_payment( $order_id, $posted_data['payment_method'] );
|
||||
} else {
|
||||
|
||||
@@ -922,7 +922,7 @@ class WC_Coupon extends WC_Legacy_Coupon {
|
||||
* @return bool
|
||||
*/
|
||||
public function is_valid_for_product( $product, $values = array() ) {
|
||||
if ( ! $this->is_type( wc_get_product_coupon_types() ) ) {
|
||||
if ( ! $this->is_type( wc_get_product_coupon_types() ) || ! is_a( $product, WC_Product::class ) ) {
|
||||
return apply_filters( 'woocommerce_coupon_is_valid_for_product', false, $product, $this, $values );
|
||||
}
|
||||
|
||||
|
||||
@@ -333,7 +333,20 @@ class WC_Discounts {
|
||||
|
||||
$items_to_apply[] = $item_to_apply;
|
||||
}
|
||||
return $items_to_apply;
|
||||
|
||||
/**
|
||||
* Filters the items that a coupon should be applied to.
|
||||
*
|
||||
* This filter allows you to modify the items that a coupon will be applied to before the discount calculations take place.
|
||||
*
|
||||
* @since 8.8.0
|
||||
* @param array $items_to_apply The items that the coupon will be applied to.
|
||||
* @param WC_Coupon $coupon The coupon object.
|
||||
* @param WC_Discounts $this The discounts instance.
|
||||
*
|
||||
* @return array The modified list of items that the coupon should be applied to.
|
||||
*/
|
||||
return apply_filters( 'woocommerce_coupon_get_items_to_apply', $items_to_apply, $coupon, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -220,7 +220,7 @@ class WC_Emails {
|
||||
*/
|
||||
public function init() {
|
||||
// Include email classes.
|
||||
include_once dirname( __FILE__ ) . '/emails/class-wc-email.php';
|
||||
include_once __DIR__ . '/emails/class-wc-email.php';
|
||||
|
||||
$this->emails['WC_Email_New_Order'] = include __DIR__ . '/emails/class-wc-email-new-order.php';
|
||||
$this->emails['WC_Email_Cancelled_Order'] = include __DIR__ . '/emails/class-wc-email-cancelled-order.php';
|
||||
@@ -610,8 +610,8 @@ class WC_Emails {
|
||||
|
||||
$checkout_fields = Package::container()->get( CheckoutFields::class );
|
||||
$fields = array_merge(
|
||||
$checkout_fields->get_order_additional_fields_with_values( $order, 'contact', '', 'view' ),
|
||||
$checkout_fields->get_order_additional_fields_with_values( $order, 'additional', '', 'view' ),
|
||||
$checkout_fields->get_order_additional_fields_with_values( $order, 'contact', 'other', 'view' ),
|
||||
$checkout_fields->get_order_additional_fields_with_values( $order, 'order', 'other', 'view' ),
|
||||
);
|
||||
|
||||
if ( ! $fields ) {
|
||||
|
||||
@@ -541,7 +541,9 @@ class WC_Frontend_Scripts {
|
||||
'checkout_url' => WC_AJAX::get_endpoint( 'checkout' ),
|
||||
'is_checkout' => is_checkout() && empty( $wp->query_vars['order-pay'] ) && ! isset( $wp->query_vars['order-received'] ) ? 1 : 0,
|
||||
'debug_mode' => Constants::is_true( 'WP_DEBUG' ),
|
||||
'i18n_checkout_error' => esc_attr__( 'Error processing checkout. Please try again.', 'woocommerce' ),
|
||||
/* translators: %s: Order history URL on My Account section */
|
||||
'i18n_checkout_error' => sprintf( esc_attr__( 'There was an error processing your order. Please check for any charges in your payment method and review your <a href="%s">order history</a> before placing the order again.', 'woocommerce' ), esc_url( wc_get_account_endpoint_url( 'orders' ) ) ),
|
||||
|
||||
);
|
||||
break;
|
||||
case 'wc-address-i18n':
|
||||
|
||||
@@ -248,6 +248,13 @@ class WC_Install {
|
||||
'8.7.0' => array(
|
||||
'wc_update_870_prevent_listing_of_transient_files_directory',
|
||||
),
|
||||
'8.9.0' => array(
|
||||
'wc_update_890_update_connect_to_woocommerce_note',
|
||||
'wc_update_890_update_paypal_standard_load_eligibility',
|
||||
),
|
||||
'8.9.1' => array(
|
||||
'wc_update_891_create_plugin_autoinstall_history_option',
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -1183,16 +1190,30 @@ class WC_Install {
|
||||
return;
|
||||
}
|
||||
|
||||
// Did we previously install this plugin?
|
||||
// We check both the woocommerce_history_of_autoinstalled_plugins options (introduced in 9.0)
|
||||
// and the woocommerce_autoinstalled_plugins option (info should still exist here if the plugin has been uninstalled but not manually reinstalled).
|
||||
$legacy_api_plugin = 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php';
|
||||
$autoinstalled_plugins = (array) get_site_option( 'woocommerce_history_of_autoinstalled_plugins', array() );
|
||||
$previously_installed_by_us = isset( $autoinstalled_plugins[ $legacy_api_plugin ] );
|
||||
if ( ! $previously_installed_by_us ) {
|
||||
$autoinstalled_plugins = (array) get_site_option( 'woocommerce_autoinstalled_plugins', array() );
|
||||
$previously_installed_by_us = isset( $autoinstalled_plugins[ $legacy_api_plugin ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter to skip the automatic installation of the WooCommerce Legacy REST API plugin
|
||||
* from the WordPress.org plugins directory.
|
||||
*
|
||||
* By default, this is true (skip installation) if we have a record of previously installing the legacy plugin,
|
||||
* and false (do not skip) if we have no record of previously installing the plugin.
|
||||
*
|
||||
* @since 8.8.0
|
||||
*
|
||||
* @param bool $skip_auto_install False, defaulting to "don't skip the plugin automatic installation".
|
||||
* @returns bool True to skip the plugin automatic installation, false to install the plugin if necessary.
|
||||
*/
|
||||
if ( apply_filters( 'woocommerce_skip_legacy_rest_api_plugin_auto_install', false ) ) {
|
||||
if ( apply_filters( 'woocommerce_skip_legacy_rest_api_plugin_auto_install', $previously_installed_by_us ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1201,19 +1222,17 @@ class WC_Install {
|
||||
return;
|
||||
}
|
||||
|
||||
$plugin_name = 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php';
|
||||
|
||||
wp_clean_plugins_cache();
|
||||
if ( ! function_exists( 'get_plugins' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
if ( isset( get_plugins()[ $plugin_name ] ) ) {
|
||||
if ( ! ( get_site_option( 'woocommerce_autoinstalled_plugins', array() )[ $plugin_name ] ?? null ) ) {
|
||||
if ( isset( get_plugins()[ $legacy_api_plugin ] ) ) {
|
||||
if ( ! $previously_installed_by_us ) {
|
||||
// The plugin was installed manually so let's not interfere.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( in_array( $plugin_name, wp_get_active_and_valid_plugins(), true ) ) {
|
||||
if ( in_array( $legacy_api_plugin, wp_get_active_and_valid_plugins(), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1244,7 +1263,7 @@ class WC_Install {
|
||||
$site_logs_url = get_admin_url( null, '/admin.php?page=wc-status&tab=logs' );
|
||||
|
||||
if ( $install_ok ) {
|
||||
$activation_result = activate_plugin( $plugin_name );
|
||||
$activation_result = activate_plugin( $legacy_api_plugin );
|
||||
if ( $activation_result instanceof \WP_Error ) {
|
||||
$message = sprintf(
|
||||
/* translators: 1 = URL of Legacy REST API plugin page, 2 = URL of Legacy API settings in current site, 3 = URL of webhooks settings in current site, 4 = URL of logs page in current site, 5 = URL of plugins page in current site, 6 = URL of blog post about the Legacy REST API removal */
|
||||
|
||||
@@ -36,7 +36,7 @@ class WC_Order_Factory {
|
||||
$order_cache = wc_get_container()->get( OrderCache::class );
|
||||
$order = $order_cache->get( $order_id );
|
||||
if ( ! is_null( $order ) ) {
|
||||
return $order;
|
||||
return 0 === $order->get_id() ? false : $order;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2302,9 +2302,15 @@ class WC_Order extends WC_Abstract_Order {
|
||||
$refunds = $this->get_refunds();
|
||||
if ( $refunds ) {
|
||||
foreach ( $refunds as $id => $refund ) {
|
||||
$reason = trim( $refund->get_reason() );
|
||||
|
||||
if ( strlen( $reason ) > 0 ) {
|
||||
$reason = "<br><small>$reason</small>";
|
||||
}
|
||||
|
||||
$total_rows[ 'refund_' . $id ] = array(
|
||||
'label' => $refund->get_reason() ? $refund->get_reason() : __( 'Refund', 'woocommerce' ) . ':',
|
||||
'value' => wc_price( '-' . $refund->get_amount(), array( 'currency' => $this->get_currency() ) ),
|
||||
'label' => __( 'Refund', 'woocommerce' ) . ':',
|
||||
'value' => wc_price( '-' . $refund->get_amount(), array( 'currency' => $this->get_currency() ) ) . $reason,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ class WC_Payment_Gateways {
|
||||
The payment gateway "%2$s" was just enabled on this site:
|
||||
%3$s
|
||||
|
||||
If this was intentional you can safely ignore and delete this email.
|
||||
If this was intentional you can safely ignore and delete this email.
|
||||
|
||||
If you did not enable this payment gateway, please log in to your site and consider disabling it here:
|
||||
%4$s
|
||||
@@ -400,6 +400,8 @@ All at %6$s
|
||||
* @return bool Whether PayPal Standard should be loaded or not.
|
||||
*/
|
||||
protected function should_load_paypal_standard() {
|
||||
// Tech debt: This class needs to be initialized to make sure any existing subscriptions gets processed as expected, even if the gateway is not enabled for new orders.
|
||||
// Eventually, we want to load this via a singleton pattern to avoid unnecessary instantiation.
|
||||
$paypal = new WC_Gateway_Paypal();
|
||||
return $paypal->should_load();
|
||||
}
|
||||
|
||||
@@ -960,7 +960,6 @@ class WC_Tracker {
|
||||
'enable_myaccount_registration' => get_option( 'woocommerce_enable_myaccount_registration' ),
|
||||
'registration_generate_username' => get_option( 'woocommerce_registration_generate_username' ),
|
||||
'registration_generate_password' => get_option( 'woocommerce_registration_generate_password' ),
|
||||
'hpos_enabled' => get_option( 'woocommerce_feature_custom_order_tables_enabled' ),
|
||||
'hpos_sync_enabled' => get_option( 'woocommerce_custom_orders_table_data_sync_enabled' ),
|
||||
'hpos_cot_authoritative' => get_option( 'woocommerce_custom_orders_table_enabled' ),
|
||||
'hpos_transactions_enabled' => get_option( 'woocommerce_use_db_transactions_for_custom_orders_table_data_sync' ),
|
||||
|
||||
@@ -102,7 +102,7 @@ class WC_Validation {
|
||||
break;
|
||||
case 'CZ':
|
||||
case 'SK':
|
||||
$valid = (bool) preg_match( '/^([0-9]{3})(\s?)([0-9]{2})$/', $postcode );
|
||||
$valid = (bool) preg_match( "/^($country-)?([0-9]{3})(\s?)([0-9]{2})$/", $postcode );
|
||||
break;
|
||||
case 'NL':
|
||||
$valid = (bool) preg_match( '/^([1-9][0-9]{3})(\s?)(?!SA|SD|SS)[A-Z]{2}$/i', $postcode );
|
||||
|
||||
@@ -10,6 +10,8 @@ defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Internal\AssignDefaultCategory;
|
||||
use Automattic\WooCommerce\Internal\BatchProcessing\BatchProcessingController;
|
||||
use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonCacheInvalidator;
|
||||
use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonRequestHandler;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
|
||||
use Automattic\WooCommerce\Internal\DownloadPermissionsAdjuster;
|
||||
use Automattic\WooCommerce\Internal\Features\FeaturesController;
|
||||
@@ -39,7 +41,7 @@ final class WooCommerce {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $version = '8.8.3';
|
||||
public $version = '8.9.3';
|
||||
|
||||
/**
|
||||
* WooCommerce Schema version.
|
||||
@@ -246,7 +248,9 @@ final class WooCommerce {
|
||||
add_action( 'init', array( 'WC_Emails', 'init_transactional_emails' ) );
|
||||
add_action( 'init', array( $this, 'add_image_sizes' ) );
|
||||
add_action( 'init', array( $this, 'load_rest_api' ) );
|
||||
add_action( 'init', array( 'WC_Site_Tracking', 'init' ) );
|
||||
if ( $this->is_request( 'admin' ) || ( $this->is_rest_api_request() && ! $this->is_store_api_request() ) || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
|
||||
add_action( 'init', array( 'WC_Site_Tracking', 'init' ) );
|
||||
}
|
||||
add_action( 'switch_blog', array( $this, 'wpdb_table_fix' ), 0 );
|
||||
add_action( 'activated_plugin', array( $this, 'activated_plugin' ) );
|
||||
add_action( 'deactivated_plugin', array( $this, 'deactivated_plugin' ) );
|
||||
@@ -255,11 +259,6 @@ final class WooCommerce {
|
||||
add_action( 'woocommerce_installed', array( $this, 'add_woocommerce_remote_variant' ) );
|
||||
add_action( 'woocommerce_updated', array( $this, 'add_woocommerce_remote_variant' ) );
|
||||
|
||||
if ( Features::is_enabled( 'launch-your-store' ) ) {
|
||||
add_action( 'woocommerce_newly_installed', array( $this, 'add_lys_default_values' ) );
|
||||
add_action( 'woocommerce_updated', array( $this, 'add_lys_default_values' ) );
|
||||
}
|
||||
|
||||
// These classes set up hooks on instantiation.
|
||||
$container = wc_get_container();
|
||||
$container->get( ProductDownloadDirectories::class );
|
||||
@@ -276,6 +275,8 @@ final class WooCommerce {
|
||||
$container->get( WebhookUtil::class );
|
||||
$container->get( Marketplace::class );
|
||||
$container->get( TimeUtil::class );
|
||||
$container->get( ComingSoonCacheInvalidator::class );
|
||||
$container->get( ComingSoonRequestHandler::class );
|
||||
|
||||
/**
|
||||
* These classes have a register method for attaching hooks.
|
||||
@@ -314,35 +315,6 @@ final class WooCommerce {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default option values for launch your store task.
|
||||
*/
|
||||
public function add_lys_default_values() {
|
||||
$is_new_install = current_action() === 'woocommerce_newly_installed';
|
||||
|
||||
$coming_soon = $is_new_install ? 'yes' : 'no';
|
||||
$launch_status = $is_new_install ? 'unlaunched' : 'launched';
|
||||
$store_pages_only = WCAdminHelper::is_site_fresh() ? 'no' : 'yes';
|
||||
$private_link = 'yes';
|
||||
$share_key = wp_generate_password( 32, false );
|
||||
|
||||
if ( false === get_option( 'woocommerce_coming_soon', false ) ) {
|
||||
update_option( 'woocommerce_coming_soon', $coming_soon );
|
||||
}
|
||||
if ( false === get_option( 'woocommerce_store_pages_only', false ) ) {
|
||||
update_option( 'woocommerce_store_pages_only', $store_pages_only );
|
||||
}
|
||||
if ( false === get_option( 'woocommerce_private_link', false ) ) {
|
||||
update_option( 'woocommerce_private_link', $private_link );
|
||||
}
|
||||
if ( false === get_option( 'woocommerce_share_key', false ) ) {
|
||||
update_option( 'woocommerce_share_key', $share_key );
|
||||
}
|
||||
if ( false === get_option( 'launch-status', false ) ) {
|
||||
update_option( 'launch-status', $launch_status );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures fatal errors are logged so they can be picked up in the status report.
|
||||
*
|
||||
@@ -431,7 +403,6 @@ final class WooCommerce {
|
||||
* The SSR in the name is preserved for bw compatibility, as this was initially used in System Status Report.
|
||||
*/
|
||||
$this->define( 'WC_SSR_PLUGIN_UPDATE_RELEASE_VERSION_TYPE', 'none' );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -492,6 +463,19 @@ final class WooCommerce {
|
||||
return apply_filters( 'woocommerce_is_rest_api_request', $is_rest_api_request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the request is a store REST API request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_store_api_request() {
|
||||
if ( empty( $_SERVER['REQUEST_URI'] ) ) {
|
||||
return false;
|
||||
}
|
||||
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
return false !== strpos( $_SERVER['REQUEST_URI'], trailingslashit( rest_get_url_prefix() ) . 'wc/store/' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load REST API.
|
||||
*/
|
||||
@@ -1023,7 +1007,7 @@ final class WooCommerce {
|
||||
* @param string $filename The filename of the activated plugin.
|
||||
*/
|
||||
public function activated_plugin( $filename ) {
|
||||
include_once dirname( __FILE__ ) . '/admin/helper/class-wc-helper.php';
|
||||
include_once __DIR__ . '/admin/helper/class-wc-helper.php';
|
||||
|
||||
if ( '/woocommerce.php' === substr( $filename, -16 ) ) {
|
||||
set_transient( 'woocommerce_activated_plugin', $filename );
|
||||
@@ -1039,7 +1023,7 @@ final class WooCommerce {
|
||||
* @param string $filename The filename of the deactivated plugin.
|
||||
*/
|
||||
public function deactivated_plugin( $filename ) {
|
||||
include_once dirname( __FILE__ ) . '/admin/helper/class-wc-helper.php';
|
||||
include_once __DIR__ . '/admin/helper/class-wc-helper.php';
|
||||
|
||||
WC_Helper::deactivated_plugin( $filename );
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// phpcs:disable Squiz.Classes.ClassFileName.NoMatch, Squiz.Classes.ValidClassName.NotCamelCaps -- Backward compatibility.
|
||||
/**
|
||||
* Abstract Order Data Store: Stored in CPT.
|
||||
*
|
||||
@@ -80,6 +81,13 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
}
|
||||
|
||||
$id = wp_insert_post(
|
||||
/**
|
||||
* Filters the data for a new order before it is inserted into the database.
|
||||
*
|
||||
* @param array $data Array of data for the new order.
|
||||
*
|
||||
* @since 3.3.0
|
||||
*/
|
||||
apply_filters(
|
||||
'woocommerce_new_order_data',
|
||||
array(
|
||||
@@ -115,7 +123,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
* @param int $order_id The order id to check.
|
||||
* @return bool True if an order exists with the given name.
|
||||
*/
|
||||
public function order_exists( $order_id ) : bool {
|
||||
public function order_exists( $order_id ): bool {
|
||||
if ( ! $order_id ) {
|
||||
return false;
|
||||
}
|
||||
@@ -135,7 +143,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
$order->set_defaults();
|
||||
$post_object = get_post( $order->get_id() );
|
||||
if ( ! $order->get_id() || ! $post_object || ! in_array( $post_object->post_type, wc_get_order_types(), true ) ) {
|
||||
throw new Exception( __( 'Invalid order.', 'woocommerce' ) );
|
||||
throw new Exception( esc_html__( 'Invalid order.', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
$this->set_order_props(
|
||||
@@ -291,7 +299,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
/**
|
||||
* Fires immediately after an order is deleted.
|
||||
*
|
||||
* @since
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @param int $order_id ID of the order that has been deleted.
|
||||
*/
|
||||
@@ -345,6 +353,13 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
$order_status = $order->get_status( 'edit' );
|
||||
|
||||
if ( ! $order_status ) {
|
||||
/**
|
||||
* Filters the default order status to use when creating a new order.
|
||||
*
|
||||
* @param string $order_status Default order status.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*/
|
||||
$order_status = apply_filters( 'woocommerce_default_order_status', 'pending' );
|
||||
}
|
||||
|
||||
@@ -352,7 +367,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
$valid_statuses = get_post_stati();
|
||||
|
||||
// Add a wc- prefix to the status, but exclude some core statuses which should not be prefixed.
|
||||
// @todo In the future this should only happen based on `wc_is_order_status`, but in order to
|
||||
// In the future this should only happen based on `wc_is_order_status`, but in order to
|
||||
// preserve back-compatibility this happens to all statuses except a select few. A doing_it_wrong
|
||||
// Notice will be needed here, followed by future removal.
|
||||
if ( ! in_array( $post_status, array( 'auto-draft', 'draft', 'trash' ), true ) && in_array( 'wc-' . $post_status, $valid_statuses, true ) ) {
|
||||
@@ -380,7 +395,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
protected function get_post_title() {
|
||||
// @codingStandardsIgnoreStart
|
||||
/* translators: %s: Order date */
|
||||
return sprintf( __( 'Order – %s', 'woocommerce' ), (new DateTime('now'))->format( _x( 'M d, Y @ h:i A', 'Order date parsed by DateTime::format', 'woocommerce' ) ) );
|
||||
return sprintf( __( 'Order – %s', 'woocommerce' ), ( new DateTime( 'now' ) )->format( _x( 'M d, Y @ h:i A', 'Order date parsed by DateTime::format', 'woocommerce' ) ) );
|
||||
// @codingStandardsIgnoreEnd
|
||||
}
|
||||
|
||||
@@ -466,6 +481,14 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action fired after updating order properties.
|
||||
*
|
||||
* @param WC_Abstract_Order $order Order object.
|
||||
* @param string[] $updated_props Array of updated properties.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*/
|
||||
do_action( 'woocommerce_order_object_updated_props', $order, $updated_props );
|
||||
}
|
||||
|
||||
@@ -491,6 +514,11 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
public function read_items( $order, $type ) {
|
||||
global $wpdb;
|
||||
|
||||
// When the order is not yet saved, we cannot get the items from DB. Trying to do so will risk reading items of different orders that were saved incorrectly.
|
||||
if ( 0 === $order->get_id() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Get from cache if available.
|
||||
$items = 0 < $order->get_id() ? wp_cache_get( 'order-items-' . $order->get_id(), 'orders' ) : false;
|
||||
|
||||
|
||||
@@ -94,19 +94,22 @@ class WC_Customer_Data_Store_Session extends WC_Data_Store_WP implements WC_Cust
|
||||
* @param array $allowed_keys The allowed meta data keys.
|
||||
* @param WC_Customer $customer The customer object.
|
||||
*/
|
||||
$allowed_keys = apply_filters( 'woocommerce_customer_allowed_session_meta_keys', array(), $customer );
|
||||
$session_value = wp_json_encode(
|
||||
array_filter(
|
||||
$customer->get_meta_data(),
|
||||
function( $meta_data ) use ( $allowed_keys ) {
|
||||
return in_array( $meta_data->key, $allowed_keys, true );
|
||||
}
|
||||
)
|
||||
);
|
||||
$allowed_keys = apply_filters( 'woocommerce_customer_allowed_session_meta_keys', array(), $customer );
|
||||
|
||||
$session_value = array();
|
||||
foreach ( $customer->get_meta_data() as $meta_data ) {
|
||||
if ( in_array( $meta_data->key, $allowed_keys, true ) ) {
|
||||
$session_value[] = array(
|
||||
'key' => $meta_data->key,
|
||||
'value' => $meta_data->value,
|
||||
);
|
||||
}
|
||||
}
|
||||
$data['meta_data'] = $session_value;
|
||||
} else {
|
||||
$session_value = $customer->{"get_$function_key"}( 'edit' );
|
||||
$session_value = $customer->{"get_$function_key"}( 'edit' );
|
||||
$data[ $session_key ] = (string) $session_value;
|
||||
}
|
||||
$data[ $session_key ] = (string) $session_value;
|
||||
}
|
||||
WC()->session->set( 'customer', $data );
|
||||
}
|
||||
@@ -137,9 +140,8 @@ class WC_Customer_Data_Store_Session extends WC_Data_Store_WP implements WC_Cust
|
||||
}
|
||||
if ( ! empty( $data[ $session_key ] ) && is_callable( array( $customer, "set_{$function_key}" ) ) ) {
|
||||
if ( 'meta_data' === $session_key ) {
|
||||
$meta_data_values = json_decode( wp_unslash( $data[ $session_key ] ), true );
|
||||
if ( $meta_data_values ) {
|
||||
foreach ( $meta_data_values as $meta_data_value ) {
|
||||
if ( is_array( $data[ $session_key ] ) ) {
|
||||
foreach ( $data[ $session_key ] as $meta_data_value ) {
|
||||
if ( ! isset( $meta_data_value['key'], $meta_data_value['value'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1193,10 +1193,11 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
* @todo Add to interface in 4.0.
|
||||
* @param WC_Product $product Variable product.
|
||||
* @param int $limit Limit the number of created variations.
|
||||
* @param array $default_values Key value pairs to set on created variations.
|
||||
* @param array $default_values Key value pairs to set on created variations.
|
||||
* @param array $metadata Key value pairs to set as meta data on created variations.
|
||||
* @return int Number of created variations.
|
||||
*/
|
||||
public function create_all_product_variations( $product, $limit = -1, $default_values = array() ) {
|
||||
public function create_all_product_variations( $product, $limit = -1, $default_values = array(), $metadata = array() ) {
|
||||
$count = 0;
|
||||
|
||||
if ( ! $product ) {
|
||||
@@ -1226,6 +1227,9 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
}
|
||||
$variation = wc_get_product_object( 'variation' );
|
||||
$variation->set_props( $default_values );
|
||||
foreach ( $metadata as $meta ) {
|
||||
$variation->add_meta_data( $meta['key'], $meta['value'] );
|
||||
}
|
||||
$variation->set_parent_id( $product->get_id() );
|
||||
$variation->set_attributes( $possible_attribute );
|
||||
$variation_id = $variation->save();
|
||||
|
||||
@@ -527,27 +527,32 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
|
||||
$should_load = $this->get_option( $option_key );
|
||||
|
||||
if ( '' === $should_load ) {
|
||||
|
||||
// New installs without PayPal Standard enabled don't load it.
|
||||
if ( 'no' === $this->enabled && WC_Install::is_new_install() ) {
|
||||
$should_load = false;
|
||||
} else {
|
||||
$should_load = true;
|
||||
}
|
||||
// Set default `_should_load` to 'yes' on existing stores with PayPal Standard enabled or with existing PayPal Standard orders.
|
||||
$should_load = 'yes' === $this->enabled || $this->has_paypal_orders();
|
||||
|
||||
$this->update_option( $option_key, wc_bool_to_string( $should_load ) );
|
||||
} else {
|
||||
$should_load = wc_string_to_bool( $should_load );
|
||||
// Enabled always takes precedence over the option.
|
||||
$should_load = wc_string_to_bool( $this->enabled ) || wc_string_to_bool( $should_load );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow third-parties to filter whether PayPal Standard should be loaded or not.
|
||||
*
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @param bool $should_load Whether PayPal Standard should be loaded.
|
||||
* @param WC_Gateway_Paypal $this The WC_Gateway_Paypal instance.
|
||||
*/
|
||||
return apply_filters( 'woocommerce_should_load_paypal_standard', $should_load, $this );
|
||||
return $should_load;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the store has at least one PayPal Standand order.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_paypal_orders() {
|
||||
$paypal_orders = wc_get_orders(
|
||||
array(
|
||||
'limit' => 1,
|
||||
'return' => 'ids',
|
||||
'payment_method' => 'paypal',
|
||||
)
|
||||
);
|
||||
|
||||
return is_countable( $paypal_orders ) ? 1 === count( $paypal_orders ) : false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,7 +747,7 @@ abstract class WC_Product_Importer implements WC_Importer_Interface {
|
||||
// Unlimited, set to 32GB.
|
||||
$memory_limit = '32000M';
|
||||
}
|
||||
return intval( $memory_limit ) * 1024 * 1024;
|
||||
return wp_convert_hr_to_bytes( $memory_limit );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,7 @@ if ( ! function_exists( 'wc_admin_get_feature_config' ) ) {
|
||||
'product-grouped' => true,
|
||||
'product-linked' => true,
|
||||
'product-pre-publish-modal' => true,
|
||||
'product-custom-fields' => false,
|
||||
'product-custom-fields' => true,
|
||||
'remote-inbox-notifications' => true,
|
||||
'remote-free-extensions' => true,
|
||||
'payment-gateway-suggestions' => true,
|
||||
|
||||
@@ -569,12 +569,6 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
|
||||
'context' => array( 'view' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'HPOS_feature_screen_enabled' => array(
|
||||
'description' => __( 'Is HPOS feature screen enabled?', 'woocommerce' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'view' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'HPOS_enabled' => array(
|
||||
'description' => __( 'Is HPOS enabled?', 'woocommerce' ),
|
||||
'type' => 'boolean',
|
||||
@@ -1349,7 +1343,6 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
|
||||
'woocommerce_com_connected' => ConnectionHelper::is_connected() ? 'yes' : 'no',
|
||||
'enforce_approved_download_dirs' => wc_get_container()->get( Download_Directories::class )->get_mode() === Download_Directories::MODE_ENABLED,
|
||||
'order_datastore' => WC_Data_Store::load( 'order' )->get_current_class_name(),
|
||||
'HPOS_feature_screen_enabled' => wc_get_container()->get( Automattic\WooCommerce\Internal\Features\FeaturesController::class )->feature_is_enabled( 'custom_order_tables' ),
|
||||
'HPOS_enabled' => OrderUtil::custom_orders_table_usage_is_enabled(),
|
||||
'HPOS_sync_enabled' => wc_get_container()->get( Order_DataSynchronizer::class )->data_sync_is_enabled(),
|
||||
);
|
||||
|
||||
@@ -1121,8 +1121,9 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
$response = array();
|
||||
$product = wc_get_product( $product_id );
|
||||
$default_values = isset( $request['default_values'] ) ? $request['default_values'] : array();
|
||||
$meta_data = isset( $request['meta_data'] ) ? $request['meta_data'] : array();
|
||||
$data_store = $product->get_data_store();
|
||||
$response['count'] = $data_store->create_all_product_variations( $product, Constants::get_constant( 'WC_MAX_LINKED_VARIATIONS' ), $default_values );
|
||||
$response['count'] = $data_store->create_all_product_variations( $product, Constants::get_constant( 'WC_MAX_LINKED_VARIATIONS' ), $default_values, $meta_data );
|
||||
|
||||
if ( isset( $request['delete'] ) && $request['delete'] ) {
|
||||
$deleted_count = $this->delete_unmatched_product_variations( $product );
|
||||
|
||||
@@ -62,6 +62,54 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/(?P<id>[\d]+)/duplicate',
|
||||
array(
|
||||
'args' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'duplicate_product' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate a product and returns the duplicated product.
|
||||
* The product status is set to "draft" and the name includes a "(copy)" at the end by default.
|
||||
*
|
||||
* @param WP_REST_Request $request Request data.
|
||||
* @return WP_REST_Response|WP_Error
|
||||
*/
|
||||
public function duplicate_product( $request ) {
|
||||
$product_id = $request->get_param( 'id' );
|
||||
$product = wc_get_product( $product_id );
|
||||
|
||||
if ( ! $product ) {
|
||||
return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
// Creating product object from request data in preparation for copying.
|
||||
$updated_product = $this->prepare_object_for_database( $request );
|
||||
$duplicated_product = ( new WC_Admin_Duplicate_Product() )->product_duplicate( $updated_product );
|
||||
|
||||
if ( is_wp_error( $duplicated_product ) ) {
|
||||
return new WP_Error( 'woocommerce_rest_product_duplicate_error', $duplicated_product->get_error_message(), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
$response_data = $duplicated_product->get_data();
|
||||
|
||||
return new WP_REST_Response( $response_data, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,7 +373,7 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
|
||||
global $wpdb;
|
||||
if ( ! empty( $this->search_sku_in_product_lookup_table ) ) {
|
||||
$like_search = '%' . $wpdb->esc_like( $this->search_sku_in_product_lookup_table ) . '%';
|
||||
$where .= ' AND ' . $wpdb->prepare( '(wc_product_meta_lookup.sku LIKE %s)', $like_search );
|
||||
$where .= ' AND ' . $wpdb->prepare( '(wc_product_meta_lookup.sku LIKE %s)', $like_search );
|
||||
}
|
||||
return $where;
|
||||
}
|
||||
@@ -1112,7 +1160,7 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'low_stock_amount' => array(
|
||||
'low_stock_amount' => array(
|
||||
'description' => __( 'Low Stock amount for the product.', 'woocommerce' ),
|
||||
'type' => array( 'integer', 'null' ),
|
||||
'context' => array( 'view', 'edit' ),
|
||||
@@ -1344,7 +1392,7 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
|
||||
),
|
||||
),
|
||||
),
|
||||
'has_options' => array(
|
||||
'has_options' => array(
|
||||
'description' => __( 'Shows if the product needs to be configured before it can be bought.', 'woocommerce' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
* @since 3.5.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
@@ -39,18 +41,18 @@ class WC_REST_Report_Orders_Totals_Controller extends WC_REST_Reports_Controller
|
||||
* @return array
|
||||
*/
|
||||
protected function get_reports() {
|
||||
$totals = wp_count_posts( 'shop_order' );
|
||||
$totals = OrderUtil::get_count_for_type( 'shop_order' );
|
||||
$data = array();
|
||||
|
||||
foreach ( wc_get_order_statuses() as $slug => $name ) {
|
||||
if ( ! isset( $totals->$slug ) ) {
|
||||
if ( ! array_key_exists( $slug, $totals ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data[] = array(
|
||||
'slug' => str_replace( 'wc-', '', $slug ),
|
||||
'name' => $name,
|
||||
'total' => (int) $totals->$slug,
|
||||
'total' => (int) $totals[ $slug ],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -393,7 +393,7 @@ function wc_get_account_saved_payment_methods_list_item_cc( $item, $payment_toke
|
||||
|
||||
$card_type = $payment_token->get_card_type();
|
||||
$item['method']['last4'] = $payment_token->get_last4();
|
||||
$item['method']['brand'] = ( ! empty( $card_type ) ? ucfirst( $card_type ) : esc_html__( 'Credit card', 'woocommerce' ) );
|
||||
$item['method']['brand'] = ( ! empty( $card_type ) ? ucwords( str_replace( '_', ' ', $card_type ) ) : esc_html__( 'Credit card', 'woocommerce' ) );
|
||||
$item['expires'] = $payment_token->get_expiry_month() . '/' . substr( $payment_token->get_expiry_year(), -2 );
|
||||
|
||||
return $item;
|
||||
|
||||
@@ -283,8 +283,6 @@ function wc_cart_totals_coupon_html( $coupon ) {
|
||||
$coupon = new WC_Coupon( $coupon );
|
||||
}
|
||||
|
||||
$discount_amount_html = '';
|
||||
|
||||
$amount = WC()->cart->get_coupon_discount_amount( $coupon->get_code(), WC()->cart->display_cart_ex_tax );
|
||||
$discount_amount_html = '-' . wc_price( $amount );
|
||||
|
||||
|
||||
@@ -1539,12 +1539,18 @@ function wc_get_credit_card_type_label( $type ) {
|
||||
'visa' => _x( 'Visa', 'Name of credit card', 'woocommerce' ),
|
||||
'discover' => _x( 'Discover', 'Name of credit card', 'woocommerce' ),
|
||||
'american express' => _x( 'American Express', 'Name of credit card', 'woocommerce' ),
|
||||
'cartes bancaires' => _x( 'Cartes Bancaires', 'Name of credit card', 'woocommerce' ),
|
||||
'diners' => _x( 'Diners', 'Name of credit card', 'woocommerce' ),
|
||||
'jcb' => _x( 'JCB', 'Name of credit card', 'woocommerce' ),
|
||||
)
|
||||
);
|
||||
|
||||
return apply_filters( 'woocommerce_get_credit_card_type_label', ( array_key_exists( $type, $labels ) ? $labels[ $type ] : ucfirst( $type ) ) );
|
||||
/**
|
||||
* Fallback to title case, uppercasing the first letter of each word.
|
||||
*
|
||||
* @since 8.9.0
|
||||
*/
|
||||
return apply_filters( 'woocommerce_get_credit_card_type_label', ( array_key_exists( $type, $labels ) ? $labels[ $type ] : ucwords( $type ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1554,7 +1560,7 @@ function wc_get_credit_card_type_label( $type ) {
|
||||
* @param string $url URL of the page to return to.
|
||||
*/
|
||||
function wc_back_link( $label, $url ) {
|
||||
echo '<small class="wc-admin-breadcrumb"><a href="' . esc_url( $url ) . '" aria-label="' . esc_attr( $label ) . '">⤴</a></small>';
|
||||
echo '<small class="wc-admin-breadcrumb"><a href="' . esc_url( $url ) . '" aria-label="' . esc_attr( $label ) . '">⤴︎</a></small>';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -979,6 +979,9 @@ function wc_format_postcode( $postcode, $country ) {
|
||||
$postcode = wc_normalize_postcode( $postcode ?? '' );
|
||||
|
||||
switch ( $country ) {
|
||||
case 'SE':
|
||||
$postcode = substr_replace( $postcode, ' ', -2, 0 );
|
||||
break;
|
||||
case 'CA':
|
||||
case 'GB':
|
||||
$postcode = substr_replace( $postcode, ' ', -3, 0 );
|
||||
@@ -1004,9 +1007,12 @@ function wc_format_postcode( $postcode, $country ) {
|
||||
$postcode = substr_replace( $postcode, ' ', 4, 0 );
|
||||
break;
|
||||
case 'LV':
|
||||
if ( preg_match( '/(?:LV)?-?(\d+)/i', $postcode, $matches ) ) {
|
||||
$postcode = count( $matches ) >= 2 ? "LV-$matches[1]" : $postcode;
|
||||
}
|
||||
$postcode = preg_replace( '/^(LV)?-?(\d+)$/', 'LV-${2}', $postcode );
|
||||
break;
|
||||
case 'CZ':
|
||||
case 'SK':
|
||||
$postcode = preg_replace( "/^({$country})-?(\d+)$/", '${1}-${2}', $postcode );
|
||||
$postcode = substr_replace( $postcode, ' ', -2, 0 );
|
||||
break;
|
||||
case 'DK':
|
||||
$postcode = preg_replace( '/^(DK)(.+)$/', '${1}-${2}', $postcode );
|
||||
|
||||
@@ -363,3 +363,13 @@ function wc_rest_check_product_reviews_permissions( $context = 'read', $object_i
|
||||
|
||||
return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $object_id, 'product_review' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current REST request is from the product editor.
|
||||
*
|
||||
* @since 8.9.0
|
||||
* @return bool
|
||||
*/
|
||||
function wc_rest_is_from_product_editor() {
|
||||
return isset( $_SERVER['HTTP_X_WC_FROM_PRODUCT_EDITOR'] ) && '1' === $_SERVER['HTTP_X_WC_FROM_PRODUCT_EDITOR'];
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Utilities\HtmlSanitizer;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
@@ -896,10 +897,11 @@ function wc_terms_and_conditions_page_content() {
|
||||
return;
|
||||
}
|
||||
|
||||
$page = get_post( $terms_page_id );
|
||||
$sanitizer = wc_get_container()->get( HtmlSanitizer::class );
|
||||
$page = get_post( $terms_page_id );
|
||||
|
||||
if ( $page && 'publish' === $page->post_status && $page->post_content && ! has_shortcode( $page->post_content, 'woocommerce_checkout' ) ) {
|
||||
echo '<div class="woocommerce-terms-and-conditions" style="display: none; max-height: 200px; overflow: auto;">' . wc_format_content( wp_kses_post( $page->post_content ) ) . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<div class="woocommerce-terms-and-conditions" style="display: none; max-height: 200px; overflow: auto;">' . wc_format_content( $sanitizer->styled_post_content( $page->post_content ) ) . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,11 @@
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\Notes\Note;
|
||||
use Automattic\WooCommerce\Admin\Notes\Notes;
|
||||
use Automattic\WooCommerce\Database\Migrations\MigrationHelper;
|
||||
use Automattic\WooCommerce\Internal\Admin\Marketing\MarketingSpecs;
|
||||
use Automattic\WooCommerce\Internal\Admin\Notes\WooSubscriptionsNotes;
|
||||
use Automattic\WooCommerce\Internal\AssignDefaultCategory;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
|
||||
@@ -167,7 +170,7 @@ function wc_update_200_taxrates() {
|
||||
)
|
||||
);
|
||||
|
||||
$loop++;
|
||||
++$loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,7 +219,7 @@ function wc_update_200_taxrates() {
|
||||
}
|
||||
}
|
||||
|
||||
$loop++;
|
||||
++$loop;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2571,7 +2574,6 @@ function wc_update_750_add_columns_to_order_stats_table() {
|
||||
and postmeta.meta_key = '_date_completed'
|
||||
SET order_stats.date_completed = IFNULL(FROM_UNIXTIME(postmeta.meta_value), '0000-00-00 00:00:00');"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2667,3 +2669,58 @@ function wc_update_870_prevent_listing_of_transient_files_directory() {
|
||||
$wp_filesystem->put_contents( $default_transient_files_dir . '/.htaccess', 'deny from all' );
|
||||
$wp_filesystem->put_contents( $default_transient_files_dir . '/index.html', '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* If it exists, remove and recreate the inbox note that asks users to connect to `Woo.com` so that the domain name is changed to the updated `WooCommerce.com`.
|
||||
*/
|
||||
function wc_update_890_update_connect_to_woocommerce_note() {
|
||||
$note = Notes::get_note_by_name( WooSubscriptionsNotes::CONNECTION_NOTE_NAME );
|
||||
if ( ! is_a( $note, 'Automattic\WooCommerce\Admin\Notes\Note' ) ) {
|
||||
return;
|
||||
}
|
||||
if ( ! str_contains( $note->get_title(), 'Woo.com' ) ) {
|
||||
return;
|
||||
}
|
||||
if ( $note->get_status() !== Note::E_WC_ADMIN_NOTE_SNOOZED && $note->get_status() !== Note::E_WC_ADMIN_NOTE_UNACTIONED ) {
|
||||
return;
|
||||
}
|
||||
Notes::delete_notes_with_name( WooSubscriptionsNotes::CONNECTION_NOTE_NAME );
|
||||
$new_note = WooSubscriptionsNotes::get_note();
|
||||
$new_note->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the PayPal Standard gateway for stores that aren't using it.
|
||||
*
|
||||
* PayPal Standard has been deprecated since WooCommerce 5.5, but there are some stores that have it showing up in their
|
||||
* list of available Payment methods even if it's not setup. In WooComerce 8.9 we will disable PayPal Standard for those stores
|
||||
* to reduce the amount of new connections to the legacy gateway.
|
||||
*
|
||||
* Shows an admin notice to inform the store owner that PayPal Standard has been disabled and suggests installing PayPal Payments.
|
||||
*/
|
||||
function wc_update_890_update_paypal_standard_load_eligibility() {
|
||||
$paypal = class_exists( 'WC_Gateway_Paypal' ) ? new WC_Gateway_Paypal() : null;
|
||||
|
||||
if ( ! $paypal ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If PayPal is enabled or set to load, but the store hasn't setup PayPal Standard live API keys and doesn't have any PayPal Orders, disable it.
|
||||
if ( ( 'yes' === $paypal->enabled || 'yes' === $paypal->get_option( '_should_load' ) ) && ! $paypal->get_option( 'api_username' ) && ! $paypal->has_paypal_orders() ) {
|
||||
$paypal->update_option( '_should_load', wc_bool_to_string( false ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the woocommerce_history_of_autoinstalled_plugins option if it doesn't exist
|
||||
* as a copy of woocommerce_autoinstalled_plugins if it exists.
|
||||
*/
|
||||
function wc_update_891_create_plugin_autoinstall_history_option() {
|
||||
$autoinstalled_plugins_history_info = get_site_option( 'woocommerce_history_of_autoinstalled_plugins' );
|
||||
if ( false === $autoinstalled_plugins_history_info ) {
|
||||
$autoinstalled_plugins_info = get_site_option( 'woocommerce_autoinstalled_plugins' );
|
||||
if ( false !== $autoinstalled_plugins_info ) {
|
||||
update_site_option( 'woocommerce_history_of_autoinstalled_plugins', $autoinstalled_plugins_info );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +159,11 @@ function wc_get_webhook_statuses() {
|
||||
* @return bool
|
||||
*/
|
||||
function wc_load_webhooks( $status = '', $limit = null ) {
|
||||
// short-circuit if webhooks should not be loaded at all.
|
||||
if ( ! is_null( $limit ) && $limit <= 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data_store = WC_Data_Store::load( 'webhook' );
|
||||
$webhooks = $data_store->get_webhooks_ids( $status );
|
||||
$loaded = 0;
|
||||
|
||||
Reference in New Issue
Block a user