plugin updates
This commit is contained in:
@@ -124,12 +124,25 @@ class Loader {
|
||||
|
||||
$sections = self::get_embed_breadcrumbs();
|
||||
$sections = is_array( $sections ) ? $sections : array( $sections );
|
||||
|
||||
$page_title = '';
|
||||
$pages_with_tabs = array( 'Settings', 'Reports', 'Status' );
|
||||
|
||||
if (
|
||||
count( $sections ) > 2 &&
|
||||
is_array( $sections[1] ) &&
|
||||
in_array( $sections[1][1], $pages_with_tabs, true )
|
||||
) {
|
||||
$page_title = $sections[1][1];
|
||||
} else {
|
||||
$page_title = end( $sections );
|
||||
}
|
||||
?>
|
||||
<div id="woocommerce-embedded-root" class="is-embed-loading">
|
||||
<div class="woocommerce-layout">
|
||||
<div class="woocommerce-layout__header is-embed-loading">
|
||||
<h1 class="woocommerce-layout__header-heading">
|
||||
<?php self::output_heading( end( $sections ) ); ?>
|
||||
<?php self::output_heading( $page_title ); ?>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
@@ -293,7 +306,7 @@ class Loader {
|
||||
$settings['orderStatuses'] = self::get_order_statuses( wc_get_order_statuses() );
|
||||
$settings['stockStatuses'] = self::get_order_statuses( wc_get_product_stock_status_options() );
|
||||
$settings['currency'] = self::get_currency_settings();
|
||||
$settings['locale'] = [
|
||||
$settings['locale'] = array(
|
||||
'siteLocale' => isset( $settings['siteLocale'] )
|
||||
? $settings['siteLocale']
|
||||
: get_locale(),
|
||||
@@ -303,7 +316,7 @@ class Loader {
|
||||
'weekdaysShort' => isset( $settings['l10n']['weekdaysShort'] )
|
||||
? $settings['l10n']['weekdaysShort']
|
||||
: array_values( $wp_locale->weekday_abbrev ),
|
||||
];
|
||||
);
|
||||
}
|
||||
|
||||
$preload_data_endpoints = apply_filters( 'woocommerce_component_settings_preload_endpoints', array() );
|
||||
@@ -327,7 +340,7 @@ class Loader {
|
||||
$setting_options = new \WC_REST_Setting_Options_V2_Controller();
|
||||
foreach ( $preload_settings as $group ) {
|
||||
$group_settings = $setting_options->get_group_settings( $group );
|
||||
$preload_settings = [];
|
||||
$preload_settings = array();
|
||||
foreach ( $group_settings as $option ) {
|
||||
if ( array_key_exists( 'id', $option ) && array_key_exists( 'value', $option ) ) {
|
||||
$preload_settings[ $option['id'] ] = $option['value'];
|
||||
@@ -374,7 +387,7 @@ class Loader {
|
||||
if ( ! empty( $preload_data_endpoints ) ) {
|
||||
$settings['dataEndpoints'] = isset( $settings['dataEndpoints'] )
|
||||
? $settings['dataEndpoints']
|
||||
: [];
|
||||
: array();
|
||||
foreach ( $preload_data_endpoints as $key => $endpoint ) {
|
||||
// Handle error case: rest_do_request() doesn't guarantee success.
|
||||
if ( empty( $preload_data[ $endpoint ] ) ) {
|
||||
|
||||
@@ -4,7 +4,8 @@ declare( strict_types = 1 );
|
||||
namespace Automattic\WooCommerce\Internal\Admin\Logging\FileV2;
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use WP_Filesystem_Direct;
|
||||
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* File class.
|
||||
@@ -60,14 +61,6 @@ class File {
|
||||
* @param string $path The absolute path of the file.
|
||||
*/
|
||||
public function __construct( $path ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
|
||||
global $wp_filesystem;
|
||||
|
||||
if ( ! $wp_filesystem instanceof WP_Filesystem_Direct ) {
|
||||
WP_Filesystem();
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
$this->ingest_path();
|
||||
}
|
||||
@@ -237,27 +230,33 @@ class File {
|
||||
/**
|
||||
* Check if the file represented by the class instance is a file and is readable.
|
||||
*
|
||||
* @global WP_Filesystem_Direct $wp_filesystem
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_readable(): bool {
|
||||
global $wp_filesystem;
|
||||
try {
|
||||
$filesystem = FilesystemUtil::get_wp_filesystem();
|
||||
$is_readable = $filesystem->is_file( $this->path ) && $filesystem->is_readable( $this->path );
|
||||
} catch ( Exception $exception ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $wp_filesystem->is_file( $this->path ) && $wp_filesystem->is_readable( $this->path );
|
||||
return $is_readable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file represented by the class instance is a file and is writable.
|
||||
*
|
||||
* @global WP_Filesystem_Direct $wp_filesystem
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_writable(): bool {
|
||||
global $wp_filesystem;
|
||||
try {
|
||||
$filesystem = FilesystemUtil::get_wp_filesystem();
|
||||
$is_writable = $filesystem->is_file( $this->path ) && $filesystem->is_writable( $this->path );
|
||||
} catch ( Exception $exception ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $wp_filesystem->is_file( $this->path ) && $wp_filesystem->is_writable( $this->path );
|
||||
return $is_writable;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -372,31 +371,38 @@ class File {
|
||||
/**
|
||||
* Get the time of the last modification of the file, as a Unix timestamp. Or false if the file isn't readable.
|
||||
*
|
||||
* @global WP_Filesystem_Direct $wp_filesystem
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public function get_modified_timestamp() {
|
||||
global $wp_filesystem;
|
||||
try {
|
||||
$filesystem = FilesystemUtil::get_wp_filesystem();
|
||||
$timestamp = $filesystem->mtime( $this->path );
|
||||
} catch ( Exception $exception ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $wp_filesystem->mtime( $this->path );
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the file in bytes. Or false if the file isn't readable.
|
||||
*
|
||||
* @global WP_Filesystem_Direct $wp_filesystem
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public function get_file_size() {
|
||||
global $wp_filesystem;
|
||||
try {
|
||||
$filesystem = FilesystemUtil::get_wp_filesystem();
|
||||
|
||||
if ( ! $wp_filesystem->is_readable( $this->path ) ) {
|
||||
if ( ! $filesystem->is_readable( $this->path ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$size = $filesystem->size( $this->path );
|
||||
} catch ( Exception $exception ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $wp_filesystem->size( $this->path );
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -405,10 +411,13 @@ class File {
|
||||
* @return bool
|
||||
*/
|
||||
protected function create(): bool {
|
||||
global $wp_filesystem;
|
||||
|
||||
$created = $wp_filesystem->touch( $this->path );
|
||||
$modded = $wp_filesystem->chmod( $this->path );
|
||||
try {
|
||||
$filesystem = FilesystemUtil::get_wp_filesystem();
|
||||
$created = $filesystem->touch( $this->path );
|
||||
$modded = $filesystem->chmod( $this->path );
|
||||
} catch ( Exception $exception ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $created && $modded;
|
||||
}
|
||||
@@ -463,8 +472,6 @@ class File {
|
||||
return false;
|
||||
}
|
||||
|
||||
global $wp_filesystem;
|
||||
|
||||
$created = 0;
|
||||
if ( $this->has_standard_filename() ) {
|
||||
$created = $this->get_created_timestamp();
|
||||
@@ -489,7 +496,13 @@ class File {
|
||||
$new_filename = str_replace( $search, $replace, $old_filename );
|
||||
$new_path = str_replace( $old_filename, $new_filename, $this->path );
|
||||
|
||||
$moved = $wp_filesystem->move( $this->path, $new_path, true );
|
||||
try {
|
||||
$filesystem = FilesystemUtil::get_wp_filesystem();
|
||||
$moved = $filesystem->move( $this->path, $new_path, true );
|
||||
} catch ( Exception $exception ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $moved ) {
|
||||
return false;
|
||||
}
|
||||
@@ -503,13 +516,16 @@ class File {
|
||||
/**
|
||||
* Delete the file from the filesystem.
|
||||
*
|
||||
* @global WP_Filesystem_Direct $wp_filesystem
|
||||
*
|
||||
* @return bool True on success, false on failure.
|
||||
*/
|
||||
public function delete(): bool {
|
||||
global $wp_filesystem;
|
||||
try {
|
||||
$filesystem = FilesystemUtil::get_wp_filesystem();
|
||||
$deleted = $filesystem->delete( $this->path, false, 'f' );
|
||||
} catch ( Exception $exception ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $wp_filesystem->delete( $this->path, false, 'f' );
|
||||
return $deleted;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,10 +481,7 @@ class FileController {
|
||||
|
||||
$files = $this->get_files_by_id( $file_ids );
|
||||
foreach ( $files as $file ) {
|
||||
$result = false;
|
||||
if ( $file->is_writable() ) {
|
||||
$result = $file->delete();
|
||||
}
|
||||
$result = $file->delete();
|
||||
|
||||
if ( true === $result ) {
|
||||
$deleted ++;
|
||||
@@ -662,7 +659,7 @@ class FileController {
|
||||
$path = realpath( Settings::get_log_directory() );
|
||||
|
||||
if ( wp_is_writable( $path ) ) {
|
||||
$iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $path, \FilesystemIterator::SKIP_DOTS ) );
|
||||
$iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $path, \FilesystemIterator::SKIP_DOTS ), \RecursiveIteratorIterator::CATCH_GET_CHILD );
|
||||
|
||||
foreach ( $iterator as $file ) {
|
||||
$bytes += $file->getSize();
|
||||
|
||||
@@ -3,8 +3,9 @@ declare( strict_types=1 );
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\Logging\FileV2;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
|
||||
use Exception;
|
||||
use WP_Error;
|
||||
use WP_Filesystem_Direct;
|
||||
|
||||
/**
|
||||
* FileExport class.
|
||||
@@ -39,11 +40,6 @@ class FileExporter {
|
||||
* part of the path.
|
||||
*/
|
||||
public function __construct( string $path, string $alternate_filename = '' ) {
|
||||
global $wp_filesystem;
|
||||
if ( ! $wp_filesystem instanceof WP_Filesystem_Direct ) {
|
||||
WP_Filesystem();
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
$this->alternate_filename = $alternate_filename;
|
||||
}
|
||||
@@ -54,8 +50,14 @@ class FileExporter {
|
||||
* @return WP_Error|void Only returns something if there is an error.
|
||||
*/
|
||||
public function emit_file() {
|
||||
global $wp_filesystem;
|
||||
if ( ! $wp_filesystem->is_file( $this->path ) || ! $wp_filesystem->is_readable( $this->path ) ) {
|
||||
try {
|
||||
$filesystem = FilesystemUtil::get_wp_filesystem();
|
||||
$is_readable = $filesystem->is_file( $this->path ) && $filesystem->is_readable( $this->path );
|
||||
} catch ( Exception $exception ) {
|
||||
$is_readable = false;
|
||||
}
|
||||
|
||||
if ( ! $is_readable ) {
|
||||
return new WP_Error(
|
||||
'wc_logs_invalid_file',
|
||||
__( 'Could not access file.', 'woocommerce' )
|
||||
@@ -104,11 +106,11 @@ class FileExporter {
|
||||
* @return void
|
||||
*/
|
||||
private function send_contents(): void {
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen -- No suitable alternative.
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- No suitable alternative.
|
||||
$stream = fopen( $this->path, 'rb' );
|
||||
|
||||
while ( is_resource( $stream ) && ! feof( $stream ) ) {
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fread -- No suitable alternative.
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fread -- No suitable alternative.
|
||||
$chunk = fread( $stream, self::CHUNK_SIZE );
|
||||
|
||||
if ( is_string( $chunk ) ) {
|
||||
@@ -117,7 +119,7 @@ class FileExporter {
|
||||
}
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose -- No suitable alternative.
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- No suitable alternative.
|
||||
fclose( $stream );
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ class PageController {
|
||||
if ( ! $this->settings->logging_is_enabled() ) {
|
||||
add_action(
|
||||
'admin_notices',
|
||||
function() {
|
||||
function () {
|
||||
?>
|
||||
<div class="notice notice-warning">
|
||||
<p>
|
||||
@@ -395,7 +395,7 @@ class PageController {
|
||||
if ( is_string( $line ) ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- format_line does the escaping.
|
||||
echo $this->format_line( $line, $line_number );
|
||||
$line_number ++;
|
||||
++$line_number;
|
||||
}
|
||||
?>
|
||||
<?php endwhile; ?>
|
||||
@@ -464,7 +464,7 @@ class PageController {
|
||||
array(
|
||||
'file_id' => array(
|
||||
'filter' => FILTER_CALLBACK,
|
||||
'options' => function( $file_id ) {
|
||||
'options' => function ( $file_id ) {
|
||||
return sanitize_file_name( wp_unslash( $file_id ) );
|
||||
},
|
||||
),
|
||||
@@ -484,13 +484,13 @@ class PageController {
|
||||
),
|
||||
'search' => array(
|
||||
'filter' => FILTER_CALLBACK,
|
||||
'options' => function( $search ) {
|
||||
'options' => function ( $search ) {
|
||||
return esc_html( wp_unslash( $search ) );
|
||||
},
|
||||
),
|
||||
'source' => array(
|
||||
'filter' => FILTER_CALLBACK,
|
||||
'options' => function( $source ) {
|
||||
'options' => function ( $source ) {
|
||||
return File::sanitize_source( wp_unslash( $source ) );
|
||||
},
|
||||
),
|
||||
@@ -624,7 +624,7 @@ class PageController {
|
||||
}
|
||||
|
||||
if ( is_wp_error( $export_error ) ) {
|
||||
wp_die( wp_kses_post( $export_error ) );
|
||||
wp_die( wp_kses_post( $export_error->get_error_message() ) );
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
@@ -654,7 +654,7 @@ class PageController {
|
||||
if ( is_numeric( $deleted ) ) {
|
||||
add_action(
|
||||
'admin_notices',
|
||||
function() use ( $deleted ) {
|
||||
function () use ( $deleted ) {
|
||||
?>
|
||||
<div class="notice notice-info is-dismissible">
|
||||
<p>
|
||||
|
||||
@@ -8,10 +8,12 @@ use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\File;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\FileController;
|
||||
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
|
||||
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil;
|
||||
use Automattic\WooCommerce\Proxies\LegacyProxy;
|
||||
use Exception;
|
||||
use WC_Admin_Settings;
|
||||
use WC_Log_Handler_DB, WC_Log_Handler_File, WC_Log_Levels;
|
||||
use WP_Filesystem_Base;
|
||||
use WP_Filesystem_Direct;
|
||||
|
||||
/**
|
||||
* Settings class.
|
||||
@@ -78,14 +80,13 @@ class Settings {
|
||||
|
||||
if ( true === $result ) {
|
||||
// Create infrastructure to prevent listing contents of the logs directory.
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
global $wp_filesystem;
|
||||
if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
|
||||
WP_Filesystem();
|
||||
try {
|
||||
$filesystem = FilesystemUtil::get_wp_filesystem();
|
||||
$filesystem->put_contents( $dir . '.htaccess', 'deny from all' );
|
||||
$filesystem->put_contents( $dir . 'index.html', '' );
|
||||
} catch ( Exception $exception ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
// Creation failed.
|
||||
}
|
||||
|
||||
$wp_filesystem->put_contents( $dir . '.htaccess', 'deny from all' );
|
||||
$wp_filesystem->put_contents( $dir . 'index.html', '' );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,6 +293,20 @@ class Settings {
|
||||
$location_info = array();
|
||||
$directory = self::get_log_directory();
|
||||
|
||||
$status_info = array();
|
||||
try {
|
||||
$filesystem = FilesystemUtil::get_wp_filesystem();
|
||||
if ( $filesystem instanceof WP_Filesystem_Direct ) {
|
||||
$status_info[] = __( '✅ Ready', 'woocommerce' );
|
||||
} else {
|
||||
$status_info[] = __( '⚠️ The file system is not configured for direct writes. This could cause problems for the logger.', 'woocommerce' );
|
||||
$status_info[] = __( 'You may want to switch to the database for log storage.', 'woocommerce' );
|
||||
}
|
||||
} catch ( Exception $exception ) {
|
||||
$status_info[] = __( '⚠️ The file system connection could not be initialized.', 'woocommerce' );
|
||||
$status_info[] = __( 'You may want to switch to the database for log storage.', 'woocommerce' );
|
||||
}
|
||||
|
||||
$location_info[] = sprintf(
|
||||
// translators: %s is a location in the filesystem.
|
||||
__( 'Log files are stored in this directory: %s', 'woocommerce' ),
|
||||
@@ -317,6 +332,11 @@ class Settings {
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'title',
|
||||
),
|
||||
'file_status' => array(
|
||||
'title' => __( 'Status', 'woocommerce' ),
|
||||
'type' => 'info',
|
||||
'text' => implode( "\n\n", $status_info ),
|
||||
),
|
||||
'log_directory' => array(
|
||||
'title' => __( 'Location', 'woocommerce' ),
|
||||
'type' => 'info',
|
||||
@@ -340,7 +360,7 @@ class Settings {
|
||||
$table = "{$wpdb->prefix}woocommerce_log";
|
||||
|
||||
$location_info = sprintf(
|
||||
// translators: %s is a location in the filesystem.
|
||||
// translators: %s is the name of a table in the database.
|
||||
__( 'Log entries are stored in this database table: %s', 'woocommerce' ),
|
||||
"<code>$table</code>"
|
||||
);
|
||||
|
||||
@@ -221,6 +221,9 @@ class WooSubscriptionsNotes {
|
||||
* @return int|false
|
||||
*/
|
||||
public function get_product_id_from_subscription_note( &$note ) {
|
||||
if ( ! is_object( $note ) ) {
|
||||
return false;
|
||||
}
|
||||
$content_data = $note->get_content_data();
|
||||
|
||||
if ( property_exists( $content_data, 'product_id' ) ) {
|
||||
|
||||
@@ -982,7 +982,7 @@ class ListTable extends WP_List_Table {
|
||||
*
|
||||
* @return string Edit link for the order.
|
||||
*/
|
||||
private function get_order_edit_link( WC_Order $order ) : string {
|
||||
private function get_order_edit_link( WC_Order $order ): string {
|
||||
return $this->page_controller->get_edit_url( $order->get_id() );
|
||||
}
|
||||
|
||||
@@ -1352,7 +1352,7 @@ class ListTable extends WP_List_Table {
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_remove_order_personal_data', $order ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
|
||||
$changed++;
|
||||
++$changed;
|
||||
}
|
||||
|
||||
return $changed;
|
||||
@@ -1380,7 +1380,7 @@ class ListTable extends WP_List_Table {
|
||||
|
||||
$order->update_status( $new_status, __( 'Order status changed by bulk edit.', 'woocommerce' ), true );
|
||||
do_action( 'woocommerce_order_edit_status', $id, $new_status ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
|
||||
$changed++;
|
||||
++$changed;
|
||||
}
|
||||
|
||||
return $changed;
|
||||
@@ -1403,7 +1403,7 @@ class ListTable extends WP_List_Table {
|
||||
$updated_order = wc_get_order( $id );
|
||||
|
||||
if ( ( $force_delete && false === $updated_order ) || ( ! $force_delete && $updated_order->get_status() === 'trash' ) ) {
|
||||
$changed++;
|
||||
++$changed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1423,7 +1423,7 @@ class ListTable extends WP_List_Table {
|
||||
|
||||
foreach ( $ids as $id ) {
|
||||
if ( $orders_store->untrash_order( wc_get_order( $id ) ) ) {
|
||||
$changed++;
|
||||
++$changed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1547,6 +1547,11 @@ class ListTable extends WP_List_Table {
|
||||
<a href="{{ data.shipping_address_map_url }}" target="_blank">{{{ data.formatted_shipping_address }}}</a>
|
||||
<# } #>
|
||||
|
||||
<# if ( data.data.shipping.phone ) { #>
|
||||
<strong><?php esc_html_e( 'Phone', 'woocommerce' ); ?></strong>
|
||||
<a href="tel:{{ data.data.shipping.phone }}">{{ data.data.shipping.phone }}</a>
|
||||
<# } #>
|
||||
|
||||
<# if ( data.shipping_via ) { #>
|
||||
<strong><?php esc_html_e( 'Shipping method', 'woocommerce' ); ?></strong>
|
||||
{{ data.shipping_via }}
|
||||
@@ -1629,10 +1634,25 @@ class ListTable extends WP_List_Table {
|
||||
'products' => __( 'Products', 'woocommerce' ),
|
||||
'all' => __( 'All', 'woocommerce' ),
|
||||
);
|
||||
|
||||
/**
|
||||
* Filters the search filters available in the admin order search. Can be used to add new or remove existing filters.
|
||||
* When adding new filters, `woocommerce_hpos_generate_where_for_search_filter` should also be used to generate the WHERE clause for the new filter
|
||||
*
|
||||
* @since 8.9.0.
|
||||
*
|
||||
* @param $options array List of available filters.
|
||||
*/
|
||||
$options = apply_filters( 'woocommerce_hpos_admin_search_filters', $options );
|
||||
$saved_setting = get_user_setting( 'wc-search-filter-hpos-admin', 'all' );
|
||||
$selected = sanitize_text_field( wp_unslash( $_REQUEST['search-filter'] ?? $saved_setting ) );
|
||||
if ( $saved_setting !== $selected ) {
|
||||
set_user_setting( 'wc-search-filter-hpos-admin', $selected );
|
||||
}
|
||||
?>
|
||||
<select name="search-filter" id="order-search-filter">
|
||||
<?php foreach ( $options as $value => $label ) { ?>
|
||||
<option value="<?php echo esc_attr( wp_unslash( sanitize_text_field( $value ) ) ); ?>" <?php selected( $value, sanitize_text_field( wp_unslash( $_REQUEST['search-filter'] ?? 'all' ) ) ); ?>><?php echo esc_html( $label ); ?></option>
|
||||
<option value="<?php echo esc_attr( wp_unslash( sanitize_text_field( $value ) ) ); ?>" <?php selected( $value, sanitize_text_field( wp_unslash( $selected ) ) ); ?>><?php echo esc_html( $label ); ?></option>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,12 +66,6 @@ class OrderAttribution {
|
||||
public function output( WC_Order $order ) {
|
||||
$meta = $this->filter_meta_data( $order->get_meta_data() );
|
||||
|
||||
// If we don't have any meta to show, return.
|
||||
if ( empty( $meta ) ) {
|
||||
esc_html_e( 'No order source data available.', 'woocommerce' );
|
||||
return;
|
||||
}
|
||||
|
||||
$this->format_meta_data( $meta );
|
||||
|
||||
// No more details if there is only the origin value - this is for unknown source types.
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
namespace Automattic\WooCommerce\Internal\ComingSoon;
|
||||
|
||||
/**
|
||||
* Adds hooks to invalidate caches when the coming soon settings are changed.
|
||||
*/
|
||||
class ComingSoonCacheInvalidator {
|
||||
|
||||
/**
|
||||
* Sets up the hooks.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final public function init() {
|
||||
add_action( 'update_option_woocommerce_coming_soon', array( $this, 'invalidate_caches' ) );
|
||||
add_action( 'update_option_woocommerce_store_pages_only', array( $this, 'invalidate_caches' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the WordPress object cache and other known caches.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function invalidate_caches() {
|
||||
// Standard WordPress object cache invalidation.
|
||||
wp_cache_flush();
|
||||
|
||||
/**
|
||||
* Temporary solution to invalidate the WordPress.com Edge Cache. We can trigger
|
||||
* invalidation by publishing any post. It should be refactored with a supported integration.
|
||||
*/
|
||||
$cart_page_id = get_option( 'woocommerce_cart_page_id' ) ?? null;
|
||||
if ( $cart_page_id ) {
|
||||
// Re-publish the coming soon page. Has the side-effect of invalidating the Edge Cache.
|
||||
wp_update_post(
|
||||
array(
|
||||
'ID' => $cart_page_id,
|
||||
'post_status' => 'publish',
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
namespace Automattic\WooCommerce\Internal\ComingSoon;
|
||||
|
||||
use Automattic\WooCommerce\Admin\WCAdminHelper;
|
||||
|
||||
/**
|
||||
* Provides helper methods for coming soon functionality.
|
||||
*/
|
||||
class ComingSoonHelper {
|
||||
|
||||
/**
|
||||
* Returns true when the entire site is live.
|
||||
*/
|
||||
public function is_site_live(): bool {
|
||||
return 'yes' !== get_option( 'woocommerce_coming_soon' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when the entire site is coming soon mode.
|
||||
*/
|
||||
public function is_site_coming_soon(): bool {
|
||||
return 'yes' === get_option( 'woocommerce_coming_soon' ) && 'yes' !== get_option( 'woocommerce_store_pages_only' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when only the store pages are in coming soon mode.
|
||||
*/
|
||||
public function is_store_coming_soon(): bool {
|
||||
return 'yes' === get_option( 'woocommerce_coming_soon' ) && 'yes' === get_option( 'woocommerce_store_pages_only' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when the provided URL is behind a coming soon screen.
|
||||
*
|
||||
* @param string $url The URL to check.
|
||||
*/
|
||||
public function is_url_coming_soon( string $url ): bool {
|
||||
// Early exit if coming soon mode not active.
|
||||
if ( $this->is_site_live() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $this->is_site_coming_soon() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the URL is a store page when in "store coming soon" mode.
|
||||
if ( $this->is_store_coming_soon() && WCAdminHelper::is_store_page( $url ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Default to false.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the relative URL from the WP instance.
|
||||
*
|
||||
* @internal
|
||||
* @link https://wordpress.stackexchange.com/a/274572
|
||||
* @param \WP $wp WordPress environment instance.
|
||||
*/
|
||||
public function get_url_from_wp( \WP $wp ) {
|
||||
// Special case for plain permalinks.
|
||||
if ( empty( get_option( 'permalink_structure' ) ) ) {
|
||||
return '/' . add_query_arg( $wp->query_vars, $wp->request );
|
||||
}
|
||||
|
||||
return trailingslashit( '/' . $wp->request );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
namespace Automattic\WooCommerce\Internal\ComingSoon;
|
||||
|
||||
use Automattic\WooCommerce\Admin\Features\Features;
|
||||
|
||||
/**
|
||||
* Handles the parse_request hook to determine whether the current page needs
|
||||
* to be replaced with a comiing soon screen.
|
||||
*/
|
||||
class ComingSoonRequestHandler {
|
||||
|
||||
/**
|
||||
* Coming soon helper.
|
||||
*
|
||||
* @var ComingSoonHelper
|
||||
*/
|
||||
private $coming_soon_helper = null;
|
||||
|
||||
/**
|
||||
* Sets up the hook.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param ComingSoonHelper $coming_soon_helper Dependency.
|
||||
*/
|
||||
final public function init( ComingSoonHelper $coming_soon_helper ) {
|
||||
$this->coming_soon_helper = $coming_soon_helper;
|
||||
add_filter( 'template_include', array( $this, 'handle_template_include' ) );
|
||||
add_action( 'wp_enqueue_scripts', array( $this, 'deregister_unnecessary_styles' ), 100 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregisters unnecessary styles for the coming soon page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deregister_unnecessary_styles() {
|
||||
global $wp;
|
||||
|
||||
if ( ! $this->should_show_coming_soon( $wp ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->coming_soon_helper->is_site_coming_soon() ) {
|
||||
global $wp_styles;
|
||||
|
||||
foreach ( $wp_styles->registered as $handle => $registered_style ) {
|
||||
// Deregister all styles except for block styles.
|
||||
if (
|
||||
strpos( $handle, 'wp-block' ) !== 0 &&
|
||||
strpos( $handle, 'core-block' ) !== 0
|
||||
) {
|
||||
wp_deregister_style( $handle );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the page template with a 'coming soon' when the site is in coming soon mode.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $template The path to the previously determined template.
|
||||
* @return string|null The path to the 'coming soon' template or null to prevent further template loading in FSE themes.
|
||||
*/
|
||||
public function handle_template_include( $template ) {
|
||||
global $wp;
|
||||
|
||||
if ( ! $this->should_show_coming_soon( $wp ) ) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
// A coming soon page needs to be displayed. Don't cache this response.
|
||||
nocache_headers();
|
||||
|
||||
// Optimize search engine by returning 503 status code and set retry-after header to 12 hours.
|
||||
status_header( 503 );
|
||||
header( 'Retry-After: ' . 12 * HOUR_IN_SECONDS );
|
||||
|
||||
add_theme_support( 'block-templates' );
|
||||
wp_dequeue_style( 'global-styles' );
|
||||
$coming_soon_template = get_query_template( 'coming-soon' );
|
||||
|
||||
if ( ! wc_current_theme_is_fse_theme() && $this->coming_soon_helper->is_store_coming_soon() ) {
|
||||
get_header();
|
||||
}
|
||||
|
||||
include $coming_soon_template;
|
||||
|
||||
if ( ! wc_current_theme_is_fse_theme() && $this->coming_soon_helper->is_store_coming_soon() ) {
|
||||
get_footer();
|
||||
}
|
||||
|
||||
if ( wc_current_theme_is_fse_theme() ) {
|
||||
// Since we've already rendered a template, return null to ensure no other template is rendered.
|
||||
return null;
|
||||
} else {
|
||||
// In non-FSE themes, other templates will still be rendered.
|
||||
// We need to exit to prevent further processing.
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the coming soon screen should be shown.
|
||||
*
|
||||
* @param \WP $wp Current WordPress environment instance.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function should_show_coming_soon( \WP &$wp ) {
|
||||
// Early exit if LYS feature is disabled.
|
||||
if ( ! Features::is_enabled( 'launch-your-store' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Early exit if the user is logged in as administrator / shop manager.
|
||||
if ( current_user_can( 'manage_woocommerce' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not show coming soon on 404 pages when restrict to store pages only.
|
||||
if ( $this->coming_soon_helper->is_store_coming_soon() && is_404() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Early exit if the URL doesn't need a coming soon screen.
|
||||
$url = $this->coming_soon_helper->get_url_from_wp( $wp );
|
||||
|
||||
if ( ! $this->coming_soon_helper->is_url_coming_soon( $url ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exclude users with a private link.
|
||||
if ( isset( $_GET['woo-share'] ) && get_option( 'woocommerce_share_key' ) === $_GET['woo-share'] ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
// Persist the share link with a cookie for 90 days.
|
||||
setcookie( 'woo-share', sanitize_text_field( wp_unslash( $_GET['woo-share'] ) ), time() + 60 * 60 * 24 * 90, '/' ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
return false;
|
||||
}
|
||||
if ( isset( $_COOKIE['woo-share'] ) && get_option( 'woocommerce_share_key' ) === $_COOKIE['woo-share'] ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -250,7 +250,9 @@ abstract class CustomMetaDataStore {
|
||||
$query = "SELECT DISTINCT meta_key FROM {$db_info['table']} ";
|
||||
|
||||
if ( ! $include_private ) {
|
||||
$query .= $wpdb->prepare( 'WHERE meta_key NOT LIKE %s ', $wpdb->esc_like( '_' ) . '%' );
|
||||
$query .= $wpdb->prepare( 'WHERE meta_key != \'\' AND meta_key NOT LIKE %s ', $wpdb->esc_like( '_' ) . '%' );
|
||||
} else {
|
||||
$query .= "WHERE meta_key != '' ";
|
||||
}
|
||||
|
||||
$order = in_array( strtoupper( $order ), array( 'ASC', 'DESC' ), true ) ? $order : 'ASC';
|
||||
|
||||
@@ -437,7 +437,7 @@ class CustomOrdersTableController {
|
||||
return array();
|
||||
}
|
||||
|
||||
$get_value = function() {
|
||||
$get_value = function () {
|
||||
return $this->custom_orders_table_usage_is_enabled() ? 'yes' : 'no';
|
||||
};
|
||||
|
||||
@@ -446,18 +446,20 @@ class CustomOrdersTableController {
|
||||
* gets called while it's still being instantiated and creates and endless loop.
|
||||
*/
|
||||
|
||||
$get_desc = function() {
|
||||
$get_desc = function () {
|
||||
$plugin_compatibility = $this->features_controller->get_compatible_plugins_for_feature( 'custom_order_tables', true );
|
||||
|
||||
return $this->plugin_util->generate_incompatible_plugin_feature_warning( 'custom_order_tables', $plugin_compatibility );
|
||||
};
|
||||
|
||||
$get_disabled = function() {
|
||||
$get_disabled = function () {
|
||||
$plugin_compatibility = $this->features_controller->get_compatible_plugins_for_feature( 'custom_order_tables', true );
|
||||
$sync_complete = 0 === $this->get_orders_pending_sync_count();
|
||||
$disabled = array();
|
||||
// Changing something here? might also want to look at `enable|disable` functions in CLIRunner.
|
||||
if ( count( array_merge( $plugin_compatibility['uncertain'], $plugin_compatibility['incompatible'] ) ) > 0 ) {
|
||||
$incompatible_plugins = array_merge( $plugin_compatibility['uncertain'], $plugin_compatibility['incompatible'] );
|
||||
$incompatible_plugins = array_diff( $incompatible_plugins, $this->plugin_util->get_plugins_excluded_from_compatibility_ui() );
|
||||
if ( count( $incompatible_plugins ) > 0 ) {
|
||||
$disabled = array( 'yes' );
|
||||
}
|
||||
if ( ! $sync_complete && ! $this->changing_data_source_with_sync_pending_is_allowed() ) {
|
||||
@@ -493,11 +495,11 @@ class CustomOrdersTableController {
|
||||
return array();
|
||||
}
|
||||
|
||||
$get_value = function() {
|
||||
$get_value = function () {
|
||||
return get_option( DataSynchronizer::ORDERS_DATA_SYNC_ENABLED_OPTION );
|
||||
};
|
||||
|
||||
$get_sync_message = function() {
|
||||
$get_sync_message = function () {
|
||||
$orders_pending_sync_count = $this->get_orders_pending_sync_count();
|
||||
$sync_in_progress = $this->batch_processing_controller->is_enqueued( get_class( $this->data_synchronizer ) );
|
||||
$sync_enabled = $this->data_synchronizer->data_sync_is_enabled();
|
||||
@@ -576,7 +578,7 @@ class CustomOrdersTableController {
|
||||
return implode( '<br />', $sync_message );
|
||||
};
|
||||
|
||||
$get_description_is_error = function() {
|
||||
$get_description_is_error = function () {
|
||||
$sync_is_pending = $this->get_orders_pending_sync_count() > 0;
|
||||
|
||||
return $sync_is_pending && $this->changing_data_source_with_sync_pending_is_allowed();
|
||||
|
||||
@@ -153,21 +153,26 @@ class LegacyDataHandler {
|
||||
public function cleanup_post_data( int $order_id, bool $skip_checks = false ): void {
|
||||
global $wpdb;
|
||||
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! $order ) {
|
||||
// translators: %d is an order ID.
|
||||
throw new \Exception( esc_html( sprintf( __( '%d is not a valid order ID.', 'woocommerce' ), $order_id ) ) );
|
||||
}
|
||||
$post_is_placeholder = get_post_type( $order_id ) === $this->data_synchronizer::PLACEHOLDER_ORDER_POST_TYPE;
|
||||
if ( ! $post_is_placeholder ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( ! $skip_checks && ! $this->is_order_newer_than_post( $order ) ) {
|
||||
throw new \Exception( esc_html( sprintf( __( 'Data in posts table appears to be more recent than in HPOS tables.', 'woocommerce' ) ) ) );
|
||||
if ( ! $order ) {
|
||||
// translators: %d is an order ID.
|
||||
throw new \Exception( esc_html( sprintf( __( '%d is not a valid order ID.', 'woocommerce' ), $order_id ) ) );
|
||||
}
|
||||
|
||||
if ( ! $skip_checks && ! $this->is_order_newer_than_post( $order ) ) {
|
||||
// translators: %1 is an order ID.
|
||||
throw new \Exception( esc_html( sprintf( __( 'Data in posts table appears to be more recent than in HPOS tables. Compare order data with `wp wc hpos diff %1$d` and use `wp wc hpos backfill %1$d --from=posts --to=hpos` to fix.', 'woocommerce' ), $order_id ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Delete all metadata.
|
||||
$wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"DELETE FROM {$wpdb->postmeta} WHERE post_id = %d",
|
||||
$order->get_id()
|
||||
$order_id
|
||||
)
|
||||
);
|
||||
|
||||
@@ -178,11 +183,11 @@ class LegacyDataHandler {
|
||||
"UPDATE {$wpdb->posts} SET post_type = %s, post_status = %s WHERE ID = %d",
|
||||
$this->data_synchronizer::PLACEHOLDER_ORDER_POST_TYPE,
|
||||
'draft',
|
||||
$order->get_id()
|
||||
$order_id
|
||||
)
|
||||
);
|
||||
|
||||
clean_post_cache( $order->get_id() );
|
||||
clean_post_cache( $order_id );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1631,15 +1631,7 @@ WHERE
|
||||
);
|
||||
// phpcs:enable
|
||||
|
||||
$meta_data_query = $this->get_order_meta_select_statement();
|
||||
$order_data = array();
|
||||
$meta_data = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $meta_data_query and $order_meta_table is autogenerated and should already be prepared. $id_placeholder is already prepared.
|
||||
"$meta_data_query WHERE $order_meta_table.order_id in ( $id_placeholder )",
|
||||
$ids
|
||||
)
|
||||
);
|
||||
$order_data = array();
|
||||
|
||||
foreach ( $table_data as $table_datum ) {
|
||||
$id = $table_datum->{"{$order_table_alias}_id"};
|
||||
@@ -1663,14 +1655,27 @@ WHERE
|
||||
$order_data[ $id ]->meta_data = array();
|
||||
}
|
||||
|
||||
foreach ( $meta_data as $meta_datum ) {
|
||||
// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key, WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Not a meta query.
|
||||
$order_data[ $meta_datum->order_id ]->meta_data[] = (object) array(
|
||||
'meta_id' => $meta_datum->id,
|
||||
'meta_key' => $meta_datum->meta_key,
|
||||
'meta_value' => $meta_datum->meta_value,
|
||||
if ( count( $order_data ) > 0 ) {
|
||||
$meta_order_ids = array_keys( $order_data );
|
||||
$meta_order_id_placeholder = implode( ', ', array_fill( 0, count( $meta_order_ids ), '%d' ) );
|
||||
$meta_data_query = $this->get_order_meta_select_statement();
|
||||
$meta_data = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $meta_data_query and $order_meta_table is autogenerated and should already be prepared. $id_placeholder is already prepared.
|
||||
"$meta_data_query WHERE $order_meta_table.order_id in ( $meta_order_id_placeholder )",
|
||||
$ids
|
||||
)
|
||||
);
|
||||
// phpcs:enable
|
||||
|
||||
foreach ( $meta_data as $meta_datum ) {
|
||||
// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key, WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Not a meta query.
|
||||
$order_data[ $meta_datum->order_id ]->meta_data[] = (object) array(
|
||||
'meta_id' => $meta_datum->id,
|
||||
'meta_key' => $meta_datum->meta_key,
|
||||
'meta_value' => $meta_datum->meta_value,
|
||||
);
|
||||
// phpcs:enable
|
||||
}
|
||||
}
|
||||
return $order_data;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class OrdersTableSearchQuery {
|
||||
/**
|
||||
* Limits the search to a specific field.
|
||||
*
|
||||
* @var string
|
||||
* @var string[]
|
||||
*/
|
||||
private $search_filters;
|
||||
|
||||
@@ -40,8 +40,8 @@ class OrdersTableSearchQuery {
|
||||
*/
|
||||
public function __construct( OrdersTableQuery $query ) {
|
||||
$this->query = $query;
|
||||
$this->search_term = urldecode( $query->get( 's' ) );
|
||||
$this->search_filters = $this->sanitize_search_filters( urldecode( $query->get( 'search_filter' ) ) );
|
||||
$this->search_term = $query->get( 's' );
|
||||
$this->search_filters = $this->sanitize_search_filters( $query->get( 'search_filter' ) ?? '' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,17 +52,18 @@ class OrdersTableSearchQuery {
|
||||
* @return array Array of search filters.
|
||||
*/
|
||||
private function sanitize_search_filters( string $search_filter ) : array {
|
||||
$available_filters = array(
|
||||
$core_filters = array(
|
||||
'order_id',
|
||||
'transaction_id',
|
||||
'customer_email',
|
||||
'customers', // customers also searches in meta.
|
||||
'products',
|
||||
);
|
||||
|
||||
if ( 'all' === $search_filter || '' === $search_filter ) {
|
||||
return $available_filters;
|
||||
return $core_filters;
|
||||
} else {
|
||||
return array_intersect( $available_filters, array( $search_filter ) );
|
||||
return array( $search_filter );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +120,29 @@ class OrdersTableSearchQuery {
|
||||
LEFT JOIN $items_table AS search_query_items ON search_query_items.order_id = $orders_table.id
|
||||
";
|
||||
}
|
||||
return '';
|
||||
|
||||
/**
|
||||
* Filter to support adding a custom order search filter.
|
||||
* Provide a JOIN clause for a new search filter. This should be used along with `woocommerce_hpos_admin_search_filters`
|
||||
* to declare a new custom filter, and `woocommerce_hpos_generate_where_for_search_filter` to generate the WHERE
|
||||
* clause.
|
||||
*
|
||||
* Hardcoded JOINS (products) cannot be modified using this filter for consistency.
|
||||
*
|
||||
* @since 8.9.0
|
||||
*
|
||||
* @param string $join The JOIN clause.
|
||||
* @param string $search_term The search term.
|
||||
* @param string $search_filter The search filter. Use this to bail early if this is not filter you are interested in.
|
||||
* @param OrdersTableQuery $query The order query object.
|
||||
*/
|
||||
return apply_filters(
|
||||
'woocommerce_hpos_generate_join_for_search_filter',
|
||||
'',
|
||||
$this->search_term,
|
||||
$search_filter,
|
||||
$this->query
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,6 +200,13 @@ class OrdersTableSearchQuery {
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'transaction_id' === $search_filter ) {
|
||||
return $wpdb->prepare(
|
||||
"`$order_table`.transaction_id LIKE %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $order_table is hardcoded.
|
||||
'%' . $wpdb->esc_like( $this->search_term ) . '%'
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'products' === $search_filter ) {
|
||||
return $wpdb->prepare(
|
||||
'search_query_items.order_item_name LIKE %s',
|
||||
@@ -189,7 +219,28 @@ class OrdersTableSearchQuery {
|
||||
return "`$order_table`.id IN ( $meta_sub_query ) ";
|
||||
}
|
||||
|
||||
return '';
|
||||
/**
|
||||
* Filter to support adding a custom order search filter.
|
||||
* Provide a WHERE clause for a custom search filter via this filter. This should be used with the
|
||||
* `woocommerce_hpos_admin_search_filters` to declare a new custom filter, and optionally also with the
|
||||
* `woocommerce_hpos_generate_join_for_search_filter` filter if a join is also needed.
|
||||
*
|
||||
* Hardcoded filters (products, customers, ID and email) cannot be modified using this filter for consistency.
|
||||
*
|
||||
* @since 8.9.0
|
||||
*
|
||||
* @param string $where WHERE clause to add to the search query.
|
||||
* @param string $search_term The search term.
|
||||
* @param string $search_filter Name of the search filter. Use this to bail early if this is not the filter you are looking for.
|
||||
* @param OrdersTableQuery $query The order query object.
|
||||
*/
|
||||
return apply_filters(
|
||||
'woocommerce_hpos_generate_where_for_search_filter',
|
||||
'',
|
||||
$this->search_term,
|
||||
$search_filter,
|
||||
$this->query
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders;
|
||||
|
||||
use Automattic\WooCommerce\Internal\DependencyManagement\AbstractServiceProvider;
|
||||
use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonCacheInvalidator;
|
||||
use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonRequestHandler;
|
||||
use Automattic\WooCommerce\Internal\ComingSoon\ComingSoonHelper;
|
||||
|
||||
/**
|
||||
* Service provider for the Coming Soon mode.
|
||||
*/
|
||||
class ComingSoonServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The classes/interfaces that are serviced by this service provider.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = array(
|
||||
ComingSoonCacheInvalidator::class,
|
||||
ComingSoonHelper::class,
|
||||
ComingSoonRequestHandler::class,
|
||||
);
|
||||
|
||||
/**
|
||||
* Register the classes.
|
||||
*/
|
||||
public function register() {
|
||||
$this->add( ComingSoonCacheInvalidator::class );
|
||||
$this->add( ComingSoonHelper::class );
|
||||
$this->add( ComingSoonRequestHandler::class )->addArgument( ComingSoonHelper::class );
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ trait DownloadableProductTrait {
|
||||
$product_downloads_section_group->add_block(
|
||||
array(
|
||||
'id' => 'product-downloadable',
|
||||
'blockName' => 'woocommerce/product-checkbox-field',
|
||||
'blockName' => 'woocommerce/product-toggle-field',
|
||||
'order' => 10,
|
||||
'attributes' => array(
|
||||
'property' => 'downloadable',
|
||||
|
||||
@@ -64,7 +64,7 @@ class ProductVariationTemplate extends AbstractProductFormTemplate implements Pr
|
||||
/**
|
||||
* Adds the group blocks to the template.
|
||||
*/
|
||||
private function add_group_blocks() {
|
||||
protected function add_group_blocks() {
|
||||
$this->add_group(
|
||||
array(
|
||||
'id' => $this::GROUP_IDS['GENERAL'],
|
||||
@@ -106,7 +106,7 @@ class ProductVariationTemplate extends AbstractProductFormTemplate implements Pr
|
||||
/**
|
||||
* Adds the general group blocks to the template.
|
||||
*/
|
||||
private function add_general_group_blocks() {
|
||||
protected function add_general_group_blocks() {
|
||||
$general_group = $this->get_group_by_id( $this::GROUP_IDS['GENERAL'] );
|
||||
$general_group->add_block(
|
||||
array(
|
||||
@@ -193,7 +193,7 @@ class ProductVariationTemplate extends AbstractProductFormTemplate implements Pr
|
||||
/**
|
||||
* Adds the pricing group blocks to the template.
|
||||
*/
|
||||
private function add_pricing_group_blocks() {
|
||||
protected function add_pricing_group_blocks() {
|
||||
$is_calc_taxes_enabled = wc_tax_enabled();
|
||||
|
||||
$pricing_group = $this->get_group_by_id( $this::GROUP_IDS['PRICING'] );
|
||||
@@ -315,7 +315,7 @@ class ProductVariationTemplate extends AbstractProductFormTemplate implements Pr
|
||||
/**
|
||||
* Adds the inventory group blocks to the template.
|
||||
*/
|
||||
private function add_inventory_group_blocks() {
|
||||
protected function add_inventory_group_blocks() {
|
||||
$inventory_group = $this->get_group_by_id( $this::GROUP_IDS['INVENTORY'] );
|
||||
$inventory_group->add_block(
|
||||
array(
|
||||
@@ -366,7 +366,7 @@ class ProductVariationTemplate extends AbstractProductFormTemplate implements Pr
|
||||
'blockName' => 'woocommerce/product-toggle-field',
|
||||
'order' => 20,
|
||||
'attributes' => array(
|
||||
'label' => __( 'Track stock quantity for this product', 'woocommerce' ),
|
||||
'label' => __( 'Track inventory', 'woocommerce' ),
|
||||
'property' => 'manage_stock',
|
||||
'disabled' => 'yes' !== get_option( 'woocommerce_manage_stock' ),
|
||||
'disabledCopy' => sprintf(
|
||||
@@ -425,7 +425,7 @@ class ProductVariationTemplate extends AbstractProductFormTemplate implements Pr
|
||||
/**
|
||||
* Adds the shipping group blocks to the template.
|
||||
*/
|
||||
private function add_shipping_group_blocks() {
|
||||
protected function add_shipping_group_blocks() {
|
||||
$shipping_group = $this->get_group_by_id( $this::GROUP_IDS['SHIPPING'] );
|
||||
$shipping_group->add_block(
|
||||
array(
|
||||
@@ -471,7 +471,7 @@ class ProductVariationTemplate extends AbstractProductFormTemplate implements Pr
|
||||
'title' => __( 'Fees & dimensions', 'woocommerce' ),
|
||||
'description' => sprintf(
|
||||
/* translators: %1$s: How to get started? link opening tag. %2$s: How to get started? link closing tag.*/
|
||||
__( 'Set up shipping costs and enter dimensions used for accurate rate calculations. %1$sHow to get started?%2$s.', 'woocommerce' ),
|
||||
__( 'Set up shipping costs and enter dimensions used for accurate rate calculations. %1$sHow to get started?%2$s', 'woocommerce' ),
|
||||
'<a href="https://woocommerce.com/posts/how-to-calculate-shipping-costs-for-your-woocommerce-store/" target="_blank" rel="noreferrer">',
|
||||
'</a>'
|
||||
),
|
||||
|
||||
@@ -215,6 +215,16 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
'attributes' => array(
|
||||
'name' => 'Product name',
|
||||
'autoFocus' => true,
|
||||
'metadata' => array(
|
||||
'bindings' => array(
|
||||
'value' => array(
|
||||
'source' => 'woocommerce/entity-product',
|
||||
'args' => array(
|
||||
'prop' => 'name',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
@@ -529,8 +539,8 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
'title' => __( 'Custom fields', 'woocommerce' ),
|
||||
'description' => sprintf(
|
||||
/* translators: %1$s: Custom fields guide link opening tag. %2$s: Custom fields guide link closing tag. */
|
||||
__( 'Custom fields can be used in a variety of ways, such as sharing more detailed product information, showing more input fields, or internal inventory organization. %1$sRead more about custom fields%2$s', 'woocommerce' ),
|
||||
'<a href="https://wordpress.org/documentation/article/assign-custom-fields/" target="_blank" rel="noreferrer">',
|
||||
__( 'Custom fields can be used in a variety of ways, such as sharing more detailed product information, showing more input fields, or for internal inventory organization. %1$sRead more about custom fields%2$s', 'woocommerce' ),
|
||||
'<a href="https://woocommerce.com/document/custom-product-fields/" target="_blank" rel="noreferrer">',
|
||||
'</a>'
|
||||
),
|
||||
),
|
||||
@@ -600,10 +610,10 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
);
|
||||
$pricing_column_1->add_block(
|
||||
array(
|
||||
'id' => 'product-pricing-regular-price',
|
||||
'blockName' => 'woocommerce/product-regular-price-field',
|
||||
'order' => 10,
|
||||
'attributes' => array(
|
||||
'id' => 'product-pricing-regular-price',
|
||||
'blockName' => 'woocommerce/product-regular-price-field',
|
||||
'order' => 10,
|
||||
'attributes' => array(
|
||||
'name' => 'regular_price',
|
||||
'label' => __( 'List price', 'woocommerce' ),
|
||||
'help' => $is_calc_taxes_enabled ? null : sprintf(
|
||||
@@ -613,6 +623,11 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
'</a>'
|
||||
),
|
||||
),
|
||||
'disableConditions' => array(
|
||||
array(
|
||||
'expression' => 'editedProduct.type === "variable"',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
$pricing_column_2 = $pricing_columns->add_block(
|
||||
@@ -627,12 +642,17 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
);
|
||||
$pricing_column_2->add_block(
|
||||
array(
|
||||
'id' => 'product-pricing-sale-price',
|
||||
'blockName' => 'woocommerce/product-sale-price-field',
|
||||
'order' => 10,
|
||||
'attributes' => array(
|
||||
'id' => 'product-pricing-sale-price',
|
||||
'blockName' => 'woocommerce/product-sale-price-field',
|
||||
'order' => 10,
|
||||
'attributes' => array(
|
||||
'label' => __( 'Sale price', 'woocommerce' ),
|
||||
),
|
||||
'disableConditions' => array(
|
||||
array(
|
||||
'expression' => 'editedProduct.type === "variable"',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
$product_pricing_section->add_block(
|
||||
@@ -778,32 +798,44 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
);
|
||||
$product_inventory_inner_section->add_block(
|
||||
array(
|
||||
'id' => 'product-sku-field',
|
||||
'blockName' => 'woocommerce/product-sku-field',
|
||||
'order' => 10,
|
||||
'id' => 'product-sku-field',
|
||||
'blockName' => 'woocommerce/product-sku-field',
|
||||
'order' => 10,
|
||||
'disableConditions' => array(
|
||||
array(
|
||||
'expression' => 'editedProduct.type === "variable"',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$manage_stock = 'yes' === get_option( 'woocommerce_manage_stock' );
|
||||
$product_inventory_inner_section->add_block(
|
||||
array(
|
||||
'id' => 'product-track-stock',
|
||||
'blockName' => 'woocommerce/product-toggle-field',
|
||||
'order' => 20,
|
||||
'attributes' => array(
|
||||
'label' => __( 'Track stock quantity for this product', 'woocommerce' ),
|
||||
'id' => 'product-track-stock',
|
||||
'blockName' => 'woocommerce/product-toggle-field',
|
||||
'order' => 20,
|
||||
'attributes' => array(
|
||||
'label' => __( 'Track inventory', 'woocommerce' ),
|
||||
'property' => 'manage_stock',
|
||||
'disabled' => 'yes' !== get_option( 'woocommerce_manage_stock' ),
|
||||
'disabledCopy' => sprintf(
|
||||
'disabled' => ! $manage_stock,
|
||||
'disabledCopy' => ! $manage_stock ? sprintf(
|
||||
/* translators: %1$s: Learn more link opening tag. %2$s: Learn more link closing tag.*/
|
||||
__( 'Per your %1$sstore settings%2$s, inventory management is <strong>disabled</strong>.', 'woocommerce' ),
|
||||
'<a href="' . admin_url( 'admin.php?page=wc-settings&tab=products§ion=inventory' ) . '" target="_blank" rel="noreferrer">',
|
||||
'</a>'
|
||||
),
|
||||
) : null,
|
||||
),
|
||||
'hideConditions' => Features::is_enabled( 'product-external-affiliate' ) || Features::is_enabled( 'product-grouped' ) ? array(
|
||||
'hideConditions' => Features::is_enabled( 'product-external-affiliate' ) || Features::is_enabled( 'product-grouped' ) ? array(
|
||||
array(
|
||||
'expression' => 'editedProduct.type === "external" || editedProduct.type === "grouped"',
|
||||
),
|
||||
) : null,
|
||||
'disableConditions' => array(
|
||||
array(
|
||||
'expression' => 'editedProduct.type === "variable"',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
$product_inventory_quantity_hide_conditions = array(
|
||||
@@ -836,10 +868,10 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
}
|
||||
$product_inventory_section->add_block(
|
||||
array(
|
||||
'id' => 'product-stock-status',
|
||||
'blockName' => 'woocommerce/product-radio-field',
|
||||
'order' => 10,
|
||||
'attributes' => array(
|
||||
'id' => 'product-stock-status',
|
||||
'blockName' => 'woocommerce/product-radio-field',
|
||||
'order' => 10,
|
||||
'attributes' => array(
|
||||
'title' => __( 'Stock status', 'woocommerce' ),
|
||||
'property' => 'stock_status',
|
||||
'options' => array(
|
||||
@@ -857,7 +889,12 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
),
|
||||
),
|
||||
),
|
||||
'hideConditions' => $product_stock_status_hide_conditions,
|
||||
'hideConditions' => $product_stock_status_hide_conditions,
|
||||
'disableConditions' => array(
|
||||
array(
|
||||
'expression' => 'editedProduct.type === "variable"',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1023,7 +1060,7 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
'title' => __( 'Fees & dimensions', 'woocommerce' ),
|
||||
'description' => sprintf(
|
||||
/* translators: %1$s: How to get started? link opening tag. %2$s: How to get started? link closing tag.*/
|
||||
__( 'Set up shipping costs and enter dimensions used for accurate rate calculations. %1$sHow to get started?%2$s.', 'woocommerce' ),
|
||||
__( 'Set up shipping costs and enter dimensions used for accurate rate calculations. %1$sHow to get started?%2$s', 'woocommerce' ),
|
||||
'<a href="https://woocommerce.com/posts/how-to-calculate-shipping-costs-for-your-woocommerce-store/" target="_blank" rel="noreferrer">',
|
||||
'</a>'
|
||||
),
|
||||
@@ -1032,16 +1069,26 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
);
|
||||
$product_fee_and_dimensions_section->add_block(
|
||||
array(
|
||||
'id' => 'product-shipping-class',
|
||||
'blockName' => 'woocommerce/product-shipping-class-field',
|
||||
'order' => 10,
|
||||
'id' => 'product-shipping-class',
|
||||
'blockName' => 'woocommerce/product-shipping-class-field',
|
||||
'order' => 10,
|
||||
'disableConditions' => array(
|
||||
array(
|
||||
'expression' => 'editedProduct.type === "variable"',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
$product_fee_and_dimensions_section->add_block(
|
||||
array(
|
||||
'id' => 'product-shipping-dimensions',
|
||||
'blockName' => 'woocommerce/product-shipping-dimensions-fields',
|
||||
'order' => 20,
|
||||
'id' => 'product-shipping-dimensions',
|
||||
'blockName' => 'woocommerce/product-shipping-dimensions-fields',
|
||||
'order' => 20,
|
||||
'disableConditions' => array(
|
||||
array(
|
||||
'expression' => 'editedProduct.type === "variable"',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1106,8 +1153,8 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
'attributes' => array(
|
||||
'title' => __( 'Upsells', 'woocommerce' ),
|
||||
'description' => sprintf(
|
||||
/* translators: %1$s: Learn more about linked products. %2$s: Learn more about linked products.*/
|
||||
__( 'Upsells are typically products that are extra profitable or better quality or more expensive. Experiment with combinations to boost sales. %1$sLearn more about linked products.%2$s', 'woocommerce' ),
|
||||
/* translators: %1$s: "Learn more about linked products" link opening tag. %2$s: "Learn more about linked products" link closing tag. */
|
||||
__( 'Upsells are typically products that are extra profitable or better quality or more expensive. Experiment with combinations to boost sales. %1$sLearn more about linked products%2$s', 'woocommerce' ),
|
||||
'<br /><a href="https://woocommerce.com/document/related-products-up-sells-and-cross-sells/" target="_blank" rel="noreferrer">',
|
||||
'</a>'
|
||||
),
|
||||
@@ -1139,8 +1186,8 @@ class SimpleProductTemplate extends AbstractProductFormTemplate implements Produ
|
||||
'attributes' => array(
|
||||
'title' => __( 'Cross-sells', 'woocommerce' ),
|
||||
'description' => sprintf(
|
||||
/* translators: %1$s: Learn more about linked products. %2$s: Learn more about linked products.*/
|
||||
__( 'By suggesting complementary products in the cart using cross-sells, you can significantly increase the average order value. %1$sLearn more about linked products.%2$s', 'woocommerce' ),
|
||||
/* translators: %1$s: "Learn more about linked products" link opening tag. %2$s: "Learn more about linked products" link closing tag. */
|
||||
__( 'By suggesting complementary products in the cart using cross-sells, you can significantly increase the average order value. %1$sLearn more about linked products%2$s', 'woocommerce' ),
|
||||
'<br /><a href="https://woocommerce.com/document/related-products-up-sells-and-cross-sells/" target="_blank" rel="noreferrer">',
|
||||
'</a>'
|
||||
),
|
||||
|
||||
@@ -16,7 +16,6 @@ use WC_Customer;
|
||||
use WC_Log_Levels;
|
||||
use WC_Logger_Interface;
|
||||
use WC_Order;
|
||||
use WC_Tracks;
|
||||
|
||||
/**
|
||||
* Class OrderAttributionController
|
||||
@@ -335,9 +334,6 @@ class OrderAttributionController implements RegisterHooksInterface {
|
||||
$source_type = $order->get_meta( $this->get_meta_prefixed_field_name( 'source_type' ) );
|
||||
$source = $order->get_meta( $this->get_meta_prefixed_field_name( 'utm_source' ) );
|
||||
$origin = $this->get_origin_label( $source_type, $source );
|
||||
if ( empty( $origin ) ) {
|
||||
$origin = __( 'Unknown', 'woocommerce' );
|
||||
}
|
||||
echo esc_html( $origin );
|
||||
}
|
||||
|
||||
@@ -440,12 +436,9 @@ class OrderAttributionController implements RegisterHooksInterface {
|
||||
'customer_registered' => $order->get_customer_id() ? 'yes' : 'no',
|
||||
);
|
||||
|
||||
$this->proxy->call_static(
|
||||
WC_Tracks::class,
|
||||
'record_event',
|
||||
'order_attribution',
|
||||
$tracks_data
|
||||
);
|
||||
if ( function_exists( 'wc_admin_record_tracks_event' ) ) {
|
||||
wc_admin_record_tracks_event( 'order_attribution', $tracks_data );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,8 +74,12 @@ class COTMigrationUtil {
|
||||
* @return bool
|
||||
*/
|
||||
public function is_custom_order_tables_in_sync() : bool {
|
||||
if ( ! $this->data_synchronizer->data_sync_is_enabled() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sync_status = $this->data_synchronizer->get_sync_status();
|
||||
return 0 === $sync_status['current_pending_count'] && $this->data_synchronizer->data_sync_is_enabled();
|
||||
return 0 === $sync_status['current_pending_count'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
declare( strict_types = 1 );
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Utilities;
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Exception;
|
||||
use WP_Filesystem_Base;
|
||||
|
||||
/**
|
||||
* FilesystemUtil class.
|
||||
*/
|
||||
class FilesystemUtil {
|
||||
/**
|
||||
* Wrapper to retrieve the class instance contained in the $wp_filesystem global, after initializing if necessary.
|
||||
*
|
||||
* @return WP_Filesystem_Base
|
||||
* @throws Exception Thrown when the filesystem fails to initialize.
|
||||
*/
|
||||
public static function get_wp_filesystem(): WP_Filesystem_Base {
|
||||
global $wp_filesystem;
|
||||
|
||||
if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
|
||||
$initialized = self::initialize_wp_filesystem();
|
||||
|
||||
if ( false === $initialized ) {
|
||||
throw new Exception( 'The WordPress filesystem could not be initialized.' );
|
||||
}
|
||||
}
|
||||
|
||||
return $wp_filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to initialize the WP filesystem with defined credentials if they are available.
|
||||
*
|
||||
* @return bool True if the $wp_filesystem global was successfully initialized.
|
||||
*/
|
||||
protected static function initialize_wp_filesystem(): bool {
|
||||
global $wp_filesystem;
|
||||
|
||||
if ( $wp_filesystem instanceof WP_Filesystem_Base ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
|
||||
$method = get_filesystem_method();
|
||||
$initialized = false;
|
||||
|
||||
if ( 'direct' === $method ) {
|
||||
$initialized = WP_Filesystem();
|
||||
} elseif ( false !== $method ) {
|
||||
// See https://core.trac.wordpress.org/changeset/56341.
|
||||
ob_start();
|
||||
$credentials = request_filesystem_credentials( '' );
|
||||
ob_end_clean();
|
||||
|
||||
$initialized = $credentials && WP_Filesystem( $credentials );
|
||||
}
|
||||
|
||||
return is_null( $initialized ) ? false : $initialized;
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,20 @@ class HtmlSanitizer {
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Sanitizes a chunk of HTML, by following the same rules as `wp_kses_post()` but also allowing
|
||||
* the style element to be supplied.
|
||||
*
|
||||
* @param string $html The HTML to be sanitized.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function styled_post_content( string $html ): string {
|
||||
$rules = wp_kses_allowed_html( 'post' );
|
||||
$rules['style'] = true;
|
||||
return wp_kses( $html, $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the HTML according to the provided rules.
|
||||
*
|
||||
|
||||
@@ -155,6 +155,12 @@ class PluginInstaller implements RegisterHooksInterface {
|
||||
$auto_installed_plugins[ $plugin_name ] = $plugin_data;
|
||||
update_site_option( 'woocommerce_autoinstalled_plugins', $auto_installed_plugins );
|
||||
|
||||
$auto_installed_plugins_history = get_site_option( 'woocommerce_history_of_autoinstalled_plugins', array() );
|
||||
if ( ! isset( $auto_installed_plugins_history[ $plugin_name ] ) ) {
|
||||
$auto_installed_plugins_history[ $plugin_name ] = $plugin_data;
|
||||
update_site_option( 'woocommerce_history_of_autoinstalled_plugins', $auto_installed_plugins_history );
|
||||
}
|
||||
|
||||
$post_install = function () use ( $plugin_name, $plugin_version, $installed_by, $plugin_url, $plugin_data ) {
|
||||
$log_context = array(
|
||||
'source' => 'plugin_auto_installs',
|
||||
|
||||
Reference in New Issue
Block a user