plugin updates
This commit is contained in:
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry;
|
||||
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||
|
||||
/**
|
||||
* Block template registry.
|
||||
*/
|
||||
final class BlockTemplateRegistry {
|
||||
|
||||
/**
|
||||
* Class instance.
|
||||
*
|
||||
* @var BlockTemplateRegistry|null
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Templates.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $templates = array();
|
||||
|
||||
/**
|
||||
* Get the instance of the class.
|
||||
*/
|
||||
public static function get_instance(): BlockTemplateRegistry {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a single template.
|
||||
*
|
||||
* @param BlockTemplateInterface $template Template to register.
|
||||
*
|
||||
* @throws \ValueError If a template with the same ID already exists.
|
||||
*/
|
||||
public function register( BlockTemplateInterface $template ) {
|
||||
$id = $template->get_id();
|
||||
|
||||
if ( isset( $this->templates[ $id ] ) ) {
|
||||
throw new \ValueError( 'A template with the specified ID already exists in the registry.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when a template is registered.
|
||||
*
|
||||
* @param BlockTemplateInterface $template Template that was registered.
|
||||
*
|
||||
* @since 8.2.0
|
||||
*/
|
||||
do_action( 'woocommerce_block_template_register', $template );
|
||||
|
||||
$this->templates[ $id ] = $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the registered templates.
|
||||
*/
|
||||
public function get_all_registered(): array {
|
||||
return $this->templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single registered template.
|
||||
*
|
||||
* @param string $id ID of the template.
|
||||
*/
|
||||
public function get_registered( $id ): BlockTemplateInterface {
|
||||
return isset( $this->templates[ $id ] ) ? $this->templates[ $id ] : null;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry;
|
||||
|
||||
/**
|
||||
* Block template controller.
|
||||
*/
|
||||
class BlockTemplatesController {
|
||||
|
||||
/**
|
||||
* Block template registry
|
||||
*
|
||||
* @var BlockTemplateRegistry
|
||||
*/
|
||||
private $block_template_registry;
|
||||
|
||||
/**
|
||||
* Block template transformer.
|
||||
*
|
||||
* @var TemplateTransformer
|
||||
*/
|
||||
private $template_transformer;
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*/
|
||||
public function init( $block_template_registry, $template_transformer ) {
|
||||
$this->block_template_registry = $block_template_registry;
|
||||
$this->template_transformer = $template_transformer;
|
||||
add_action( 'rest_api_init', array( $this, 'register_templates' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register templates in the blocks endpoint.
|
||||
*/
|
||||
public function register_templates() {
|
||||
$templates = $this->block_template_registry->get_all_registered();
|
||||
|
||||
foreach ( $templates as $template ) {
|
||||
add_filter( 'pre_get_block_templates', function( $query_result, $query, $template_type ) use( $template ) {
|
||||
if ( ! isset( $query['area'] ) || $query['area'] !== $template->get_area() ) {
|
||||
return $query_result;
|
||||
}
|
||||
|
||||
$wp_block_template = $this->template_transformer->transform( $template );
|
||||
$query_result[] = $wp_block_template;
|
||||
|
||||
return $query_result;
|
||||
}, 10, 3 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry;
|
||||
|
||||
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
|
||||
|
||||
/**
|
||||
* Template transformer.
|
||||
*/
|
||||
class TemplateTransformer {
|
||||
|
||||
/**
|
||||
* Transform the WooCommerceBlockTemplate to a WP_Block_Template.
|
||||
*
|
||||
* @param object $block_template The product template.
|
||||
*/
|
||||
public function transform( BlockTemplateInterface $block_template ): \WP_Block_Template {
|
||||
$template = new \WP_Block_Template();
|
||||
$template->id = $block_template->get_id();
|
||||
$template->theme = 'woocommerce/woocommerce';
|
||||
$template->content = $block_template->get_formatted_template();
|
||||
$template->source = 'plugin';
|
||||
$template->slug = $block_template->get_id();
|
||||
$template->type = 'wp_template';
|
||||
$template->title = $block_template->get_title();
|
||||
$template->description = $block_template->get_description();
|
||||
$template->status = 'publish';
|
||||
$template->has_theme_file = true;
|
||||
$template->origin = 'plugin';
|
||||
$template->is_custom = false; // Templates loaded from the filesystem aren't custom, ones that have been edited and loaded from the DB are.
|
||||
$template->post_types = array(); // Don't appear in any Edit Post template selector dropdown.
|
||||
$template->area = $block_template->get_area();
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -131,4 +131,19 @@ abstract class AbstractBlockTemplate implements BlockTemplateInterface {
|
||||
|
||||
return $inner_blocks_formatted_template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template as JSON like array.
|
||||
*
|
||||
* @return array The JSON.
|
||||
*/
|
||||
public function to_json(): array {
|
||||
return array(
|
||||
'id' => $this->get_id(),
|
||||
'title' => $this->get_title(),
|
||||
'description' => $this->get_description(),
|
||||
'area' => $this->get_area(),
|
||||
'blockTemplates' => $this->get_formatted_template(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,25 +210,35 @@ class BlockTemplateLogger {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all template events for a given template.
|
||||
* Get all template events for a given template as a JSON like array.
|
||||
*
|
||||
* @param string $template_id Template ID.
|
||||
*/
|
||||
public function get_formatted_template_events( string $template_id ): array {
|
||||
public function template_events_to_json( string $template_id ): array {
|
||||
if ( ! isset( $this->all_template_events[ $template_id ] ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$template_events = $this->all_template_events[ $template_id ];
|
||||
$template = $this->templates[ $template_id ];
|
||||
|
||||
$formatted_template_events = array();
|
||||
return $this->to_json( $template_events );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all template events as a JSON like array.
|
||||
*
|
||||
* @param array $template_events Template events.
|
||||
*
|
||||
* @return array The JSON.
|
||||
*/
|
||||
private function to_json( array $template_events ): array {
|
||||
$json = array();
|
||||
|
||||
foreach ( $template_events as $template_event ) {
|
||||
$container = $template_event['container'];
|
||||
$block = $template_event['block'];
|
||||
|
||||
$formatted_template_events[] = array(
|
||||
$json[] = array(
|
||||
'level' => $template_event['level'],
|
||||
'event_type' => $template_event['event_type'],
|
||||
'message' => $template_event['message'],
|
||||
@@ -246,7 +256,7 @@ class BlockTemplateLogger {
|
||||
);
|
||||
}
|
||||
|
||||
return $formatted_template_events;
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,7 +321,7 @@ class BlockTemplateLogger {
|
||||
* @param array $template_events Template events.
|
||||
*/
|
||||
private function generate_template_events_hash( array $template_events ): string {
|
||||
return md5( wp_json_encode( $template_events ) );
|
||||
return md5( wp_json_encode( $this->to_json( $template_events ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,7 +8,6 @@ namespace Automattic\WooCommerce\Internal\Admin;
|
||||
use Automattic\WooCommerce\Admin\Features\Features;
|
||||
use Automattic\WooCommerce\Admin\PageController;
|
||||
use Automattic\WooCommerce\Admin\PluginsHelper;
|
||||
use Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry\BlockTemplatesController;
|
||||
use Automattic\WooCommerce\Internal\Admin\ProductReviews\Reviews;
|
||||
use Automattic\WooCommerce\Internal\Admin\ProductReviews\ReviewsCommentsOverrides;
|
||||
use Automattic\WooCommerce\Internal\Admin\Settings;
|
||||
@@ -73,7 +72,6 @@ class Loader {
|
||||
|
||||
wc_get_container()->get( Reviews::class );
|
||||
wc_get_container()->get( ReviewsCommentsOverrides::class );
|
||||
wc_get_container()->get( BlockTemplatesController::class );
|
||||
|
||||
add_filter( 'admin_body_class', array( __CLASS__, 'add_admin_body_classes' ) );
|
||||
add_filter( 'admin_title', array( __CLASS__, 'update_admin_title' ) );
|
||||
|
||||
@@ -86,7 +86,7 @@ class FileController {
|
||||
* Class FileController
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->log_directory = trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) );
|
||||
$this->log_directory = trailingslashit( Constants::get_constant( 'WC_LOG_DIR' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
namespace Automattic\WooCommerce\Internal\Admin\Logging;
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\FileController;
|
||||
use Automattic\WooCommerce\Proxies\LegacyProxy;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\{ File, FileController };
|
||||
use WC_Log_Handler;
|
||||
|
||||
/**
|
||||
@@ -18,11 +17,19 @@ class LogHandlerFileV2 extends WC_Log_Handler {
|
||||
*/
|
||||
private $file_controller;
|
||||
|
||||
/**
|
||||
* Instance of the Settings class.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* LogHandlerFileV2 class.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->file_controller = wc_get_container()->get( FileController::class );
|
||||
$this->settings = wc_get_container()->get( Settings::class );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,20 +80,17 @@ class LogHandlerFileV2 extends WC_Log_Handler {
|
||||
$time_string = static::format_time( $timestamp );
|
||||
$level_string = strtoupper( $level );
|
||||
|
||||
// Remove line breaks so the whole entry is on one line in the file.
|
||||
$formatted_message = str_replace( PHP_EOL, ' ', $message );
|
||||
|
||||
unset( $context['source'] );
|
||||
if ( ! empty( $context ) ) {
|
||||
if ( isset( $context['backtrace'] ) && true === filter_var( $context['backtrace'], FILTER_VALIDATE_BOOLEAN ) ) {
|
||||
$context['backtrace'] = static::get_backtrace();
|
||||
}
|
||||
|
||||
$formatted_context = wp_json_encode( $context );
|
||||
$formatted_message .= " CONTEXT: $formatted_context";
|
||||
$formatted_context = wp_json_encode( $context );
|
||||
$message .= " CONTEXT: $formatted_context";
|
||||
}
|
||||
|
||||
$entry = "$time_string $level_string $formatted_message";
|
||||
$entry = "$time_string $level_string $message";
|
||||
|
||||
// phpcs:disable WooCommerce.Commenting.CommentHooks.MissingSinceComment
|
||||
/** This filter is documented in includes/abstracts/abstract-wc-log-handler.php */
|
||||
@@ -152,6 +156,63 @@ class LogHandlerFileV2 extends WC_Log_Handler {
|
||||
return sanitize_title( $source );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all logs from a specific source.
|
||||
*
|
||||
* @param string $source The source of the log entries.
|
||||
*
|
||||
* @return int The number of files that were deleted.
|
||||
*/
|
||||
public function clear( string $source ): int {
|
||||
$source = File::sanitize_source( $source );
|
||||
|
||||
$files = $this->file_controller->get_files(
|
||||
array(
|
||||
'source' => $source,
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $files ) || count( $files ) < 1 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$file_ids = array_map(
|
||||
fn( $file ) => $file->get_file_id(),
|
||||
$files
|
||||
);
|
||||
|
||||
$deleted = $this->file_controller->delete_files( $file_ids );
|
||||
|
||||
if ( $deleted > 0 ) {
|
||||
$this->handle(
|
||||
time(),
|
||||
'info',
|
||||
sprintf(
|
||||
esc_html(
|
||||
// translators: %1$s is a number of log files, %2$s is a slug-style name for a file.
|
||||
_n(
|
||||
'%1$s log file from source %2$s was deleted.',
|
||||
'%1$s log files from source %2$s were deleted.',
|
||||
$deleted,
|
||||
'woocommerce'
|
||||
)
|
||||
),
|
||||
number_format_i18n( $deleted ),
|
||||
sprintf(
|
||||
'<code>%s</code>',
|
||||
esc_html( $source )
|
||||
)
|
||||
),
|
||||
array(
|
||||
'source' => 'wc_logger',
|
||||
'backtrace' => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all logs older than a specified timestamp.
|
||||
*
|
||||
@@ -172,7 +233,7 @@ class LogHandlerFileV2 extends WC_Log_Handler {
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $files ) ) {
|
||||
if ( is_wp_error( $files ) || count( $files ) < 1 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -181,12 +242,8 @@ class LogHandlerFileV2 extends WC_Log_Handler {
|
||||
$files
|
||||
);
|
||||
|
||||
$deleted = $this->file_controller->delete_files( $file_ids );
|
||||
|
||||
// phpcs:disable WooCommerce.Commenting.CommentHooks.MissingSinceComment
|
||||
/** This filter is documented in includes/class-wc-logger.php. */
|
||||
$retention_days = absint( apply_filters( 'woocommerce_logger_days_to_retain_logs', 30 ) );
|
||||
// phpcs:enable WooCommerce.Commenting.CommentHooks.MissingSinceComment
|
||||
$deleted = $this->file_controller->delete_files( $file_ids );
|
||||
$retention_days = $this->settings->get_retention_period();
|
||||
|
||||
if ( $deleted > 0 ) {
|
||||
$this->handle(
|
||||
|
||||
@@ -4,7 +4,7 @@ declare( strict_types = 1 );
|
||||
namespace Automattic\WooCommerce\Internal\Admin\Logging;
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\{ LogHandlerFileV2, Settings };
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\{ File, FileController, FileListTable, SearchListTable };
|
||||
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
|
||||
use WC_Admin_Status;
|
||||
@@ -26,6 +26,13 @@ class PageController {
|
||||
*/
|
||||
private $file_controller;
|
||||
|
||||
/**
|
||||
* Instance of Settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* Instance of FileListTable or SearchListTable.
|
||||
*
|
||||
@@ -39,13 +46,16 @@ class PageController {
|
||||
* @internal
|
||||
*
|
||||
* @param FileController $file_controller Instance of FileController.
|
||||
* @param Settings $settings Instance of Settings.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
final public function init(
|
||||
FileController $file_controller
|
||||
FileController $file_controller,
|
||||
Settings $settings
|
||||
): void {
|
||||
$this->file_controller = $file_controller;
|
||||
$this->settings = $settings;
|
||||
|
||||
$this->init_hooks();
|
||||
}
|
||||
@@ -56,8 +66,61 @@ class PageController {
|
||||
* @return void
|
||||
*/
|
||||
private function init_hooks(): void {
|
||||
self::add_action( 'load-woocommerce_page_wc-status', array( $this, 'setup_screen_options' ) );
|
||||
self::add_action( 'load-woocommerce_page_wc-status', array( $this, 'handle_list_table_bulk_actions' ) );
|
||||
self::add_action( 'load-woocommerce_page_wc-status', array( $this, 'maybe_do_logs_tab_action' ), 2 );
|
||||
|
||||
self::add_action( 'wc_logs_load_tab', array( $this, 'setup_screen_options' ) );
|
||||
self::add_action( 'wc_logs_load_tab', array( $this, 'handle_list_table_bulk_actions' ) );
|
||||
self::add_action( 'wc_logs_load_tab', array( $this, 'notices' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current tab on the Status page is Logs, and if so, fire an action.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function maybe_do_logs_tab_action(): void {
|
||||
$is_logs_tab = 'logs' === filter_input( INPUT_GET, 'tab' );
|
||||
|
||||
if ( $is_logs_tab ) {
|
||||
$params = $this->get_query_params( array( 'view' ) );
|
||||
|
||||
/**
|
||||
* Action fires when the Logs tab starts loading.
|
||||
*
|
||||
* @param string $view The current view within the Logs tab.
|
||||
*
|
||||
* @since 8.6.0
|
||||
*/
|
||||
do_action( 'wc_logs_load_tab', $params['view'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notices to display on Logs screens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function notices() {
|
||||
if ( ! $this->settings->logging_is_enabled() ) {
|
||||
add_action(
|
||||
'admin_notices',
|
||||
function() {
|
||||
?>
|
||||
<div class="notice notice-warning">
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
// translators: %s is a URL to another admin screen.
|
||||
wp_kses_post( __( 'Logging is disabled. It can be enabled in <a href="%s">Logs Settings</a>.', 'woocommerce' ) ),
|
||||
esc_url( add_query_arg( 'view', 'settings', $this->get_logs_tab_url() ) )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,40 +138,83 @@ class PageController {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the default log handler.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_default_handler(): string {
|
||||
$handler = Constants::get_constant( 'WC_LOG_HANDLER' );
|
||||
|
||||
if ( is_null( $handler ) || ! class_exists( $handler ) ) {
|
||||
$handler = WC_Log_Handler_File::class;
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the "Logs" tab, depending on the current default log handler.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render(): void {
|
||||
$handler = $this->get_default_handler();
|
||||
$handler = $this->settings->get_default_handler();
|
||||
$params = $this->get_query_params( array( 'view' ) );
|
||||
|
||||
$this->render_section_nav();
|
||||
|
||||
if ( 'settings' === $params['view'] ) {
|
||||
$this->settings->render_form();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( $handler ) {
|
||||
case LogHandlerFileV2::class:
|
||||
$this->render_filev2();
|
||||
break;
|
||||
case 'WC_Log_Handler_DB':
|
||||
return;
|
||||
case WC_Log_Handler_DB::class:
|
||||
WC_Admin_Status::status_logs_db();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
case WC_Log_Handler_File::class:
|
||||
WC_Admin_Status::status_logs_file();
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Action fires only if there is not a built-in rendering method for the current default log handler.
|
||||
*
|
||||
* This is intended as a way for extensions to render log views for custom handlers.
|
||||
*
|
||||
* @param string $handler
|
||||
*
|
||||
* @since 8.6.0
|
||||
*/
|
||||
do_action( 'wc_logs_render_page', $handler );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render navigation to switch between logs browsing and settings.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function render_section_nav(): void {
|
||||
$params = $this->get_query_params( array( 'view' ) );
|
||||
$browse_url = $this->get_logs_tab_url();
|
||||
$settings_url = add_query_arg( 'view', 'settings', $this->get_logs_tab_url() );
|
||||
|
||||
?>
|
||||
<ul class="subsubsub">
|
||||
<li>
|
||||
<?php
|
||||
printf(
|
||||
'<a href="%1$s"%2$s>%3$s</a>',
|
||||
esc_url( $browse_url ),
|
||||
'settings' !== $params['view'] ? ' class="current"' : '',
|
||||
esc_html__( 'Browse', 'woocommerce' )
|
||||
);
|
||||
?>
|
||||
|
|
||||
</li>
|
||||
<li>
|
||||
<?php
|
||||
printf(
|
||||
'<a href="%1$s"%2$s>%3$s</a>',
|
||||
esc_url( $settings_url ),
|
||||
'settings' === $params['view'] ? ' class="current"' : '',
|
||||
esc_html__( 'Settings', 'woocommerce' )
|
||||
);
|
||||
?>
|
||||
</li>
|
||||
</ul>
|
||||
<br class="clear">
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,6 +400,17 @@ class PageController {
|
||||
?>
|
||||
<?php endwhile; ?>
|
||||
</section>
|
||||
<script>
|
||||
// Clear the line number hash and highlight with a click.
|
||||
document.documentElement.addEventListener( 'click', ( event ) => {
|
||||
if ( window.location.hash && ! event.target.classList.contains( 'line-anchor' ) ) {
|
||||
let scrollPos = document.documentElement.scrollTop;
|
||||
window.location.hash = '';
|
||||
document.documentElement.scrollTop = scrollPos;
|
||||
history.replaceState( null, '', window.location.pathname + window.location.search );
|
||||
}
|
||||
} );
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
@@ -303,7 +420,7 @@ class PageController {
|
||||
* @return void
|
||||
*/
|
||||
private function render_search_results_view(): void {
|
||||
$params = $this->get_query_params( array( 'order', 'orderby', 'search', 'source', 'view' ) );
|
||||
$params = $this->get_query_params( array( 'view' ) );
|
||||
$list_table = $this->get_list_table( $params['view'] );
|
||||
|
||||
$list_table->prepare_items();
|
||||
@@ -380,7 +497,7 @@ class PageController {
|
||||
'view' => array(
|
||||
'filter' => FILTER_VALIDATE_REGEXP,
|
||||
'options' => array(
|
||||
'regexp' => '/^(list_files|single_file|search_results)$/',
|
||||
'regexp' => '/^(list_files|single_file|search_results|settings)$/',
|
||||
'default' => $defaults['view'],
|
||||
),
|
||||
),
|
||||
@@ -423,17 +540,18 @@ class PageController {
|
||||
/**
|
||||
* Register screen options for the logging views.
|
||||
*
|
||||
* @param string $view The current view within the Logs tab.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function setup_screen_options(): void {
|
||||
$params = $this->get_query_params( array( 'view' ) );
|
||||
$handler = $this->get_default_handler();
|
||||
private function setup_screen_options( string $view ): void {
|
||||
$handler = $this->settings->get_default_handler();
|
||||
$list_table = null;
|
||||
|
||||
switch ( $handler ) {
|
||||
case LogHandlerFileV2::class:
|
||||
if ( in_array( $params['view'], array( 'list_files', 'search_results' ), true ) ) {
|
||||
$list_table = $this->get_list_table( $params['view'] );
|
||||
if ( in_array( $view, array( 'list_files', 'search_results' ), true ) ) {
|
||||
$list_table = $this->get_list_table( $view );
|
||||
}
|
||||
break;
|
||||
case 'WC_Log_Handler_DB':
|
||||
@@ -458,22 +576,24 @@ class PageController {
|
||||
/**
|
||||
* Process bulk actions initiated from the log file list table.
|
||||
*
|
||||
* @param string $view The current view within the Logs tab.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function handle_list_table_bulk_actions(): void {
|
||||
private function handle_list_table_bulk_actions( string $view ): void {
|
||||
// Bail if we're not using the file handler.
|
||||
if ( LogHandlerFileV2::class !== $this->get_default_handler() ) {
|
||||
if ( LogHandlerFileV2::class !== $this->settings->get_default_handler() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$params = $this->get_query_params( array( 'file_id', 'view' ) );
|
||||
$params = $this->get_query_params( array( 'file_id' ) );
|
||||
|
||||
// Bail if this is not the list table view.
|
||||
if ( 'list_files' !== $params['view'] ) {
|
||||
if ( 'list_files' !== $view ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$action = $this->get_list_table( $params['view'] )->current_action();
|
||||
$action = $this->get_list_table( $view )->current_action();
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : $this->get_logs_tab_url();
|
||||
@@ -562,10 +682,9 @@ class PageController {
|
||||
* @return string
|
||||
*/
|
||||
private function format_line( string $line, int $line_number ): string {
|
||||
$severity_levels = WC_Log_Levels::get_all_severity_levels();
|
||||
$classes = array( 'line' );
|
||||
$classes = array( 'line' );
|
||||
|
||||
$line = esc_html( trim( $line ) );
|
||||
$line = esc_html( $line );
|
||||
if ( empty( $line ) ) {
|
||||
$line = ' ';
|
||||
}
|
||||
@@ -583,11 +702,11 @@ class PageController {
|
||||
$has_timestamp = true;
|
||||
}
|
||||
|
||||
if ( isset( $segments[1] ) && in_array( strtolower( $segments[1] ), $severity_levels, true ) ) {
|
||||
if ( isset( $segments[1] ) && WC_Log_Levels::is_valid_level( strtolower( $segments[1] ) ) ) {
|
||||
$segments[1] = sprintf(
|
||||
'<span class="%1$s">%2$s</span>',
|
||||
esc_attr( 'log-level log-level--' . strtolower( $segments[1] ) ),
|
||||
esc_html( $segments[1] )
|
||||
esc_html( WC_Log_Levels::get_level_label( strtolower( $segments[1] ) ) )
|
||||
);
|
||||
$has_level = true;
|
||||
}
|
||||
@@ -600,7 +719,7 @@ class PageController {
|
||||
$context = json_decode( $maybe_json, false, 512, JSON_THROW_ON_ERROR );
|
||||
|
||||
$message_chunks[1] = sprintf(
|
||||
'<details><summary>%1$s</summary><pre>%2$s</pre></details>',
|
||||
'<details><summary>%1$s</summary>%2$s</details>',
|
||||
esc_html__( 'Additional context', 'woocommerce' ),
|
||||
wp_json_encode( $context, JSON_PRETTY_PRINT )
|
||||
);
|
||||
|
||||
@@ -0,0 +1,449 @@
|
||||
<?php
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\Logging;
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\LogHandlerFileV2;
|
||||
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
|
||||
use WC_Admin_Settings;
|
||||
use WC_Log_Handler, WC_Log_Handler_DB, WC_Log_Handler_File, WC_Log_Levels;
|
||||
|
||||
/**
|
||||
* Settings class.
|
||||
*/
|
||||
class Settings {
|
||||
|
||||
use AccessiblePrivateMethods;
|
||||
|
||||
/**
|
||||
* Default values for logging settings.
|
||||
*
|
||||
* @const array
|
||||
*/
|
||||
private const DEFAULTS = array(
|
||||
'logging_enabled' => true,
|
||||
'default_handler' => LogHandlerFileV2::class,
|
||||
'retention_period_days' => 30,
|
||||
'level_threshold' => 'none',
|
||||
'file_entry_collapse_lines' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* The prefix for settings keys used in the options table.
|
||||
*
|
||||
* @const string
|
||||
*/
|
||||
private const PREFIX = 'woocommerce_logs_';
|
||||
|
||||
/**
|
||||
* Class Settings.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::add_action( 'wc_logs_load_tab', array( $this, 'save_settings' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* The definitions used by WC_Admin_Settings to render and save settings controls.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_settings_definitions(): array {
|
||||
$settings = array(
|
||||
'start' => array(
|
||||
'title' => __( 'Logs settings', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'title',
|
||||
),
|
||||
'logging_enabled' => array(
|
||||
'title' => __( 'Logger', 'woocommerce' ),
|
||||
'desc' => __( 'Enable logging', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'logging_enabled',
|
||||
'type' => 'checkbox',
|
||||
'value' => $this->logging_is_enabled() ? 'yes' : 'no',
|
||||
'default' => self::DEFAULTS['logging_enabled'] ? 'yes' : 'no',
|
||||
'autoload' => false,
|
||||
),
|
||||
'default_handler' => array(),
|
||||
'retention_period_days' => array(),
|
||||
'level_threshold' => array(),
|
||||
'end' => array(
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'sectionend',
|
||||
),
|
||||
);
|
||||
|
||||
if ( true === $this->logging_is_enabled() ) {
|
||||
$settings['default_handler'] = $this->get_default_handler_setting_definition();
|
||||
$settings['retention_period_days'] = $this->get_retention_period_days_setting_definition();
|
||||
$settings['level_threshold'] = $this->get_level_threshold_setting_definition();
|
||||
}
|
||||
|
||||
$default_handler = $this->get_default_handler();
|
||||
if ( in_array( $default_handler, array( LogHandlerFileV2::class, WC_Log_Handler_File::class ), true ) ) {
|
||||
$settings += $this->get_filesystem_settings_definitions();
|
||||
} elseif ( WC_Log_Handler_DB::class === $default_handler ) {
|
||||
$settings += $this->get_database_settings_definitions();
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* The definition for the default_handler setting.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_default_handler_setting_definition(): array {
|
||||
$handler_options = array(
|
||||
LogHandlerFileV2::class => __( 'File system (default)', 'woocommerce' ),
|
||||
WC_Log_Handler_DB::class => __( 'Database (not recommended on live sites)', 'woocommerce' ),
|
||||
);
|
||||
|
||||
/**
|
||||
* Filter the list of logging handlers that can be set as the default handler.
|
||||
*
|
||||
* @param array $handler_options An associative array of class_name => description.
|
||||
*
|
||||
* @since 8.6.0
|
||||
*/
|
||||
$handler_options = apply_filters( 'woocommerce_logger_handler_options', $handler_options );
|
||||
|
||||
$current_value = $this->get_default_handler();
|
||||
if ( ! array_key_exists( $current_value, $handler_options ) ) {
|
||||
$handler_options[ $current_value ] = $current_value;
|
||||
}
|
||||
|
||||
$desc = array();
|
||||
|
||||
$desc[] = __( 'Note that if this setting is changed, any log entries that have already been recorded will remain stored in their current location, but will not migrate.', 'woocommerce' );
|
||||
|
||||
$hardcoded = ! is_null( Constants::get_constant( 'WC_LOG_HANDLER' ) );
|
||||
if ( $hardcoded ) {
|
||||
$desc[] = sprintf(
|
||||
// translators: %s is the name of a code variable.
|
||||
__( 'This setting cannot be changed here because it is defined in the %s constant.', 'woocommerce' ),
|
||||
'<code>WC_LOG_HANDLER</code>'
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => __( 'Log storage', 'woocommerce' ),
|
||||
'desc_tip' => __( 'This determines where log entries are saved.', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'default_handler',
|
||||
'type' => 'radio',
|
||||
'value' => $current_value,
|
||||
'default' => self::DEFAULTS['default_handler'],
|
||||
'autoload' => false,
|
||||
'options' => $handler_options,
|
||||
'disabled' => $hardcoded ? array_keys( $handler_options ) : array(),
|
||||
'desc' => implode( '<br><br>', $desc ),
|
||||
'desc_at_end' => true,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The definition for the retention_period_days setting.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_retention_period_days_setting_definition(): array {
|
||||
$custom_attributes = array(
|
||||
'min' => 1,
|
||||
'step' => 1,
|
||||
);
|
||||
|
||||
$hardcoded = has_filter( 'woocommerce_logger_days_to_retain_logs' );
|
||||
$desc = '';
|
||||
if ( $hardcoded ) {
|
||||
$custom_attributes['disabled'] = 'true';
|
||||
|
||||
$desc = sprintf(
|
||||
// translators: %s is the name of a filter hook.
|
||||
__( 'This setting cannot be changed here because it is being set by a filter on the %s hook.', 'woocommerce' ),
|
||||
'<code>woocommerce_logger_days_to_retain_logs</code>'
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => __( 'Retention period', 'woocommerce' ),
|
||||
'desc_tip' => __( 'This sets how many days log entries will be kept before being auto-deleted.', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'retention_period_days',
|
||||
'type' => 'number',
|
||||
'value' => $this->get_retention_period(),
|
||||
'default' => self::DEFAULTS['retention_period_days'],
|
||||
'autoload' => false,
|
||||
'custom_attributes' => $custom_attributes,
|
||||
'css' => 'width:70px;',
|
||||
'row_class' => 'logs-retention-period-days',
|
||||
'suffix' => sprintf(
|
||||
' %s',
|
||||
__( 'days', 'woocommerce' ),
|
||||
),
|
||||
'desc' => $desc,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The definition for the level_threshold setting.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_level_threshold_setting_definition(): array {
|
||||
$hardcoded = ! is_null( Constants::get_constant( 'WC_LOG_THRESHOLD' ) );
|
||||
$desc = '';
|
||||
if ( $hardcoded ) {
|
||||
$desc = sprintf(
|
||||
// translators: %1$s is the name of a code variable. %2$s is the name of a file.
|
||||
__( 'This setting cannot be changed here because it is defined in the %1$s constant, probably in your %2$s file.', 'woocommerce' ),
|
||||
'<code>WC_LOG_THRESHOLD</code>',
|
||||
'<b>wp-config.php</b>'
|
||||
);
|
||||
}
|
||||
|
||||
$labels = WC_Log_Levels::get_all_level_labels();
|
||||
$labels['none'] = __( 'None', 'woocommerce' );
|
||||
|
||||
$custom_attributes = array();
|
||||
if ( $hardcoded ) {
|
||||
$custom_attributes['disabled'] = 'true';
|
||||
}
|
||||
|
||||
return array(
|
||||
'title' => __( 'Level threshold', 'woocommerce' ),
|
||||
'desc_tip' => __( 'This sets the minimum severity level of logs that will be stored. Lower severity levels will be ignored. "None" means all logs will be stored.', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'level_threshold',
|
||||
'type' => 'select',
|
||||
'value' => $this->get_level_threshold(),
|
||||
'default' => self::DEFAULTS['level_threshold'],
|
||||
'autoload' => false,
|
||||
'options' => $labels,
|
||||
'custom_attributes' => $custom_attributes,
|
||||
'css' => 'width:auto;',
|
||||
'desc' => $desc,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The definitions used by WC_Admin_Settings to render settings related to filesystem log handlers.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_filesystem_settings_definitions(): array {
|
||||
$location_info = array();
|
||||
$directory = trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) );
|
||||
|
||||
$location_info[] = sprintf(
|
||||
// translators: %s is a location in the filesystem.
|
||||
__( 'Log files are stored in this directory: %s', 'woocommerce' ),
|
||||
sprintf(
|
||||
'<code>%s</code>',
|
||||
esc_html( $directory )
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! wp_is_writable( $directory ) ) {
|
||||
$location_info[] = __( '⚠️ This directory does not appear to be writable.', 'woocommerce' );
|
||||
}
|
||||
|
||||
$location_info[] = sprintf(
|
||||
// translators: %1$s is a code variable. %2$s is the name of a file.
|
||||
__( 'Change the location by defining the %1$s constant in your %2$s file with a new path.', 'woocommerce' ),
|
||||
'<code>WC_LOG_DIR</code>',
|
||||
'<code>wp-config.php</code>'
|
||||
);
|
||||
|
||||
return array(
|
||||
'file_start' => array(
|
||||
'title' => __( 'File system settings', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'title',
|
||||
),
|
||||
'log_directory' => array(
|
||||
'type' => 'info',
|
||||
'text' => implode( "\n\n", $location_info ),
|
||||
),
|
||||
'entry_format' => array(),
|
||||
'file_end' => array(
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'sectionend',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The definitions used by WC_Admin_Settings to render settings related to database log handlers.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_database_settings_definitions(): array {
|
||||
global $wpdb;
|
||||
$table = "{$wpdb->prefix}woocommerce_log";
|
||||
|
||||
$location_info = sprintf(
|
||||
// translators: %s is a location in the filesystem.
|
||||
__( 'Log entries are stored in this database table: %s', 'woocommerce' ),
|
||||
"<code>$table</code>"
|
||||
);
|
||||
|
||||
return array(
|
||||
'file_start' => array(
|
||||
'title' => __( 'Database settings', 'woocommerce' ),
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'title',
|
||||
),
|
||||
'database_table' => array(
|
||||
'type' => 'info',
|
||||
'text' => $location_info,
|
||||
),
|
||||
'file_end' => array(
|
||||
'id' => self::PREFIX . 'settings',
|
||||
'type' => 'sectionend',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the submission of the settings form and update the settings values.
|
||||
*
|
||||
* @param string $view The current view within the Logs tab.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function save_settings( string $view ): void {
|
||||
$is_saving = 'settings' === $view && isset( $_POST['save_settings'] );
|
||||
|
||||
if ( $is_saving ) {
|
||||
check_admin_referer( self::PREFIX . 'settings' );
|
||||
|
||||
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
wp_die( esc_html__( 'You do not have permission to manage logging settings.', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
$settings = $this->get_settings_definitions();
|
||||
|
||||
WC_Admin_Settings::save_fields( $settings );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the settings page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render_form(): void {
|
||||
$settings = $this->get_settings_definitions();
|
||||
|
||||
?>
|
||||
<form id="mainform" class="wc-logs-settings" method="post">
|
||||
<?php WC_Admin_Settings::output_fields( $settings ); ?>
|
||||
<?php
|
||||
/**
|
||||
* Action fires after the built-in logging settings controls have been rendered.
|
||||
*
|
||||
* This is intended as a way to allow other logging settings controls to be added by extensions.
|
||||
*
|
||||
* @param bool $enabled True if logging is currently enabled.
|
||||
*
|
||||
* @since 8.6.0
|
||||
*/
|
||||
do_action( 'wc_logs_settings_form_fields', $this->logging_is_enabled() );
|
||||
?>
|
||||
<?php wp_nonce_field( self::PREFIX . 'settings' ); ?>
|
||||
<?php submit_button( __( 'Save changes', 'woocommerce' ), 'primary', 'save_settings' ); ?>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the logging_enabled setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function logging_is_enabled(): bool {
|
||||
$key = self::PREFIX . 'logging_enabled';
|
||||
|
||||
$enabled = WC_Admin_Settings::get_option( $key, self::DEFAULTS['logging_enabled'] );
|
||||
$enabled = filter_var( $enabled, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE );
|
||||
|
||||
if ( is_null( $enabled ) ) {
|
||||
$enabled = self::DEFAULTS['logging_enabled'];
|
||||
}
|
||||
|
||||
return $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the default_handler setting.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_default_handler(): string {
|
||||
$key = self::PREFIX . 'default_handler';
|
||||
|
||||
$handler = Constants::get_constant( 'WC_LOG_HANDLER' );
|
||||
|
||||
if ( is_null( $handler ) ) {
|
||||
$handler = WC_Admin_Settings::get_option( $key );
|
||||
}
|
||||
|
||||
if ( ! class_exists( $handler ) || ! is_a( $handler, 'WC_Log_Handler_Interface', true ) ) {
|
||||
$handler = self::DEFAULTS['default_handler'];
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the retention_period_days setting.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_retention_period(): int {
|
||||
$key = self::PREFIX . 'retention_period_days';
|
||||
|
||||
$retention_period = self::DEFAULTS['retention_period_days'];
|
||||
|
||||
if ( has_filter( 'woocommerce_logger_days_to_retain_logs' ) ) {
|
||||
/**
|
||||
* Filter the retention period of log entries.
|
||||
*
|
||||
* @param int $days The number of days to retain log entries.
|
||||
*
|
||||
* @since 3.4.0
|
||||
*/
|
||||
$retention_period = apply_filters( 'woocommerce_logger_days_to_retain_logs', $retention_period );
|
||||
} else {
|
||||
$retention_period = WC_Admin_Settings::get_option( $key );
|
||||
}
|
||||
|
||||
$retention_period = absint( $retention_period );
|
||||
|
||||
if ( $retention_period < 1 ) {
|
||||
$retention_period = self::DEFAULTS['retention_period_days'];
|
||||
}
|
||||
|
||||
return $retention_period;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the level_threshold setting.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_level_threshold(): string {
|
||||
$key = self::PREFIX . 'level_threshold';
|
||||
|
||||
$threshold = Constants::get_constant( 'WC_LOG_THRESHOLD' );
|
||||
|
||||
if ( is_null( $threshold ) ) {
|
||||
$threshold = WC_Admin_Settings::get_option( $key );
|
||||
}
|
||||
|
||||
if ( ! WC_Log_Levels::is_valid_level( $threshold ) ) {
|
||||
$threshold = self::DEFAULTS['level_threshold'];
|
||||
}
|
||||
|
||||
return $threshold;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,20 @@ class Marketing {
|
||||
|
||||
use CouponsMovedTrait;
|
||||
|
||||
/**
|
||||
* Constant representing the key for the submenu name value in the global $submenu array.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const SUBMENU_NAME_KEY = 0;
|
||||
|
||||
/**
|
||||
* Constant representing the key for the submenu location value in the global $submenu array.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const SUBMENU_LOCATION_KEY = 2;
|
||||
|
||||
/**
|
||||
* Class instance.
|
||||
*
|
||||
@@ -44,6 +58,9 @@ class Marketing {
|
||||
add_action( 'admin_menu', array( $this, 'register_pages' ), 5 );
|
||||
add_action( 'admin_menu', array( $this, 'add_parent_menu_item' ), 6 );
|
||||
|
||||
// Overwrite submenu default ordering for marketing menu. High priority gives plugins the chance to register their own menu items.
|
||||
add_action( 'admin_menu', array( $this, 'reorder_marketing_submenu' ), 99 );
|
||||
|
||||
add_filter( 'woocommerce_admin_shared_settings', array( $this, 'component_settings' ), 30 );
|
||||
}
|
||||
|
||||
@@ -140,6 +157,67 @@ class Marketing {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Order marketing menu items alphabeticaly.
|
||||
* Overview should be first, and Coupons should be second, followed by other marketing menu items.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reorder_marketing_submenu() {
|
||||
global $submenu;
|
||||
|
||||
if ( ! isset( $submenu['woocommerce-marketing'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$marketing_submenu = $submenu['woocommerce-marketing'];
|
||||
$new_menu_order = array();
|
||||
|
||||
// Overview should be first.
|
||||
$overview_key = array_search( 'Overview', array_column( $marketing_submenu, self::SUBMENU_NAME_KEY ), true );
|
||||
|
||||
if ( false === $overview_key ) {
|
||||
/*
|
||||
* If Overview is not found we may be on a site witha different language.
|
||||
* We can use a fallback and try to find the overview page by its path.
|
||||
*/
|
||||
$overview_key = array_search( 'admin.php?page=wc-admin&path=/marketing', array_column( $marketing_submenu, self::SUBMENU_LOCATION_KEY ), true );
|
||||
}
|
||||
|
||||
if ( false !== $overview_key ) {
|
||||
$new_menu_order[] = $marketing_submenu[ $overview_key ];
|
||||
array_splice( $marketing_submenu, $overview_key, 1 );
|
||||
}
|
||||
|
||||
// Coupons should be second.
|
||||
$coupons_key = array_search( 'Coupons', array_column( $marketing_submenu, self::SUBMENU_NAME_KEY ), true );
|
||||
|
||||
if ( false === $coupons_key ) {
|
||||
/*
|
||||
* If Coupons is not found we may be on a site witha different language.
|
||||
* We can use a fallback and try to find the coupons page by its path.
|
||||
*/
|
||||
$coupons_key = array_search( 'edit.php?post_type=shop_coupon', array_column( $marketing_submenu, self::SUBMENU_LOCATION_KEY ), true );
|
||||
}
|
||||
|
||||
if ( false !== $coupons_key ) {
|
||||
$new_menu_order[] = $marketing_submenu[ $coupons_key ];
|
||||
array_splice( $marketing_submenu, $coupons_key, 1 );
|
||||
}
|
||||
|
||||
// Sort the rest of the items alphabetically.
|
||||
usort(
|
||||
$marketing_submenu,
|
||||
function( $a, $b ) {
|
||||
return strcmp( $a[0], $b[0] );
|
||||
}
|
||||
);
|
||||
|
||||
$new_menu_order = array_merge( $new_menu_order, $marketing_submenu );
|
||||
|
||||
$submenu['woocommerce-marketing'] = $new_menu_order; //phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
||||
}
|
||||
|
||||
/**
|
||||
* Add settings for marketing feature.
|
||||
*
|
||||
|
||||
@@ -14,13 +14,6 @@ namespace Automattic\WooCommerce\Internal\Admin\Marketing;
|
||||
* @since x.x.x
|
||||
*/
|
||||
class MarketingSpecs {
|
||||
/**
|
||||
* Name of recommended plugins transient.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const RECOMMENDED_PLUGINS_TRANSIENT = 'wc_marketing_recommended_plugins';
|
||||
|
||||
/**
|
||||
* Name of knowledge base post transient.
|
||||
*
|
||||
@@ -28,111 +21,6 @@ class MarketingSpecs {
|
||||
*/
|
||||
const KNOWLEDGE_BASE_TRANSIENT = 'wc_marketing_knowledge_base';
|
||||
|
||||
/**
|
||||
* Slug of the category specifying marketing extensions on the Woo.com store.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const MARKETING_EXTENSION_CATEGORY_SLUG = 'marketing';
|
||||
|
||||
/**
|
||||
* Slug of the subcategory specifying marketing channels on the Woo.com store.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const MARKETING_CHANNEL_SUBCATEGORY_SLUG = 'sales-channels';
|
||||
|
||||
/**
|
||||
* Load recommended plugins from Woo.com
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_recommended_plugins(): array {
|
||||
$plugins = get_transient( self::RECOMMENDED_PLUGINS_TRANSIENT );
|
||||
|
||||
if ( false === $plugins ) {
|
||||
$request = wp_remote_get(
|
||||
'https://woocommerce.com/wp-json/wccom/marketing-tab/1.3/recommendations.json',
|
||||
array(
|
||||
'user-agent' => 'WooCommerce/' . WC()->version . '; ' . get_bloginfo( 'url' ),
|
||||
)
|
||||
);
|
||||
$plugins = [];
|
||||
|
||||
if ( ! is_wp_error( $request ) && 200 === $request['response']['code'] ) {
|
||||
$plugins = json_decode( $request['body'], true );
|
||||
}
|
||||
|
||||
set_transient(
|
||||
self::RECOMMENDED_PLUGINS_TRANSIENT,
|
||||
$plugins,
|
||||
// Expire transient in 15 minutes if remote get failed.
|
||||
// Cache an empty result to avoid repeated failed requests.
|
||||
empty( $plugins ) ? 900 : 3 * DAY_IN_SECONDS
|
||||
);
|
||||
}
|
||||
|
||||
return array_values( $plugins );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only the recommended marketing channels from Woo.com.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_recommended_marketing_channels(): array {
|
||||
return array_filter( $this->get_recommended_plugins(), [ $this, 'is_marketing_channel_plugin' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all recommended marketing extensions EXCEPT the marketing channels from Woo.com.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_recommended_marketing_extensions_excluding_channels(): array {
|
||||
return array_filter(
|
||||
$this->get_recommended_plugins(),
|
||||
function ( array $plugin_data ) {
|
||||
return $this->is_marketing_plugin( $plugin_data ) && ! $this->is_marketing_channel_plugin( $plugin_data );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a plugin is a marketing extension.
|
||||
*
|
||||
* @param array $plugin_data The plugin properties returned by the API.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_marketing_plugin( array $plugin_data ): bool {
|
||||
$categories = $plugin_data['categories'] ?? [];
|
||||
|
||||
return in_array( self::MARKETING_EXTENSION_CATEGORY_SLUG, $categories, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a plugin is a marketing channel.
|
||||
*
|
||||
* @param array $plugin_data The plugin properties returned by the API.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_marketing_channel_plugin( array $plugin_data ): bool {
|
||||
if ( ! $this->is_marketing_plugin( $plugin_data ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$subcategories = $plugin_data['subcategories'] ?? [];
|
||||
foreach ( $subcategories as $subcategory ) {
|
||||
if ( isset( $subcategory['slug'] ) && self::MARKETING_CHANNEL_SUBCATEGORY_SLUG === $subcategory['slug'] ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load knowledge base posts from Woo.com
|
||||
*
|
||||
@@ -165,21 +53,21 @@ class MarketingSpecs {
|
||||
'user-agent' => 'WooCommerce/' . WC()->version . '; ' . get_bloginfo( 'url' ),
|
||||
)
|
||||
);
|
||||
$posts = [];
|
||||
$posts = array();
|
||||
|
||||
if ( ! is_wp_error( $request ) && 200 === $request['response']['code'] ) {
|
||||
$raw_posts = json_decode( $request['body'], true );
|
||||
|
||||
foreach ( $raw_posts as $raw_post ) {
|
||||
$post = [
|
||||
$post = array(
|
||||
'title' => html_entity_decode( $raw_post['title']['rendered'] ),
|
||||
'date' => $raw_post['date_gmt'],
|
||||
'link' => $raw_post['link'],
|
||||
'author_name' => isset( $raw_post['author_name'] ) ? html_entity_decode( $raw_post['author_name'] ) : '',
|
||||
'author_avatar' => isset( $raw_post['author_avatar_url'] ) ? $raw_post['author_avatar_url'] : '',
|
||||
];
|
||||
);
|
||||
|
||||
$featured_media = $raw_post['_embedded']['wp:featuredmedia'] ?? [];
|
||||
$featured_media = isset( $raw_post['_embedded']['wp:featuredmedia'] ) && is_array( $raw_post['_embedded']['wp:featuredmedia'] ) ? $raw_post['_embedded']['wp:featuredmedia'] : array();
|
||||
if ( count( $featured_media ) > 0 ) {
|
||||
$image = current( $featured_media );
|
||||
$post['image'] = add_query_arg(
|
||||
|
||||
@@ -10,6 +10,7 @@ use Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes\CustomMetaBox;
|
||||
use Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes\OrderAttribution;
|
||||
use Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes\TaxonomiesMetaBox;
|
||||
use Automattic\WooCommerce\Internal\Features\FeaturesController;
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
use WC_Order;
|
||||
|
||||
/**
|
||||
@@ -250,6 +251,15 @@ class Edit {
|
||||
'high'
|
||||
);
|
||||
|
||||
// Add customer history meta box if analytics is enabled.
|
||||
if ( 'yes' !== get_option( 'woocommerce_analytics_enabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! OrderUtil::is_order_edit_screen() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer history meta box.
|
||||
*
|
||||
@@ -260,7 +270,7 @@ class Edit {
|
||||
add_meta_box(
|
||||
'woocommerce-customer-history',
|
||||
__( 'Customer history', 'woocommerce' ),
|
||||
function( $post_or_order ) use ( $customer_history_meta_box ) {
|
||||
function ( $post_or_order ) use ( $customer_history_meta_box ) {
|
||||
$order = $post_or_order instanceof WC_Order ? $post_or_order : wc_get_order( $post_or_order );
|
||||
if ( $order instanceof WC_Order ) {
|
||||
$customer_history_meta_box->output( $order );
|
||||
|
||||
@@ -372,7 +372,7 @@ class ListTable extends WP_List_Table {
|
||||
'type' => $this->order_type,
|
||||
);
|
||||
|
||||
foreach ( array( 'status', 's', 'm', '_customer_user' ) as $query_var ) {
|
||||
foreach ( array( 'status', 's', 'm', '_customer_user', 'search-filter' ) as $query_var ) {
|
||||
$this->request[ $query_var ] = sanitize_text_field( wp_unslash( $_REQUEST[ $query_var ] ?? '' ) );
|
||||
}
|
||||
|
||||
@@ -532,6 +532,11 @@ class ListTable extends WP_List_Table {
|
||||
$this->order_query_args['s'] = $search_term;
|
||||
$this->has_filter = true;
|
||||
}
|
||||
|
||||
$filter = trim( sanitize_text_field( $this->request['search-filter'] ) );
|
||||
if ( ! empty( $filter ) ) {
|
||||
$this->order_query_args['search_filter'] = $filter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -541,8 +546,22 @@ class ListTable extends WP_List_Table {
|
||||
* @return array
|
||||
*/
|
||||
public function get_views() {
|
||||
$view_links = array();
|
||||
|
||||
/**
|
||||
* Filters the list of available list table view links before the actual query runs.
|
||||
* This can be used to, e.g., remove counts from the links.
|
||||
*
|
||||
* @since 8.6.0
|
||||
*
|
||||
* @param string[] $views An array of available list table view links.
|
||||
*/
|
||||
$view_links = apply_filters( 'woocommerce_before_' . $this->order_type . '_list_table_view_links', $view_links );
|
||||
if ( ! empty( $view_links ) ) {
|
||||
return $view_links;
|
||||
}
|
||||
|
||||
$view_counts = array();
|
||||
$view_links = array();
|
||||
$statuses = $this->get_visible_statuses();
|
||||
$current = ! empty( $this->request['status'] ) ? sanitize_text_field( $this->request['status'] ) : 'all';
|
||||
$all_count = 0;
|
||||
@@ -620,6 +639,24 @@ class ListTable extends WP_List_Table {
|
||||
* @return boolean TRUE when the blank state should be rendered, FALSE otherwise.
|
||||
*/
|
||||
private function should_render_blank_state(): bool {
|
||||
/**
|
||||
* Whether we should render a blank state so that custom count queries can be used.
|
||||
*
|
||||
* @since 8.6.0
|
||||
*
|
||||
* @param null $should_render_blank_state `null` will use the built-in counts. Sending a boolean will short-circuit that path.
|
||||
* @param object ListTable The current instance of the class.
|
||||
*/
|
||||
$should_render_blank_state = apply_filters(
|
||||
'woocommerce_' . $this->order_type . '_list_table_should_render_blank_state',
|
||||
null,
|
||||
$this
|
||||
);
|
||||
|
||||
if ( is_bool( $should_render_blank_state ) ) {
|
||||
return $should_render_blank_state;
|
||||
}
|
||||
|
||||
return ( ! $this->has_filter ) && 0 === $this->count_orders_by_status( array_keys( $this->get_visible_statuses() ) );
|
||||
}
|
||||
|
||||
@@ -719,11 +756,22 @@ class ListTable extends WP_List_Table {
|
||||
private function months_filter() {
|
||||
// XXX: [review] we may prefer to move this logic outside of the ListTable class.
|
||||
|
||||
/**
|
||||
* Filters whether to remove the 'Months' drop-down from the order list table.
|
||||
*
|
||||
* @since 8.6.0
|
||||
*
|
||||
* @param bool $disable Whether to disable the drop-down. Default false.
|
||||
*/
|
||||
if ( apply_filters( 'woocommerce_' . $this->order_type . '_list_table_disable_months_filter', false ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wp_locale;
|
||||
global $wpdb;
|
||||
|
||||
$orders_table = esc_sql( OrdersTableDataStore::get_orders_table_name() );
|
||||
$utc_offset = wc_timezone_offset();
|
||||
$utc_offset = wc_timezone_offset();
|
||||
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$order_dates = $wpdb->get_results(
|
||||
@@ -1347,7 +1395,7 @@ class ListTable extends WP_List_Table {
|
||||
* @return int Number of orders that were trashed.
|
||||
*/
|
||||
private function do_delete( array $ids, bool $force_delete = false ): int {
|
||||
$changed = 0;
|
||||
$changed = 0;
|
||||
|
||||
foreach ( $ids as $id ) {
|
||||
$order = wc_get_order( $id );
|
||||
@@ -1537,4 +1585,55 @@ class ListTable extends WP_List_Table {
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the search box with various options to limit order search results.
|
||||
*
|
||||
* @param string $text The search button text.
|
||||
* @param string $input_id The search input ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function search_box( $text, $input_id ) {
|
||||
if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$input_id = $input_id . '-search-input';
|
||||
|
||||
if ( ! empty( $_REQUEST['orderby'] ) ) {
|
||||
echo '<input type="hidden" name="orderby" value="' . esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ) ) . '" />';
|
||||
}
|
||||
if ( ! empty( $_REQUEST['order'] ) ) {
|
||||
echo '<input type="hidden" name="order" value="' . esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) ) . '" />';
|
||||
}
|
||||
?>
|
||||
<p class="search-box">
|
||||
<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_html( $text ); ?>:</label>
|
||||
<input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
|
||||
<?php $this->search_filter(); ?>
|
||||
<?php submit_button( $text, '', '', false, array( 'id' => 'search-submit' ) ); ?>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the search filter dropdown.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function search_filter() {
|
||||
$options = array(
|
||||
'order_id' => __( 'Order ID', 'woocommerce' ),
|
||||
'customer_email' => __( 'Customer Email', 'woocommerce' ),
|
||||
'customers' => __( 'Customers', 'woocommerce' ),
|
||||
'products' => __( 'Products', 'woocommerce' ),
|
||||
'all' => __( 'All', 'woocommerce' ),
|
||||
);
|
||||
?>
|
||||
<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>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\Orders\MetaBoxes;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Traits\OrderAttributionMeta;
|
||||
use Automattic\WooCommerce\Admin\API\Reports\Customers\Query as CustomersQuery;
|
||||
use WC_Order;
|
||||
|
||||
/**
|
||||
@@ -12,8 +12,6 @@ use WC_Order;
|
||||
*/
|
||||
class CustomerHistory {
|
||||
|
||||
use OrderAttributionMeta;
|
||||
|
||||
/**
|
||||
* Output the customer history template for the order.
|
||||
*
|
||||
@@ -22,34 +20,47 @@ class CustomerHistory {
|
||||
* @return void
|
||||
*/
|
||||
public function output( WC_Order $order ): void {
|
||||
$this->display_customer_history( $order->get_customer_id(), $order->get_billing_email() );
|
||||
}
|
||||
// No history when adding a new order.
|
||||
if ( 'auto-draft' === $order->get_status() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the customer history template for the customer.
|
||||
*
|
||||
* @param int $customer_id The customer ID.
|
||||
* @param string $billing_email The customer billing email.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function display_customer_history( int $customer_id, string $billing_email ): void {
|
||||
$has_customer_id = false;
|
||||
if ( $customer_id ) {
|
||||
$has_customer_id = true;
|
||||
$args = $this->get_customer_history( $customer_id );
|
||||
} elseif ( $billing_email ) {
|
||||
$args = $this->get_customer_history( $billing_email );
|
||||
} else {
|
||||
$args = array(
|
||||
'order_count' => 0,
|
||||
'total_spent' => 0,
|
||||
'average_spent' => 0,
|
||||
$customer_history = null;
|
||||
|
||||
if ( method_exists( $order, 'get_report_customer_id' ) ) {
|
||||
$customer_history = $this->get_customer_history( $order->get_report_customer_id() );
|
||||
}
|
||||
|
||||
if ( ! $customer_history ) {
|
||||
$customer_history = array(
|
||||
'orders_count' => 0,
|
||||
'total_spend' => 0,
|
||||
'avg_order_value' => 0,
|
||||
);
|
||||
}
|
||||
|
||||
$args['has_customer_id'] = $has_customer_id;
|
||||
wc_get_template( 'order/customer-history.php', $args );
|
||||
wc_get_template( 'order/customer-history.php', $customer_history );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order history for the customer (data matches Customers report).
|
||||
*
|
||||
* @param int $customer_report_id The reports customer ID (not necessarily User ID).
|
||||
*
|
||||
* @return array|null Order count, total spend, and average spend per order.
|
||||
*/
|
||||
private function get_customer_history( $customer_report_id ): ?array {
|
||||
|
||||
$args = array(
|
||||
'customers' => array( $customer_report_id ),
|
||||
// If unset, these params have default values that affect the results.
|
||||
'order_after' => null,
|
||||
'order_before' => null,
|
||||
);
|
||||
|
||||
$customers_query = new CustomersQuery( $args );
|
||||
$customer_data = $customers_query->get_data();
|
||||
return $customer_data->data[0] ?? null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -79,6 +79,6 @@ class OrderAttribution {
|
||||
// Only show more details toggle if there is more than just the origin.
|
||||
'has_more_details' => array( 'origin' ) !== array_keys( $meta ),
|
||||
);
|
||||
wc_get_template( 'order/attribution-data-fields.php', $template_data );
|
||||
wc_get_template( 'order/attribution-details.php', $template_data );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ abstract class Component {
|
||||
*/
|
||||
public static function get_argument_from_path( $arguments, $path, $delimiter = '.' ) {
|
||||
$path_keys = explode( $delimiter, $path );
|
||||
$num_keys = count( $path_keys );
|
||||
$num_keys = false !== $path_keys ? count( $path_keys ) : 0;
|
||||
|
||||
$val = $arguments;
|
||||
for ( $i = 0; $i < $num_keys; $i++ ) {
|
||||
|
||||
@@ -64,7 +64,25 @@ class MailchimpScheduler {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = $this->make_request( $profile_data['store_email'] );
|
||||
$country_code = WC()->countries->get_base_country();
|
||||
$country_name = WC()->countries->countries[ $country_code ] ?? 'N/A';
|
||||
|
||||
$state = WC()->countries->get_base_state();
|
||||
$state_name = WC()->countries->states[ $country_code ][ $state ] ?? 'N/A';
|
||||
|
||||
$address = array(
|
||||
// Setting N/A for addr1, city, state, zipcode and country as they are
|
||||
// required fields. Setting '' doesn't work.
|
||||
'addr1' => 'N/A',
|
||||
'addr2' => '',
|
||||
'city' => 'N/A',
|
||||
'state' => $state_name,
|
||||
'zip' => 'N/A',
|
||||
'country' => $country_name,
|
||||
);
|
||||
|
||||
$response = $this->make_request( $profile_data['store_email'], $address );
|
||||
|
||||
if ( is_wp_error( $response ) || ! isset( $response['body'] ) ) {
|
||||
$this->handle_request_error();
|
||||
return false;
|
||||
@@ -85,10 +103,11 @@ class MailchimpScheduler {
|
||||
*
|
||||
* @internal
|
||||
* @param string $store_email Email address to subscribe.
|
||||
* @param array $address Store address.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function make_request( $store_email ) {
|
||||
public function make_request( $store_email, $address ) {
|
||||
if ( true === defined( 'WP_ENVIRONMENT_TYPE' ) && 'development' === constant( 'WP_ENVIRONMENT_TYPE' ) ) {
|
||||
$subscribe_endpoint = self::SUBSCRIBE_ENDPOINT_DEV;
|
||||
} else {
|
||||
@@ -101,7 +120,8 @@ class MailchimpScheduler {
|
||||
'user-agent' => 'WooCommerce/' . WC()->version . '; ' . get_bloginfo( 'url' ),
|
||||
'method' => 'POST',
|
||||
'body' => array(
|
||||
'email' => $store_email,
|
||||
'email' => $store_email,
|
||||
'address' => $address,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
@@ -240,7 +240,19 @@ class Settings {
|
||||
|
||||
$settings['isWooPayEligible'] = WCPayPromotionInit::is_woopay_eligible();
|
||||
|
||||
$settings['gutenberg_version'] = defined( 'GUTENBERG_VERSION' ) ? constant( 'GUTENBERG_VERSION' ) : 0;
|
||||
$has_gutenberg = is_plugin_active( 'gutenberg/gutenberg.php' );
|
||||
$gutenberg_version = '';
|
||||
if ( $has_gutenberg ) {
|
||||
if ( defined( 'GUTENBERG_VERSION' ) ) {
|
||||
$gutenberg_version = GUTENBERG_VERSION;
|
||||
}
|
||||
|
||||
if ( ! $gutenberg_version ) {
|
||||
$gutenberg_data = get_plugin_data( WP_PLUGIN_DIR . '/gutenberg/gutenberg.php' );
|
||||
$gutenberg_version = $gutenberg_data['Version'];
|
||||
}
|
||||
}
|
||||
$settings['gutenberg_version'] = $has_gutenberg ? $gutenberg_version : 0;
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,34 @@ class WCPaymentGatewayPreInstallWCPayPromotion extends \WC_Payment_Gateway {
|
||||
$this->method_description = $wc_pay_spec->content;
|
||||
$this->has_fields = false;
|
||||
|
||||
// Set the promotion pseudo-gateway support features.
|
||||
// If the promotion spec provides the supports property, use it.
|
||||
if ( property_exists( $wc_pay_spec, 'supports' ) ) {
|
||||
$this->supports = $wc_pay_spec->supports;
|
||||
} else {
|
||||
// Otherwise, use the default supported features in line with WooPayments ones.
|
||||
// We include all features here, even if some of them are behind settings, since this is for info only.
|
||||
$this->supports = array(
|
||||
// Regular features.
|
||||
'products',
|
||||
'refunds',
|
||||
// Subscriptions features.
|
||||
'subscriptions',
|
||||
'multiple_subscriptions',
|
||||
'subscription_cancellation',
|
||||
'subscription_reactivation',
|
||||
'subscription_suspension',
|
||||
'subscription_amount_changes',
|
||||
'subscription_date_changes',
|
||||
'subscription_payment_method_change_admin',
|
||||
'subscription_payment_method_change_customer',
|
||||
'subscription_payment_method_change',
|
||||
// Saved cards features.
|
||||
'tokenization',
|
||||
'add_payment_method',
|
||||
);
|
||||
}
|
||||
|
||||
// Get setting values.
|
||||
$this->enabled = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user