Plugin Updates

This commit is contained in:
Tony Volpe
2024-04-02 20:23:21 +00:00
parent 96800520e8
commit 94170ec2c4
1514 changed files with 133309 additions and 105985 deletions

View File

@@ -664,6 +664,26 @@ class FileController {
return array_slice( $matched_lines, $args['offset'], $args['per_page'] );
}
/**
* Calculate the size, in bytes, of the log directory.
*
* @return int
*/
public function get_log_directory_size(): int {
$bytes = 0;
$path = realpath( $this->log_directory );
if ( wp_is_writable( $path ) ) {
$iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $path, \FilesystemIterator::SKIP_DOTS ) );
foreach ( $iterator as $file ) {
$bytes += $file->getSize();
}
}
return $bytes;
}
/**
* Invalidate the cache group related to log file data.
*

View File

@@ -123,6 +123,10 @@ class LogHandlerFileV2 extends WC_Log_Handler {
$backtrace = static::get_backtrace();
foreach ( $backtrace as $frame ) {
if ( ! isset( $frame['file'] ) ) {
continue;
}
foreach ( $source_roots as $type => $path ) {
if ( 0 === strpos( $frame['file'], $path ) ) {
$relative_path = trim( substr( $frame['file'], strlen( $path ) ), DIRECTORY_SEPARATOR );
@@ -233,7 +237,29 @@ class LogHandlerFileV2 extends WC_Log_Handler {
)
);
if ( is_wp_error( $files ) || count( $files ) < 1 ) {
if ( is_wp_error( $files ) ) {
return 0;
}
$files = array_filter(
$files,
function( $file ) use ( $timestamp ) {
/**
* Allows preventing an expired log file from being deleted.
*
* @param bool $delete True to delete the file.
* @param File $file The log file object.
* @param int $timestamp The expiration threshold.
*
* @since 8.7.0
*/
$delete = apply_filters( 'woocommerce_logger_delete_expired_file', true, $file, $timestamp );
return boolval( $delete );
}
);
if ( count( $files ) < 1 ) {
return 0;
}
@@ -250,31 +276,16 @@ class LogHandlerFileV2 extends WC_Log_Handler {
time(),
'info',
sprintf(
'%s %s',
sprintf(
esc_html(
// translators: %s is a number of log files.
_n(
'%s expired log file was deleted.',
'%s expired log files were deleted.',
$deleted,
'woocommerce'
)
),
number_format_i18n( $deleted )
esc_html(
// translators: %s is a number of log files.
_n(
'%s expired log file was deleted.',
'%s expired log files were deleted.',
$deleted,
'woocommerce'
)
),
sprintf(
esc_html(
// translators: %s is a number of days.
_n(
'The retention period for log files is %s day.',
'The retention period for log files is %s days.',
$retention_days,
'woocommerce'
)
),
number_format_i18n( $retention_days )
)
number_format_i18n( $deleted )
),
array(
'source' => 'wc_logger',

View File

@@ -4,10 +4,12 @@ declare( strict_types=1 );
namespace Automattic\WooCommerce\Internal\Admin\Logging;
use Automattic\Jetpack\Constants;
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 WC_Admin_Settings;
use WC_Log_Handler, WC_Log_Handler_DB, WC_Log_Handler_File, WC_Log_Levels;
use WC_Log_Handler_DB, WC_Log_Handler_File, WC_Log_Levels;
/**
* Settings class.
@@ -22,11 +24,10 @@ class 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,
'logging_enabled' => true,
'default_handler' => LogHandlerFileV2::class,
'retention_period_days' => 30,
'level_threshold' => 'none',
);
/**
@@ -77,13 +78,13 @@ class Settings {
$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();
$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;
@@ -153,18 +154,28 @@ class Settings {
'step' => 1,
);
$desc = array();
$hardcoded = has_filter( 'woocommerce_logger_days_to_retain_logs' );
$desc = '';
if ( $hardcoded ) {
$custom_attributes['disabled'] = 'true';
$desc = sprintf(
$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>'
);
}
$file_delete_has_filter = LogHandlerFileV2::class === $this->get_default_handler() && has_filter( 'woocommerce_logger_delete_expired_file' );
if ( $file_delete_has_filter ) {
$desc[] = sprintf(
// translators: %s is the name of a filter hook.
__( 'The %s hook has a filter set, so some log files may have different retention settings.', 'woocommerce' ),
'<code>woocommerce_logger_delete_expired_file</code>'
);
}
return array(
'title' => __( 'Retention period', 'woocommerce' ),
'desc_tip' => __( 'This sets how many days log entries will be kept before being auto-deleted.', 'woocommerce' ),
@@ -180,7 +191,7 @@ class Settings {
' %s',
__( 'days', 'woocommerce' ),
),
'desc' => $desc,
'desc' => implode( '<br><br>', $desc ),
);
}
@@ -231,7 +242,7 @@ class Settings {
*/
private function get_filesystem_settings_definitions(): array {
$location_info = array();
$directory = trailingslashit( realpath( Constants::get_constant( 'WC_LOG_DIR' ) ) );
$directory = trailingslashit( Constants::get_constant( 'WC_LOG_DIR' ) );
$location_info[] = sprintf(
// translators: %s is a location in the filesystem.
@@ -253,6 +264,12 @@ class Settings {
'<code>wp-config.php</code>'
);
$location_info[] = sprintf(
// translators: %s is an amount of computer disk space, e.g. 5 KB.
__( 'Directory size: %s', 'woocommerce' ),
size_format( wc_get_container()->get( FileController::class )->get_log_directory_size() )
);
return array(
'file_start' => array(
'title' => __( 'File system settings', 'woocommerce' ),
@@ -260,8 +277,9 @@ class Settings {
'type' => 'title',
),
'log_directory' => array(
'type' => 'info',
'text' => implode( "\n\n", $location_info ),
'title' => __( 'Location', 'woocommerce' ),
'type' => 'info',
'text' => implode( "\n\n", $location_info ),
),
'entry_format' => array(),
'file_end' => array(
@@ -293,8 +311,9 @@ class Settings {
'type' => 'title',
),
'database_table' => array(
'type' => 'info',
'text' => $location_info,
'title' => __( 'Location', 'woocommerce' ),
'type' => 'info',
'text' => $location_info,
),
'file_end' => array(
'id' => self::PREFIX . 'settings',

View File

@@ -11,8 +11,10 @@ namespace Automattic\WooCommerce\Internal\Admin\Onboarding;
class Onboarding {
/**
* Initialize onboarding functionality.
*
* @internal This method is for internal purposes only.
*/
public static function init() {
final public static function init() {
OnboardingHelper::instance()->init();
OnboardingIndustries::init();
OnboardingJetpack::instance()->init();
@@ -21,5 +23,6 @@ class Onboarding {
OnboardingSetupWizard::instance()->init();
OnboardingSync::instance()->init();
OnboardingThemes::init();
OnboardingFonts::init();
}
}

View File

@@ -0,0 +1,260 @@
<?php
namespace Automattic\WooCommerce\Internal\Admin\Onboarding;
use Automattic\WooCommerce\Internal\Font\FontFace;
use Automattic\WooCommerce\Internal\Font\FontFamily;
/**
* Class to install fonts for the Assembler.
*
* @internal
*/
class OnboardingFonts {
/**
* Initialize the class.
*
* @internal This method is for internal purposes only.
*/
final public static function init() {
add_action( 'woocommerce_install_assembler_fonts', array( __CLASS__, 'install_fonts' ) );
add_filter( 'update_option_woocommerce_allow_tracking', array( self::class, 'start_install_fonts_async_job' ), 10, 2 );
}
const SOURCE_LOGGER = 'font_loader';
/**
* Font families to install.
* PHP version of https://github.com/woocommerce/woocommerce/blob/45923dc5f38150c717210ae9db10045cd9582331/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/global-styles/font-pairing-variations/constants.ts/#L13-L74
*
* @var array
*/
const FONT_FAMILIES_TO_INSTALL = array(
'inter' => array(
'fontFamily' => 'Inter',
'fontWeights' => array( '400', '500', '600' ),
'fontStyles' => array( 'normal' ),
),
'bodoni-moda' => array(
'fontFamily' => 'Bodoni Moda',
'fontWeights' => array( '400' ),
'fontStyles' => array( 'normal' ),
),
'overpass' => array(
'fontFamily' => 'Overpass',
'fontWeights' => array( '300', '400' ),
'fontStyles' => array( 'normal' ),
),
'albert-sans' => array(
'fontFamily' => 'Albert Sans',
'fontWeights' => array( '700' ),
'fontStyles' => array( 'normal' ),
),
'lora' => array(
'fontFamily' => 'Lora',
'fontWeights' => array( '400' ),
'fontStyles' => array( 'normal' ),
),
'montserrat' => array(
'fontFamily' => 'Montserrat',
'fontWeights' => array( '500', '700' ),
'fontStyles' => array( 'normal' ),
),
'arvo' => array(
'fontFamily' => 'Arvo',
'fontWeights' => array( '400' ),
'fontStyles' => array( 'normal' ),
),
'rubik' => array(
'fontFamily' => 'Rubik',
'fontWeights' => array( '400', '800' ),
'fontStyles' => array( 'normal' ),
),
'newsreader' => array(
'fontFamily' => 'Newsreader',
'fontWeights' => array( '400' ),
'fontStyles' => array( 'normal' ),
),
'cormorant' => array(
'fontFamily' => 'Cormorant',
'fontWeights' => array( '400', '500' ),
'fontStyles' => array( 'normal' ),
),
'work-sans' => array(
'fontFamily' => 'Work Sans',
'fontWeights' => array( '400' ),
'fontStyles' => array( 'normal' ),
),
'raleway' => array(
'fontFamily' => 'Raleway',
'fontWeights' => array( '700' ),
'fontStyles' => array( 'normal' ),
),
);
/**
* Start install fonts async job.
*
* @param string $old_value Old option value.
* @param string $value Option value.
* @return string
*/
public static function start_install_fonts_async_job( $old_value, $value ) {
if ( 'yes' !== $value || ! class_exists( 'WP_Font_Library' ) ) {
return;
}
WC()->call_function(
'as_schedule_single_action',
WC()->call_function( 'time' ),
'woocommerce_install_assembler_fonts',
);
}
/**
* Create Font Families and Font Faces.
*
* @return void
*/
public static function install_fonts() {
$collections = \WP_Font_Library::get_instance()->get_font_collections();
$google_fonts = $collections['google-fonts']->get_data();
$font_collection = $google_fonts['font_families'];
$slug_font_families_to_install = array_keys( self::FONT_FAMILIES_TO_INSTALL );
$installed_font_families = self::install_font_families( $slug_font_families_to_install, $font_collection );
if ( ! empty( $installed_font_families ) ) {
$font_faces_from_collection = self::get_font_faces_data_from_font_collection( $slug_font_families_to_install, $font_collection );
self::install_font_faces( $slug_font_families_to_install, $installed_font_families, $font_faces_from_collection );
}
}
/**
* Install font families.
*
* @param array $slug_font_families_to_install Font families to install.
* @param array $font_collection Font collection.
* @return array
*/
private static function install_font_families( $slug_font_families_to_install, $font_collection ) {
return array_reduce(
$slug_font_families_to_install,
function( $carry, $slug ) use ( $font_collection ) {
$font_family_from_collection = self::get_font_family_by_slug_from_font_collection( $slug, $font_collection );
$font_family_name = $font_family_from_collection['fontFamily'];
$font_family_installed = FontFamily::get_font_family_by_name( $font_family_name );
if ( $font_family_installed ) {
return array_merge( $carry, array( $slug => $font_family_installed ) );
}
$font_family_settings = array(
'fontFamily' => $font_family_from_collection['fontFamily'],
'preview' => $font_family_from_collection['preview'],
'slug' => $font_family_from_collection['slug'],
'name' => $font_family_from_collection['name'],
);
$font_family_id = FontFamily::insert_font_family( $font_family_settings );
if ( is_wp_error( $font_family_id ) ) {
if ( 'duplicate_font_family' !== $font_family_id->get_error_code() ) {
wc_get_logger()->error(
sprintf(
'Font Family installation error: %s',
$font_family_id->get_error_message(),
),
array( 'source' => self::SOURCE_LOGGER )
);
}
return $carry;
}
return array_merge( $carry, array( $slug => get_post( $font_family_id ) ) );
},
array(),
);
}
/**
* Install font faces.
*
* @param array $slug_font_families_to_install Font families to install.
* @param array $installed_font_families Installed font families.
* @param array $font_faces_from_collection Font faces from collection.
*/
private static function install_font_faces( $slug_font_families_to_install, $installed_font_families, $font_faces_from_collection ) {
foreach ( $slug_font_families_to_install as $slug ) {
$font_family = $installed_font_families[ $slug ];
$font_faces = $font_faces_from_collection[ $slug ];
$font_faces_to_install = self::FONT_FAMILIES_TO_INSTALL[ $slug ]['fontWeights'];
foreach ( $font_faces as $font_face ) {
if ( ! in_array( $font_face['fontWeight'], $font_faces_to_install, true ) ) {
continue;
}
$slug = \WP_Font_Utils::get_font_face_slug( $font_face );
$font_face_installed = FontFace::get_installed_font_faces_by_slug( $slug );
if ( $font_face_installed ) {
continue;
}
$wp_error = FontFace::insert_font_face( $font_face, $font_family->ID );
if ( is_wp_error( $wp_error ) ) {
wc_get_logger()->error(
sprintf(
/* translators: %s: error message */
__( 'Font Face installation error: %s', 'woocommerce' ),
$wp_error->get_error_message()
),
array( 'source' => self::SOURCE_LOGGER )
);
}
}
}
}
/**
* Get font faces data from font collection.
*
* @param array $slug_font_families_to_install Font families to install.
* @param array $font_collection Font collection.
* @return array
*/
private static function get_font_faces_data_from_font_collection( $slug_font_families_to_install, $font_collection ) {
return array_reduce(
$slug_font_families_to_install,
function( $carry, $slug ) use ( $font_collection ) {
$font_family = self::get_font_family_by_slug_from_font_collection( $slug, $font_collection );
if ( ! $font_family ) {
return $carry;
}
return array_merge( $carry, array( $slug => $font_family['fontFace'] ) );
},
array()
);
}
/**
* Get font family by slug from font collection.
*
* @param string $slug Font slug.
* @param array $font_families_collection Font families collection.
* @return array|null
*/
private static function get_font_family_by_slug_from_font_collection( $slug, $font_families_collection ) {
$font_family = null;
foreach ( $font_families_collection as $font_family ) {
if ( $font_family['font_family_settings']['slug'] === $slug ) {
$font_family = $font_family['font_family_settings'];
break;
}
}
return $font_family;
}
}

View File

@@ -20,7 +20,7 @@ class EvaluateExtension {
* @param object $extension The extension to evaluate.
* @return object The evaluated extension.
*/
public static function evaluate( $extension ) {
private static function evaluate( $extension ) {
global $wp_version;
$rule_evaluator = new RuleEvaluator();
@@ -49,4 +49,44 @@ class EvaluateExtension {
return $extension;
}
/**
* Evaluates the specs and returns the bundles with visible extensions.
*
* @param array $specs extensions spec array.
* @param array $allowed_bundles Optional array of allowed bundles to be returned.
* @return array The bundles and errors.
*/
public static function evaluate_bundles( $specs, $allowed_bundles = array() ) {
$bundles = array();
foreach ( $specs as $spec ) {
$spec = (object) $spec;
$bundle = (array) $spec;
$bundle['plugins'] = array();
if ( ! empty( $allowed_bundles ) && ! in_array( $spec->key, $allowed_bundles, true ) ) {
continue;
}
$errors = array();
foreach ( $spec->plugins as $plugin ) {
try {
$extension = self::evaluate( (object) $plugin );
if ( ! property_exists( $extension, 'is_visible' ) || $extension->is_visible ) {
$bundle['plugins'][] = $extension;
}
} catch ( \Throwable $e ) {
$errors[] = $e;
}
}
$bundles[] = $bundle;
}
return array(
'bundles' => $bundles,
'errors' => $errors,
);
}
}

View File

@@ -8,12 +8,13 @@ namespace Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions;
defined( 'ABSPATH' ) || exit;
use Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions\DefaultFreeExtensions;
use Automattic\WooCommerce\Admin\RemoteSpecs\RemoteSpecsEngine;
/**
* Remote Payment Methods engine.
* This goes through the specs and gets eligible payment methods.
*/
class Init {
class Init extends RemoteSpecsEngine {
/**
* Constructor.
@@ -29,34 +30,39 @@ class Init {
* @return array
*/
public static function get_extensions( $allowed_bundles = array() ) {
$bundles = array();
$specs = self::get_specs();
$locale = get_user_locale();
foreach ( $specs as $spec ) {
$spec = (object) $spec;
$bundle = (array) $spec;
$bundle['plugins'] = array();
$specs = self::get_specs();
$results = EvaluateExtension::evaluate_bundles( $specs, $allowed_bundles );
$specs_to_return = $results['bundles'];
$specs_to_save = null;
if ( ! empty( $allowed_bundles ) && ! in_array( $spec->key, $allowed_bundles, true ) ) {
continue;
$plugins = array_filter(
$results['bundles'],
function( $bundle ) {
return count( $bundle['plugins'] ) > 0;
}
);
foreach ( $spec->plugins as $plugin ) {
try {
$extension = EvaluateExtension::evaluate( (object) $plugin );
if ( ! property_exists( $extension, 'is_visible' ) || $extension->is_visible ) {
$bundle['plugins'][] = $extension;
}
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
} catch ( \Throwable $e ) {
// Ignore errors.
}
}
$bundles[] = $bundle;
if ( empty( $plugins ) ) {
// When no plugins are visible, replace it with defaults and save for 3 hours.
$specs_to_save = DefaultFreeExtensions::get_all();
$specs_to_return = EvaluateExtension::evaluate_bundles( $specs_to_save, $allowed_bundles )['bundles'];
} elseif ( count( $results['errors'] ) > 0 ) {
// When suggestions is not empty but has errors, save it for 3 hours.
$specs_to_save = $specs;
}
return $bundles;
// When plugins is not empty but has errors, save it for 3 hours.
if ( count( $results['errors'] ) > 0 ) {
self::log_errors( $results['errors'] );
}
if ( $specs_to_save ) {
RemoteFreeExtensionsDataSourcePoller::get_instance()->set_specs_transient( array( $locale => $specs_to_save ), 3 * HOUR_IN_SECONDS );
}
return $specs_to_return;
}
/**

View File

@@ -288,6 +288,8 @@ class WCAdminAssets {
'wc-components',
'wc-customer-effort-score',
'wc-experimental',
'wc-navigation',
'wc-product-editor',
WC_ADMIN_APP,
);

View File

@@ -7,15 +7,14 @@ namespace Automattic\WooCommerce\Internal\Admin\WCPayPromotion;
defined( 'ABSPATH' ) || exit;
use Automattic\WooCommerce\Admin\DataSourcePoller;
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\EvaluateSuggestion;
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\PaymentGatewaySuggestionsDataSourcePoller as PaymentGatewaySuggestionsDataSourcePoller;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Admin\RemoteSpecs\RemoteSpecsEngine;
/**
* WC Pay Promotion engine.
*/
class Init {
class Init extends RemoteSpecsEngine {
const EXPLAT_VARIATION_PREFIX = 'woocommerce_wc_pay_promotion_payment_methods_table_';
/**
@@ -30,8 +29,8 @@ class Init {
}
add_filter( 'woocommerce_payment_gateways', array( __CLASS__, 'possibly_register_pre_install_wc_pay_promotion_gateway' ) );
add_filter( 'option_woocommerce_gateway_order', [ __CLASS__, 'set_gateway_top_of_list' ] );
add_filter( 'default_option_woocommerce_gateway_order', [ __CLASS__, 'set_gateway_top_of_list' ] );
add_filter( 'option_woocommerce_gateway_order', array( __CLASS__, 'set_gateway_top_of_list' ) );
add_filter( 'default_option_woocommerce_gateway_order', array( __CLASS__, 'set_gateway_top_of_list' ) );
$rtl = is_rtl() ? '.rtl' : '';
@@ -122,28 +121,19 @@ class Init {
* Go through the specs and run them.
*/
public static function get_promotions() {
$suggestions = array();
$specs = self::get_specs();
$locale = get_user_locale();
foreach ( $specs as $spec ) {
try {
$suggestion = EvaluateSuggestion::evaluate( $spec );
$suggestions[] = $suggestion;
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
} catch ( \Throwable $e ) {
// Ignore errors.
}
$specs = self::get_specs();
$results = EvaluateSuggestion::evaluate_specs( $specs );
if ( count( $results['errors'] ) > 0 ) {
// Unlike payment gateway suggestions, we don't have a non-empty default set of promotions to fall back to.
// So just set the specs transient with expired time to 3 hours.
WCPayPromotionDataSourcePoller::get_instance()->set_specs_transient( array( $locale => $specs ), 3 * HOUR_IN_SECONDS );
self::log_errors( $results['errors'] );
}
return array_values(
array_filter(
$suggestions,
function( $suggestion ) {
return ! property_exists( $suggestion, 'is_visible' ) || $suggestion->is_visible;
}
)
);
return $results['suggestions'];
}
/**