Plugins
This commit is contained in:
@@ -1,325 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* A class of utilities for dealing with arrays.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Utilities;
|
||||
|
||||
/**
|
||||
* A class of utilities for dealing with arrays.
|
||||
*/
|
||||
class ArrayUtil {
|
||||
|
||||
/**
|
||||
* Automatic selector type for the 'select' method.
|
||||
*/
|
||||
public const SELECT_BY_AUTO = 0;
|
||||
|
||||
/**
|
||||
* Object method selector type for the 'select' method.
|
||||
*/
|
||||
public const SELECT_BY_OBJECT_METHOD = 1;
|
||||
|
||||
/**
|
||||
* Object property selector type for the 'select' method.
|
||||
*/
|
||||
public const SELECT_BY_OBJECT_PROPERTY = 2;
|
||||
|
||||
/**
|
||||
* Array key selector type for the 'select' method.
|
||||
*/
|
||||
public const SELECT_BY_ARRAY_KEY = 3;
|
||||
|
||||
/**
|
||||
* Get a value from an nested array by specifying the entire key hierarchy with '::' as separator.
|
||||
*
|
||||
* E.g. for [ 'foo' => [ 'bar' => [ 'fizz' => 'buzz' ] ] ] the value for key 'foo::bar::fizz' would be 'buzz'.
|
||||
*
|
||||
* @param array $array The array to get the value from.
|
||||
* @param string $key The complete key hierarchy, using '::' as separator.
|
||||
* @param mixed $default The value to return if the key doesn't exist in the array.
|
||||
*
|
||||
* @return mixed The retrieved value, or the supplied default value.
|
||||
* @throws \Exception $array is not an array.
|
||||
*/
|
||||
public static function get_nested_value( array $array, string $key, $default = null ) {
|
||||
$key_stack = explode( '::', $key );
|
||||
$subkey = array_shift( $key_stack );
|
||||
|
||||
if ( isset( $array[ $subkey ] ) ) {
|
||||
$value = $array[ $subkey ];
|
||||
|
||||
if ( count( $key_stack ) ) {
|
||||
foreach ( $key_stack as $subkey ) {
|
||||
if ( is_array( $value ) && isset( $value[ $subkey ] ) ) {
|
||||
$value = $value[ $subkey ];
|
||||
} else {
|
||||
$value = $default;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$value = $default;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given key exists in an array and its value can be evaluated as 'true'.
|
||||
*
|
||||
* @param array $array The array to check.
|
||||
* @param string $key The key for the value to check.
|
||||
* @return bool True if the key exists in the array and the value can be evaluated as 'true'.
|
||||
*/
|
||||
public static function is_truthy( array $array, string $key ) {
|
||||
return isset( $array[ $key ] ) && $array[ $key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for a given key from an array, or a default value if the key doesn't exist in the array.
|
||||
*
|
||||
* This is equivalent to "$array[$key] ?? $default" except in one case:
|
||||
* when they key exists, has a null value, and a non-null default is supplied:
|
||||
*
|
||||
* $array = ['key' => null]
|
||||
* $array['key'] ?? 'default' => 'default'
|
||||
* ArrayUtil::get_value_or_default($array, 'key', 'default') => null
|
||||
*
|
||||
* @param array $array The array to get the value from.
|
||||
* @param string $key The key to use to retrieve the value.
|
||||
* @param null $default The default value to return if the key doesn't exist in the array.
|
||||
* @return mixed|null The value for the key, or the default value passed.
|
||||
*/
|
||||
public static function get_value_or_default( array $array, string $key, $default = null ) {
|
||||
return array_key_exists( $key, $array ) ? $array[ $key ] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of numbers to a human-readable range, such as "1,2,3,5" to "1-3, 5". It also supports
|
||||
* floating point numbers, however with some perhaps unexpected / undefined behaviour if used within a range.
|
||||
* Source: https://stackoverflow.com/a/34254663/4574
|
||||
*
|
||||
* @param array $items An array (in any order, see $sort) of individual numbers.
|
||||
* @param string $item_separator The string that separates sequential range groups. Defaults to ', '.
|
||||
* @param string $range_separator The string that separates ranges. Defaults to '-'. A plausible example otherwise would be ' to '.
|
||||
* @param bool|true $sort Sort the array prior to iterating? You'll likely always want to sort, but if not, you can set this to false.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function to_ranges_string( array $items, string $item_separator = ', ', string $range_separator = '-', bool $sort = true ): string {
|
||||
if ( $sort ) {
|
||||
sort( $items );
|
||||
}
|
||||
|
||||
$point = null;
|
||||
$range = false;
|
||||
$str = '';
|
||||
|
||||
foreach ( $items as $i ) {
|
||||
if ( null === $point ) {
|
||||
$str .= $i;
|
||||
} elseif ( ( $point + 1 ) === $i ) {
|
||||
$range = true;
|
||||
} else {
|
||||
if ( $range ) {
|
||||
$str .= $range_separator . $point;
|
||||
$range = false;
|
||||
}
|
||||
$str .= $item_separator . $i;
|
||||
}
|
||||
$point = $i;
|
||||
}
|
||||
|
||||
if ( $range ) {
|
||||
$str .= $range_separator . $point;
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to generate a callback which can be executed on an array to select a value from each item.
|
||||
*
|
||||
* @param string $selector_name Field/property/method name to select.
|
||||
* @param int $selector_type Selector type.
|
||||
*
|
||||
* @return \Closure Callback to select the value.
|
||||
*/
|
||||
private static function get_selector_callback( string $selector_name, int $selector_type = self::SELECT_BY_AUTO ): \Closure {
|
||||
if ( self::SELECT_BY_OBJECT_METHOD === $selector_type ) {
|
||||
$callback = function( $item ) use ( $selector_name ) {
|
||||
return $item->$selector_name();
|
||||
};
|
||||
} elseif ( self::SELECT_BY_OBJECT_PROPERTY === $selector_type ) {
|
||||
$callback = function( $item ) use ( $selector_name ) {
|
||||
return $item->$selector_name;
|
||||
};
|
||||
} elseif ( self::SELECT_BY_ARRAY_KEY === $selector_type ) {
|
||||
$callback = function( $item ) use ( $selector_name ) {
|
||||
return $item[ $selector_name ];
|
||||
};
|
||||
} else {
|
||||
$callback = function( $item ) use ( $selector_name ) {
|
||||
if ( is_array( $item ) ) {
|
||||
return $item[ $selector_name ];
|
||||
} elseif ( method_exists( $item, $selector_name ) ) {
|
||||
return $item->$selector_name();
|
||||
} else {
|
||||
return $item->$selector_name;
|
||||
}
|
||||
};
|
||||
}
|
||||
return $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select one single value from all the items in an array of either arrays or objects based on a selector.
|
||||
* For arrays, the selector is a key name; for objects, the selector can be either a method name or a property name.
|
||||
*
|
||||
* @param array $items Items to apply the selection to.
|
||||
* @param string $selector_name Key, method or property name to use as a selector.
|
||||
* @param int $selector_type Selector type, one of the SELECT_BY_* constants.
|
||||
* @return array The selected values.
|
||||
*/
|
||||
public static function select( array $items, string $selector_name, int $selector_type = self::SELECT_BY_AUTO ): array {
|
||||
$callback = self::get_selector_callback( $selector_name, $selector_type );
|
||||
return array_map( $callback, $items );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new assoc array with format [ $key1 => $item1, $key2 => $item2, ... ] where $key is the value of the selector and items are original items passed.
|
||||
*
|
||||
* @param array $items Items to use for conversion.
|
||||
* @param string $selector_name Key, method or property name to use as a selector.
|
||||
* @param int $selector_type Selector type, one of the SELECT_BY_* constants.
|
||||
*
|
||||
* @return array The converted assoc array.
|
||||
*/
|
||||
public static function select_as_assoc( array $items, string $selector_name, int $selector_type = self::SELECT_BY_AUTO ): array {
|
||||
$selector_callback = self::get_selector_callback( $selector_name, $selector_type );
|
||||
$result = array();
|
||||
foreach ( $items as $item ) {
|
||||
$key = $selector_callback( $item );
|
||||
self::ensure_key_is_array( $result, $key );
|
||||
$result[ $key ][] = $item;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether two assoc array are same. The comparison is done recursively by keys, and the functions returns on first difference found.
|
||||
*
|
||||
* @param array $array1 First array to compare.
|
||||
* @param array $array2 Second array to compare.
|
||||
* @param bool $strict Whether to use strict comparison.
|
||||
*
|
||||
* @return bool Whether the arrays are different.
|
||||
*/
|
||||
public static function deep_compare_array_diff( array $array1, array $array2, bool $strict = true ) {
|
||||
return self::deep_compute_or_compare_array_diff( $array1, $array2, true, $strict );
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes difference between two assoc arrays recursively. Similar to PHP's native assoc_array_diff, but also supports nested arrays.
|
||||
*
|
||||
* @param array $array1 First array.
|
||||
* @param array $array2 Second array.
|
||||
* @param bool $strict Whether to also match type of values.
|
||||
*
|
||||
* @return array The difference between the two arrays.
|
||||
*/
|
||||
public static function deep_assoc_array_diff( array $array1, array $array2, bool $strict = true ): array {
|
||||
return self::deep_compute_or_compare_array_diff( $array1, $array2, false, $strict );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to compare to compute difference between two arrays. Comparison is done recursively.
|
||||
*
|
||||
* @param array $array1 First array.
|
||||
* @param array $array2 Second array.
|
||||
* @param bool $compare Whether to compare the arrays. If true, then function will return false on first difference, in order to be slightly more efficient.
|
||||
* @param bool $strict Whether to do string comparison.
|
||||
*
|
||||
* @return array|bool The difference between the two arrays, or if array are same, depending upon $compare param.
|
||||
*/
|
||||
private static function deep_compute_or_compare_array_diff( array $array1, array $array2, bool $compare, bool $strict = true ) {
|
||||
$diff = array();
|
||||
foreach ( $array1 as $key => $value ) {
|
||||
if ( is_array( $value ) ) {
|
||||
if ( ! array_key_exists( $key, $array2 ) || ! is_array( $array2[ $key ] ) ) {
|
||||
if ( $compare ) {
|
||||
return true;
|
||||
}
|
||||
$diff[ $key ] = $value;
|
||||
continue;
|
||||
}
|
||||
$new_diff = self::deep_assoc_array_diff( $value, $array2[ $key ], $strict );
|
||||
if ( ! empty( $new_diff ) ) {
|
||||
if ( $compare ) {
|
||||
return true;
|
||||
}
|
||||
$diff[ $key ] = $new_diff;
|
||||
}
|
||||
} elseif ( $strict ) {
|
||||
if ( ! array_key_exists( $key, $array2 ) || $value !== $array2[ $key ] ) {
|
||||
if ( $compare ) {
|
||||
return true;
|
||||
}
|
||||
$diff[ $key ] = $value;
|
||||
}
|
||||
} else {
|
||||
// phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison -- Intentional when $strict is false.
|
||||
if ( ! array_key_exists( $key, $array2 ) || $value != $array2[ $key ] ) {
|
||||
if ( $compare ) {
|
||||
return true;
|
||||
}
|
||||
$diff[ $key ] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $compare ? false : $diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a value to an array, but only if the value isn't in the array already.
|
||||
*
|
||||
* @param array $array The array.
|
||||
* @param mixed $value The value to maybe push.
|
||||
* @return bool True if the value has been added to the array, false if the value was already in the array.
|
||||
*/
|
||||
public static function push_once( array &$array, $value ) : bool {
|
||||
if ( in_array( $value, $array, true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$array[] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that an associative array has a given key, and if not, set the key to an empty array.
|
||||
*
|
||||
* @param array $array The array to check.
|
||||
* @param string $key The key to check.
|
||||
* @param bool $throw_if_existing_is_not_array If true, an exception will be thrown if the key already exists in the array but the value is not an array.
|
||||
* @return bool True if the key has been added to the array, false if not (the key already existed).
|
||||
* @throws \Exception The key already exists in the array but the value is not an array.
|
||||
*/
|
||||
public static function ensure_key_is_array( array &$array, string $key, bool $throw_if_existing_is_not_array = false ): bool {
|
||||
if ( ! isset( $array[ $key ] ) ) {
|
||||
$array[ $key ] = array();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $throw_if_existing_is_not_array && ! is_array( $array[ $key ] ) ) {
|
||||
$type = is_object( $array[ $key ] ) ? get_class( $array[ $key ] ) : gettype( $array[ $key ] );
|
||||
throw new \Exception( "Array key exists but it's not an array, it's a {$type}" );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* FeaturesUtil class file.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Utilities;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Features\FeaturesController;
|
||||
|
||||
/**
|
||||
* Class with methods that allow to retrieve information about the existing WooCommerce features,
|
||||
* also has methods for WooCommerce plugins to declare (in)compatibility with the features.
|
||||
*/
|
||||
class FeaturesUtil {
|
||||
|
||||
/**
|
||||
* Get all the existing WooCommerce features.
|
||||
*
|
||||
* Returns an associative array where keys are unique feature ids
|
||||
* and values are arrays with these keys:
|
||||
*
|
||||
* - name
|
||||
* - description
|
||||
* - is_experimental
|
||||
* - is_enabled (if $include_enabled_info is passed as true)
|
||||
*
|
||||
* @param bool $include_experimental Include also experimental/work in progress features in the list.
|
||||
* @param bool $include_enabled_info True to include the 'is_enabled' field in the returned features info.
|
||||
* @returns array An array of information about existing features.
|
||||
*/
|
||||
public static function get_features( bool $include_experimental = false, bool $include_enabled_info = false ): array {
|
||||
return wc_get_container()->get( FeaturesController::class )->get_features( $include_experimental, $include_enabled_info );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given feature is currently enabled.
|
||||
*
|
||||
* @param string $feature_id Unique feature id.
|
||||
* @return bool True if the feature is enabled, false if not or if the feature doesn't exist.
|
||||
*/
|
||||
public static function feature_is_enabled( string $feature_id ): bool {
|
||||
return wc_get_container()->get( FeaturesController::class )->feature_is_enabled( $feature_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare (in)compatibility with a given feature for a given plugin.
|
||||
*
|
||||
* This method MUST be executed from inside a handler for the 'before_woocommerce_init' hook and
|
||||
* SHOULD be executed from the main plugin file passing __FILE__ or 'my-plugin/my-plugin.php' for the
|
||||
* $plugin_file argument.
|
||||
*
|
||||
* @param string $feature_id Unique feature id.
|
||||
* @param string $plugin_file The full plugin file path.
|
||||
* @param bool $positive_compatibility True if the plugin declares being compatible with the feature, false if it declares being incompatible.
|
||||
* @return bool True on success, false on error (feature doesn't exist or not inside the required hook).
|
||||
*/
|
||||
public static function declare_compatibility( string $feature_id, string $plugin_file, bool $positive_compatibility = true ): bool {
|
||||
$plugin_id = wc_get_container()->get( PluginUtil::class )->get_wp_plugin_id( $plugin_file );
|
||||
|
||||
if ( ! $plugin_id ) {
|
||||
$logger = wc_get_logger();
|
||||
$logger->error( "FeaturesUtil::declare_compatibility: {$plugin_file} is not a known WordPress plugin." );
|
||||
return false;
|
||||
}
|
||||
|
||||
return wc_get_container()->get( FeaturesController::class )->declare_compatibility( $feature_id, $plugin_id, $positive_compatibility );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ids of the features that a certain plugin has declared compatibility for.
|
||||
*
|
||||
* This method can't be called before the 'woocommerce_init' hook is fired.
|
||||
*
|
||||
* @param string $plugin_name Plugin name, in the form 'directory/file.php'.
|
||||
* @return array An array having a 'compatible' and an 'incompatible' key, each holding an array of plugin ids.
|
||||
*/
|
||||
public static function get_compatible_features_for_plugin( string $plugin_name ): array {
|
||||
return wc_get_container()->get( FeaturesController::class )->get_compatible_features_for_plugin( $plugin_name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of the plugins that have been declared compatible or incompatible with a given feature.
|
||||
*
|
||||
* @param string $feature_id Feature id.
|
||||
* @return array An array having a 'compatible' and an 'incompatible' key, each holding an array of plugin names.
|
||||
*/
|
||||
public static function get_compatible_plugins_for_feature( string $feature_id ): array {
|
||||
return wc_get_container()->get( FeaturesController::class )->get_compatible_plugins_for_feature( $feature_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag indicating that it's allowed to enable features for which incompatible plugins are active
|
||||
* from the WooCommerce feature settings page.
|
||||
*/
|
||||
public static function allow_enabling_features_with_incompatible_plugins(): void {
|
||||
wc_get_container()->get( FeaturesController::class )->allow_enabling_features_with_incompatible_plugins();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag indicating that it's allowed to activate plugins for which incompatible features are enabled
|
||||
* from the WordPress plugins page.
|
||||
*/
|
||||
public static function allow_activating_plugins_with_incompatible_features(): void {
|
||||
wc_get_container()->get( FeaturesController::class )->allow_activating_plugins_with_incompatible_features();
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* A class of utilities for dealing with internationalization.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Utilities;
|
||||
|
||||
/**
|
||||
* A class of utilities for dealing with internationalization.
|
||||
*/
|
||||
final class I18nUtil {
|
||||
/**
|
||||
* A cache for the i18n units data.
|
||||
*
|
||||
* @var array $units
|
||||
*/
|
||||
private static $units;
|
||||
|
||||
/**
|
||||
* Get the translated label for a weight unit of measure.
|
||||
*
|
||||
* This will return the original input string if it isn't found in the units array. This way a custom unit of
|
||||
* measure can be used even if it's not getting translated.
|
||||
*
|
||||
* @param string $weight_unit The abbreviated weight unit in English, e.g. kg.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_weight_unit_label( $weight_unit ) {
|
||||
if ( empty( self::$units ) ) {
|
||||
self::$units = include WC()->plugin_path() . '/i18n/units.php';
|
||||
}
|
||||
|
||||
$label = $weight_unit;
|
||||
|
||||
if ( ! empty( self::$units['weight'][ $weight_unit ] ) ) {
|
||||
$label = self::$units['weight'][ $weight_unit ];
|
||||
}
|
||||
|
||||
return $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the translated label for a dimensions unit of measure.
|
||||
*
|
||||
* This will return the original input string if it isn't found in the units array. This way a custom unit of
|
||||
* measure can be used even if it's not getting translated.
|
||||
*
|
||||
* @param string $dimensions_unit The abbreviated dimension unit in English, e.g. cm.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_dimensions_unit_label( $dimensions_unit ) {
|
||||
if ( empty( self::$units ) ) {
|
||||
self::$units = include WC()->plugin_path() . '/i18n/units.php';
|
||||
}
|
||||
|
||||
$label = $dimensions_unit;
|
||||
|
||||
if ( ! empty( self::$units['dimensions'][ $dimensions_unit ] ) ) {
|
||||
$label = self::$units['dimensions'][ $dimensions_unit ];
|
||||
}
|
||||
|
||||
return $label;
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
<?php
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace Automattic\WooCommerce\Utilities;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\{ PageController, Settings };
|
||||
use Automattic\WooCommerce\Internal\Admin\Logging\FileV2\{ File, FileController };
|
||||
|
||||
/**
|
||||
* A class of utilities for dealing with logging.
|
||||
*/
|
||||
final class LoggingUtil {
|
||||
/**
|
||||
* Get the canonical URL for the Logs tab of the Status admin page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_logs_tab_url(): string {
|
||||
return wc_get_container()->get( PageController::class )->get_logs_tab_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the logging_enabled setting.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function logging_is_enabled(): bool {
|
||||
return wc_get_container()->get( Settings::class )->logging_is_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the default_handler setting.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_default_handler(): string {
|
||||
return wc_get_container()->get( Settings::class )->get_default_handler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the retention_period_days setting.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_retention_period(): int {
|
||||
return wc_get_container()->get( Settings::class )->get_retention_period();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the current value of the level_threshold setting.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_level_threshold(): string {
|
||||
return wc_get_container()->get( Settings::class )->get_level_threshold();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a public ID for a log file based on its properties.
|
||||
*
|
||||
* The file ID is the basename of the file without the hash part. It allows us to identify a file without revealing
|
||||
* its full name in the filesystem, so that it's difficult to access the file directly with an HTTP request.
|
||||
*
|
||||
* @param string $source The source of the log entries contained in the file.
|
||||
* @param int|null $rotation Optional. The 0-based incremental rotation marker, if the file has been rotated.
|
||||
* Should only be a single digit.
|
||||
* @param int $created Optional. The date the file was created, as a Unix timestamp.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function generate_log_file_id( string $source, ?int $rotation = null, int $created = 0 ): string {
|
||||
return File::generate_file_id( $source, $rotation, $created );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a hash to use as the suffix on a log filename.
|
||||
*
|
||||
* @param string $file_id A file ID (file basename without the hash).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function generate_log_file_hash( string $file_id ): string {
|
||||
return File::generate_hash( $file_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the directory for storing log files.
|
||||
*
|
||||
* @return string The full directory path, with trailing slash.
|
||||
*/
|
||||
public static function get_log_directory(): string {
|
||||
return Settings::get_log_directory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the size, in bytes, of the log directory.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_log_directory_size(): int {
|
||||
return wc_get_container()->get( FileController::class )->get_log_directory_size();
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* A class of utilities for dealing with numbers.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Utilities;
|
||||
|
||||
/**
|
||||
* A class of utilities for dealing with numbers.
|
||||
*/
|
||||
final class NumberUtil {
|
||||
|
||||
/**
|
||||
* Round a number using the built-in `round` function, but unless the value to round is numeric
|
||||
* (a number or a string that can be parsed as a number), apply 'floatval' first to it
|
||||
* (so it will convert it to 0 in most cases).
|
||||
*
|
||||
* This is needed because in PHP 7 applying `round` to a non-numeric value returns 0,
|
||||
* but in PHP 8 it throws an error. Specifically, in WooCommerce we have a few places where
|
||||
* round('') is often executed.
|
||||
*
|
||||
* @param mixed $val The value to round.
|
||||
* @param int $precision The optional number of decimal digits to round to.
|
||||
* @param int $mode A constant to specify the mode in which rounding occurs.
|
||||
*
|
||||
* @return float The value rounded to the given precision as a float, or the supplied default value.
|
||||
*/
|
||||
public static function round( $val, int $precision = 0, int $mode = PHP_ROUND_HALF_UP ) : float {
|
||||
if ( ! is_numeric( $val ) ) {
|
||||
$val = floatval( $val );
|
||||
}
|
||||
return round( $val, $precision, $mode );
|
||||
}
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* A class of utilities for dealing with orders.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Utilities;
|
||||
|
||||
use Automattic\WooCommerce\Caches\OrderCacheController;
|
||||
use Automattic\WooCommerce\Internal\Admin\Orders\PageController;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
|
||||
use Automattic\WooCommerce\Internal\Utilities\COTMigrationUtil;
|
||||
use WC_Order;
|
||||
use WP_Post;
|
||||
|
||||
/**
|
||||
* A class of utilities for dealing with orders.
|
||||
*/
|
||||
final class OrderUtil {
|
||||
|
||||
/**
|
||||
* Helper function to get screen name of orders page in wp-admin.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_order_admin_screen() : string {
|
||||
return wc_get_container()->get( COTMigrationUtil::class )->get_order_admin_screen();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to get whether custom order tables are enabled or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function custom_orders_table_usage_is_enabled() : bool {
|
||||
return wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get whether the orders cache should be used or not.
|
||||
*
|
||||
* @return bool True if the orders cache should be used, false otherwise.
|
||||
*/
|
||||
public static function orders_cache_usage_is_enabled() : bool {
|
||||
return wc_get_container()->get( OrderCacheController::class )->orders_cache_usage_is_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if posts and order custom table sync is enabled and there are no pending orders.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_custom_order_tables_in_sync() : bool {
|
||||
return wc_get_container()->get( COTMigrationUtil::class )->is_custom_order_tables_in_sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets value of a meta key from WC_Data object if passed, otherwise from the post object.
|
||||
* This helper function support backward compatibility for meta box functions, when moving from posts based store to custom tables.
|
||||
*
|
||||
* @param WP_Post|null $post Post object, meta will be fetched from this only when `$data` is not passed.
|
||||
* @param \WC_Data|null $data WC_Data object, will be preferred over post object when passed.
|
||||
* @param string $key Key to fetch metadata for.
|
||||
* @param bool $single Whether metadata is single.
|
||||
*
|
||||
* @return array|mixed|string Value of the meta key.
|
||||
*/
|
||||
public static function get_post_or_object_meta( ?WP_Post $post, ?\WC_Data $data, string $key, bool $single ) {
|
||||
return wc_get_container()->get( COTMigrationUtil::class )->get_post_or_object_meta( $post, $data, $key, $single );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to initialize the global $theorder object, mostly used during order meta boxes rendering.
|
||||
*
|
||||
* @param WC_Order|WP_Post $post_or_order_object Post or order object.
|
||||
*
|
||||
* @return bool|WC_Order|WC_Order_Refund WC_Order object.
|
||||
*/
|
||||
public static function init_theorder_object( $post_or_order_object ) {
|
||||
return wc_get_container()->get( COTMigrationUtil::class )->init_theorder_object( $post_or_order_object );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to id from an post or order object.
|
||||
*
|
||||
* @param WP_Post/WC_Order $post_or_order_object WP_Post/WC_Order object to get ID for.
|
||||
*
|
||||
* @return int Order or post ID.
|
||||
*/
|
||||
public static function get_post_or_order_id( $post_or_order_object ) : int {
|
||||
return wc_get_container()->get( COTMigrationUtil::class )->get_post_or_order_id( $post_or_order_object );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if passed id, post or order object is a WC_Order object.
|
||||
*
|
||||
* @param int|WP_Post|WC_Order $order_id Order ID, post object or order object.
|
||||
* @param string[] $types Types to match against.
|
||||
*
|
||||
* @return bool Whether the passed param is an order.
|
||||
*/
|
||||
public static function is_order( $order_id, $types = array( 'shop_order' ) ) {
|
||||
return wc_get_container()->get( COTMigrationUtil::class )->is_order( $order_id, $types );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns type pf passed id, post or order object.
|
||||
*
|
||||
* @param int|WP_Post|WC_Order $order_id Order ID, post object or order object.
|
||||
*
|
||||
* @return string|null Type of the order.
|
||||
*/
|
||||
public static function get_order_type( $order_id ) {
|
||||
return wc_get_container()->get( COTMigrationUtil::class )->get_order_type( $order_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to generate admin url for an order.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
*
|
||||
* @return string Admin url for an order.
|
||||
*/
|
||||
public static function get_order_admin_edit_url( int $order_id ) : string {
|
||||
return wc_get_container()->get( PageController::class )->get_edit_url( $order_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to generate admin URL for new order.
|
||||
*
|
||||
* @return string Link for new order.
|
||||
*/
|
||||
public static function get_order_admin_new_url() : string {
|
||||
return wc_get_container()->get( PageController::class )->get_new_page_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current admin screen is an order list table.
|
||||
*
|
||||
* @param string $order_type Optional. The order type to check for. Default shop_order.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_order_list_table_screen( $order_type = 'shop_order' ) : bool {
|
||||
return wc_get_container()->get( PageController::class )->is_order_screen( $order_type, 'list' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current admin screen is for editing an order.
|
||||
*
|
||||
* @param string $order_type Optional. The order type to check for. Default shop_order.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_order_edit_screen( $order_type = 'shop_order' ) : bool {
|
||||
return wc_get_container()->get( PageController::class )->is_order_screen( $order_type, 'edit' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current admin screen is adding a new order.
|
||||
*
|
||||
* @param string $order_type Optional. The order type to check for. Default shop_order.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_new_order_screen( $order_type = 'shop_order' ) : bool {
|
||||
return wc_get_container()->get( PageController::class )->is_order_screen( $order_type, 'new' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the database table that's currently in use for orders.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_table_for_orders() {
|
||||
return wc_get_container()->get( COTMigrationUtil::class )->get_table_for_orders();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the database table that's currently in use for orders.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_table_for_order_meta() {
|
||||
return wc_get_container()->get( COTMigrationUtil::class )->get_table_for_order_meta();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts number of orders of a given type.
|
||||
*
|
||||
* @since 8.7.0
|
||||
*
|
||||
* @param string $order_type Order type.
|
||||
* @return array<string,int> Array of order counts indexed by order type.
|
||||
*/
|
||||
public static function get_count_for_type( $order_type ) {
|
||||
global $wpdb;
|
||||
|
||||
$cache_key = \WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'order-count-' . $order_type;
|
||||
$count_per_status = wp_cache_get( $cache_key, 'counts' );
|
||||
|
||||
if ( false === $count_per_status ) {
|
||||
if ( self::custom_orders_table_usage_is_enabled() ) {
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
|
||||
$results = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
'SELECT `status`, COUNT(*) AS `count` FROM ' . self::get_table_for_orders() . ' WHERE `type` = %s GROUP BY `status`',
|
||||
$order_type
|
||||
),
|
||||
ARRAY_A
|
||||
);
|
||||
// phpcs:enable
|
||||
|
||||
$count_per_status = array_map( 'absint', array_column( $results, 'count', 'status' ) );
|
||||
} else {
|
||||
$count_per_status = (array) wp_count_posts( $order_type );
|
||||
}
|
||||
|
||||
// Make sure all order statuses are included just in case.
|
||||
$count_per_status = array_merge(
|
||||
array_fill_keys( array_keys( wc_get_order_statuses() ), 0 ),
|
||||
$count_per_status
|
||||
);
|
||||
|
||||
wp_cache_set( $cache_key, $count_per_status, 'counts' );
|
||||
}
|
||||
|
||||
return $count_per_status;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,292 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* A class of utilities for dealing with plugins.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Utilities;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
|
||||
use Automattic\WooCommerce\Internal\Utilities\PluginInstaller;
|
||||
use Automattic\WooCommerce\Proxies\LegacyProxy;
|
||||
|
||||
/**
|
||||
* A class of utilities for dealing with plugins.
|
||||
*/
|
||||
class PluginUtil {
|
||||
|
||||
use AccessiblePrivateMethods;
|
||||
|
||||
/**
|
||||
* The LegacyProxy instance to use.
|
||||
*
|
||||
* @var LegacyProxy
|
||||
*/
|
||||
private $proxy;
|
||||
|
||||
/**
|
||||
* The cached list of WooCommerce aware plugin ids.
|
||||
*
|
||||
* @var null|array
|
||||
*/
|
||||
private $woocommerce_aware_plugins = null;
|
||||
|
||||
/**
|
||||
* The cached list of enabled WooCommerce aware plugin ids.
|
||||
*
|
||||
* @var null|array
|
||||
*/
|
||||
private $woocommerce_aware_active_plugins = null;
|
||||
|
||||
/**
|
||||
* List of plugins excluded from feature compatibility warnings in UI.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $plugins_excluded_from_compatibility_ui;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the class.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::add_action( 'activated_plugin', array( $this, 'handle_plugin_de_activation' ), 10, 0 );
|
||||
self::add_action( 'deactivated_plugin', array( $this, 'handle_plugin_de_activation' ), 10, 0 );
|
||||
|
||||
$this->plugins_excluded_from_compatibility_ui = array( 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the class instance.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param LegacyProxy $proxy The instance of LegacyProxy to use.
|
||||
*/
|
||||
final public function init( LegacyProxy $proxy ) {
|
||||
$this->proxy = $proxy;
|
||||
require_once ABSPATH . WPINC . '/plugin.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list with the names of the WordPress plugins that are WooCommerce aware
|
||||
* (they have a "WC tested up to" header).
|
||||
*
|
||||
* @param bool $active_only True to return only active plugins, false to return all the active plugins.
|
||||
* @return string[] A list of plugin ids (path/file.php).
|
||||
*/
|
||||
public function get_woocommerce_aware_plugins( bool $active_only = false ): array {
|
||||
if ( is_null( $this->woocommerce_aware_plugins ) ) {
|
||||
// In case `get_plugins` was called much earlier in the request (before our headers could be injected), we
|
||||
// invalidate the plugin cache list.
|
||||
wp_cache_delete( 'plugins', 'plugins' );
|
||||
$all_plugins = $this->proxy->call_function( 'get_plugins' );
|
||||
|
||||
$this->woocommerce_aware_plugins =
|
||||
array_keys(
|
||||
array_filter(
|
||||
$all_plugins,
|
||||
array( $this, 'is_woocommerce_aware_plugin' )
|
||||
)
|
||||
);
|
||||
|
||||
$this->woocommerce_aware_active_plugins =
|
||||
array_values(
|
||||
array_filter(
|
||||
$this->woocommerce_aware_plugins,
|
||||
function ( $plugin_name ) {
|
||||
return $this->proxy->call_function( 'is_plugin_active', $plugin_name );
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $active_only ? $this->woocommerce_aware_active_plugins : $this->woocommerce_aware_plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the printable name of a plugin.
|
||||
*
|
||||
* @param string $plugin_id Plugin id (path/file.php).
|
||||
* @return string Printable plugin name, or the plugin id itself if printable name is not available.
|
||||
*/
|
||||
public function get_plugin_name( string $plugin_id ): string {
|
||||
$plugin_data = $this->proxy->call_function( 'get_plugin_data', WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $plugin_id );
|
||||
return $plugin_data['Name'] ?? $plugin_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a plugin is WooCommerce aware.
|
||||
*
|
||||
* @param string|array $plugin_file_or_data Plugin id (path/file.php) or plugin data (as returned by get_plugins).
|
||||
* @return bool True if the plugin exists and is WooCommerce aware.
|
||||
* @throws \Exception The input is neither a string nor an array.
|
||||
*/
|
||||
public function is_woocommerce_aware_plugin( $plugin_file_or_data ): bool {
|
||||
if ( is_string( $plugin_file_or_data ) ) {
|
||||
return in_array( $plugin_file_or_data, $this->get_woocommerce_aware_plugins(), true );
|
||||
} elseif ( is_array( $plugin_file_or_data ) ) {
|
||||
return '' !== ( $plugin_file_or_data['WC tested up to'] ?? '' );
|
||||
} else {
|
||||
throw new \Exception( 'is_woocommerce_aware_plugin requires a plugin name or an array of plugin data as input' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Match plugin identifier passed as a parameter with the output from `get_plugins()`.
|
||||
*
|
||||
* @param string $plugin_file Plugin identifier, either 'my-plugin/my-plugin.php', or output from __FILE__.
|
||||
*
|
||||
* @return string|false Key from the array returned by `get_plugins` if matched. False if no match.
|
||||
*/
|
||||
public function get_wp_plugin_id( $plugin_file ) {
|
||||
$wp_plugins = array_keys( $this->proxy->call_function( 'get_plugins' ) );
|
||||
|
||||
// Try to match plugin_basename().
|
||||
$plugin_basename = $this->proxy->call_function( 'plugin_basename', $plugin_file );
|
||||
if ( in_array( $plugin_basename, $wp_plugins, true ) ) {
|
||||
return $plugin_basename;
|
||||
}
|
||||
|
||||
// Try to match by the my-file/my-file.php (dir + file name), then by my-file.php (file name only).
|
||||
$plugin_file = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, $plugin_file );
|
||||
$file_name_parts = explode( DIRECTORY_SEPARATOR, $plugin_file );
|
||||
$file_name = array_pop( $file_name_parts );
|
||||
$directory_name = array_pop( $file_name_parts );
|
||||
$full_matches = array();
|
||||
$partial_matches = array();
|
||||
foreach ( $wp_plugins as $wp_plugin ) {
|
||||
if ( false !== strpos( $wp_plugin, $directory_name . DIRECTORY_SEPARATOR . $file_name ) ) {
|
||||
$full_matches[] = $wp_plugin;
|
||||
}
|
||||
|
||||
if ( false !== strpos( $wp_plugin, $file_name ) ) {
|
||||
$partial_matches[] = $wp_plugin;
|
||||
}
|
||||
}
|
||||
|
||||
if ( 1 === count( $full_matches ) ) {
|
||||
return $full_matches[0];
|
||||
}
|
||||
|
||||
if ( 1 === count( $partial_matches ) ) {
|
||||
return $partial_matches[0];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle plugin activation and deactivation by clearing the WooCommerce aware plugin ids cache.
|
||||
*/
|
||||
private function handle_plugin_de_activation(): void {
|
||||
$this->woocommerce_aware_plugins = null;
|
||||
$this->woocommerce_aware_active_plugins = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to generate warning string for incompatible features based on active plugins.
|
||||
*
|
||||
* Additionally, this method will manually print a warning message on the HPOS feature if both
|
||||
* the Legacy REST API and HPOS are active.
|
||||
*
|
||||
* @param string $feature_id Feature id.
|
||||
* @param array $plugin_feature_info Array of plugin feature info. See FeaturesControllers->get_compatible_plugins_for_feature() for details.
|
||||
*
|
||||
* @return string Warning string.
|
||||
*/
|
||||
public function generate_incompatible_plugin_feature_warning( string $feature_id, array $plugin_feature_info ): string {
|
||||
$feature_warning = '';
|
||||
$incompatibles = array_merge( $plugin_feature_info['incompatible'], $plugin_feature_info['uncertain'] );
|
||||
$incompatibles = array_filter( $incompatibles, 'is_plugin_active' );
|
||||
$incompatibles = array_values( array_diff( $incompatibles, $this->get_plugins_excluded_from_compatibility_ui() ) );
|
||||
$incompatible_count = count( $incompatibles );
|
||||
|
||||
$feature_warnings = array();
|
||||
if ( 'custom_order_tables' === $feature_id && 'yes' === get_option( 'woocommerce_api_enabled' ) ) {
|
||||
if ( is_plugin_active( 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php' ) ) {
|
||||
$legacy_api_and_hpos_incompatibility_warning_text =
|
||||
sprintf(
|
||||
// translators: %s is a URL.
|
||||
__( '⚠ <b><a target="_blank" href="%s">The Legacy REST API plugin</a> is installed and active on this site.</b> Please be aware that the WooCommerce Legacy REST API is <b>not</b> compatible with HPOS.', 'woocommerce' ),
|
||||
'https://wordpress.org/plugins/woocommerce-legacy-rest-api/'
|
||||
);
|
||||
} else {
|
||||
$legacy_api_and_hpos_incompatibility_warning_text =
|
||||
sprintf(
|
||||
// translators: %s is a URL.
|
||||
__( '⚠ <b><a target="_blank" href="%s">The Legacy REST API</a> is active on this site.</b> Please be aware that the WooCommerce Legacy REST API is <b>not</b> compatible with HPOS.', 'woocommerce' ),
|
||||
admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=legacy_api' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter to modify the warning text that appears in the HPOS section of the features settings page
|
||||
* when both the Legacy REST API is active (via WooCommerce core or via the Legacy REST API plugin)
|
||||
* and the orders table is in use as the primary data store for orders.
|
||||
*
|
||||
* @param string $legacy_api_and_hpos_incompatibility_warning_text Original warning text.
|
||||
* @returns string|null Actual warning text to use, or null to suppress the warning.
|
||||
*
|
||||
* @since 8.9.0
|
||||
*/
|
||||
$legacy_api_and_hpos_incompatibility_warning_text = apply_filters( 'woocommerce_legacy_api_and_hpos_incompatibility_warning_text', $legacy_api_and_hpos_incompatibility_warning_text );
|
||||
|
||||
if ( ! is_null( $legacy_api_and_hpos_incompatibility_warning_text ) ) {
|
||||
$feature_warnings[] = $legacy_api_and_hpos_incompatibility_warning_text . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ( $incompatible_count > 0 ) {
|
||||
if ( 1 === $incompatible_count ) {
|
||||
/* translators: %s = printable plugin name */
|
||||
$feature_warnings[] = sprintf( __( '⚠ 1 Incompatible plugin detected (%s).', 'woocommerce' ), $this->get_plugin_name( $incompatibles[0] ) );
|
||||
} elseif ( 2 === $incompatible_count ) {
|
||||
$feature_warnings[] = sprintf(
|
||||
/* translators: %1\$s, %2\$s = printable plugin names */
|
||||
__( '⚠ 2 Incompatible plugins detected (%1$s and %2$s).', 'woocommerce' ),
|
||||
$this->get_plugin_name( $incompatibles[0] ),
|
||||
$this->get_plugin_name( $incompatibles[1] )
|
||||
);
|
||||
} else {
|
||||
$feature_warnings[] = sprintf(
|
||||
/* translators: %1\$s, %2\$s = printable plugin names, %3\$d = plugins count */
|
||||
_n(
|
||||
'⚠ Incompatible plugins detected (%1$s, %2$s and %3$d other).',
|
||||
'⚠ Incompatible plugins detected (%1$s and %2$s plugins and %3$d others).',
|
||||
$incompatible_count - 2,
|
||||
'woocommerce'
|
||||
),
|
||||
$this->get_plugin_name( $incompatibles[0] ),
|
||||
$this->get_plugin_name( $incompatibles[1] ),
|
||||
$incompatible_count - 2
|
||||
);
|
||||
}
|
||||
|
||||
$incompatible_plugins_url = add_query_arg(
|
||||
array(
|
||||
'plugin_status' => 'incompatible_with_feature',
|
||||
'feature_id' => $feature_id,
|
||||
),
|
||||
admin_url( 'plugins.php' )
|
||||
);
|
||||
$feature_warnings[] = sprintf(
|
||||
/* translators: %1$s opening link tag %2$s closing link tag. */
|
||||
__( '%1$sView and manage%2$s', 'woocommerce' ),
|
||||
'<a href="' . esc_url( $incompatible_plugins_url ) . '">',
|
||||
'</a>'
|
||||
);
|
||||
}
|
||||
|
||||
return str_replace( "\n", '<br>', implode( "\n", $feature_warnings ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of the plugins that are excluded from the feature compatibility UI.
|
||||
* These plugins won't be considered as incompatible with any existing feature for the purposes
|
||||
* of displaying compatibility warning in UI, even if they declare incompatibilities explicitly.
|
||||
*
|
||||
* @return string[] Plugin names relative to the root plugins directory.
|
||||
*/
|
||||
public function get_plugins_excluded_from_compatibility_ui() {
|
||||
return $this->plugins_excluded_from_compatibility_ui;
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* A class of utilities for dealing with strings.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Utilities;
|
||||
|
||||
/**
|
||||
* A class of utilities for dealing with strings.
|
||||
*/
|
||||
final class StringUtil {
|
||||
|
||||
/**
|
||||
* Checks to see whether or not a string starts with another.
|
||||
*
|
||||
* @param string $string The string we want to check.
|
||||
* @param string $starts_with The string we're looking for at the start of $string.
|
||||
* @param bool $case_sensitive Indicates whether the comparison should be case-sensitive.
|
||||
*
|
||||
* @return bool True if the $string starts with $starts_with, false otherwise.
|
||||
*/
|
||||
public static function starts_with( string $string, string $starts_with, bool $case_sensitive = true ): bool {
|
||||
$len = strlen( $starts_with );
|
||||
if ( $len > strlen( $string ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$string = substr( $string, 0, $len );
|
||||
|
||||
if ( $case_sensitive ) {
|
||||
return strcmp( $string, $starts_with ) === 0;
|
||||
}
|
||||
|
||||
return strcasecmp( $string, $starts_with ) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see whether or not a string ends with another.
|
||||
*
|
||||
* @param string $string The string we want to check.
|
||||
* @param string $ends_with The string we're looking for at the end of $string.
|
||||
* @param bool $case_sensitive Indicates whether the comparison should be case-sensitive.
|
||||
*
|
||||
* @return bool True if the $string ends with $ends_with, false otherwise.
|
||||
*/
|
||||
public static function ends_with( string $string, string $ends_with, bool $case_sensitive = true ): bool {
|
||||
$len = strlen( $ends_with );
|
||||
if ( $len > strlen( $string ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$string = substr( $string, -$len );
|
||||
|
||||
if ( $case_sensitive ) {
|
||||
return strcmp( $string, $ends_with ) === 0;
|
||||
}
|
||||
|
||||
return strcasecmp( $string, $ends_with ) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if one string is contained into another at any position.
|
||||
*
|
||||
* @param string $string The string we want to check.
|
||||
* @param string $contained The string we're looking for inside $string.
|
||||
* @param bool $case_sensitive Indicates whether the comparison should be case-sensitive.
|
||||
* @return bool True if $contained is contained inside $string, false otherwise.
|
||||
*/
|
||||
public static function contains( string $string, string $contained, bool $case_sensitive = true ): bool {
|
||||
if ( $case_sensitive ) {
|
||||
return false !== strpos( $string, $contained );
|
||||
} else {
|
||||
return false !== stripos( $string, $contained );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of a plugin in the form 'directory/file.php', as in the keys of the array returned by 'get_plugins'.
|
||||
*
|
||||
* @param string $plugin_file_path The path of the main plugin file (can be passed as __FILE__ from the plugin itself).
|
||||
* @return string The name of the plugin in the form 'directory/file.php'.
|
||||
*/
|
||||
public static function plugin_name_from_plugin_file( string $plugin_file_path ): string {
|
||||
return basename( dirname( $plugin_file_path ) ) . DIRECTORY_SEPARATOR . basename( $plugin_file_path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string is null or is empty.
|
||||
*
|
||||
* @param string|null $value The string to check.
|
||||
* @return bool True if the string is null or is empty.
|
||||
*/
|
||||
public static function is_null_or_empty( ?string $value ) {
|
||||
return is_null( $value ) || '' === $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string is null, is empty, or has only whitespace characters
|
||||
* (space, tab, vertical tab, form feed, carriage return, new line)
|
||||
*
|
||||
* @param string|null $value The string to check.
|
||||
* @return bool True if the string is null, is empty, or contains only whitespace characters.
|
||||
*/
|
||||
public static function is_null_or_whitespace( ?string $value ) {
|
||||
return is_null( $value ) || '' === $value || ctype_space( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of values to a list suitable for a SQL "IN" statement
|
||||
* (so comma separated and delimited by parenthesis).
|
||||
* e.g.: [1,2,3] --> (1,2,3)
|
||||
*
|
||||
* @param array $values The values to convert.
|
||||
* @return string A parenthesized and comma-separated string generated from the values.
|
||||
* @throws \InvalidArgumentException Empty values array passed.
|
||||
*/
|
||||
public static function to_sql_list( array $values ) {
|
||||
if ( empty( $values ) ) {
|
||||
throw new \InvalidArgumentException( self::class_name_without_namespace( __CLASS__ ) . '::' . __FUNCTION__ . ': the values array is empty' );
|
||||
}
|
||||
|
||||
return '(' . implode( ',', $values ) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of a class without the namespace.
|
||||
*
|
||||
* @param string $class_name The full class name.
|
||||
* @return string The class name without the namespace.
|
||||
*/
|
||||
public static function class_name_without_namespace( string $class_name ) {
|
||||
// A '?:' would convert this to a one-liner, but WP coding standards disallow these :shrug:.
|
||||
$result = substr( strrchr( $class_name, '\\' ), 1 );
|
||||
return $result ? $result : $class_name;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Utilities;
|
||||
|
||||
use \DateTime;
|
||||
use \DateTimeZone;
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Class with date and time utilities.
|
||||
*/
|
||||
class TimeUtil {
|
||||
|
||||
/**
|
||||
* Instance of a DateTimeZone object representing UTC.
|
||||
*
|
||||
* @var DateTimeZone
|
||||
*/
|
||||
private static DateTimeZone $utc_date_time_zone;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::$utc_date_time_zone = new DateTimeZone( 'UTC' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instance of the DateTimeZone object representing UTC.
|
||||
*
|
||||
* @return DateTimeZone DateTimeZone object representing UTC.
|
||||
*/
|
||||
public static function get_utc_date_time_zone(): DateTimeZone {
|
||||
return self::$utc_date_time_zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string represents a valid date in a given format.
|
||||
*
|
||||
* @param string $date The date string to check.
|
||||
* @param string $format The format to verify the date string against.
|
||||
* @return bool True if $date represents a valid date/time according to $format, false otherwise.
|
||||
*/
|
||||
public static function is_valid_date( string $date, string $format = 'Y-m-d H:i:s' ): bool {
|
||||
$d = DateTime::createFromFormat( $format, $date );
|
||||
return $d && $d->format( $format ) === $date;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user