2019-04-11 18:31:31 +00:00
< ? php
/**
* Register the scripts , styles , and includes needed for pieces of the WooCommerce Admin experience .
* NOTE : DO NOT edit this file in WooCommerce core , this is generated from woocommerce - admin .
*/
2019-08-12 18:11:28 +00:00
namespace Automattic\WooCommerce\Admin ;
2019-09-23 21:47:08 +00:00
use \_WP_Dependency ;
2020-04-10 14:42:03 +00:00
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrdersDataStore ;
2020-04-20 02:04:13 +00:00
use Automattic\WooCommerce\Admin\API\Plugins ;
2021-01-21 00:26:40 +00:00
use Automattic\WooCommerce\Admin\Features\Features ;
2020-11-11 21:27:26 +00:00
use Automattic\WooCommerce\Admin\Features\Navigation\Screen ;
2020-04-24 22:41:57 +00:00
use WC_Marketplace_Suggestions ;
2019-09-23 21:47:08 +00:00
2019-04-11 18:31:31 +00:00
/**
2019-08-12 21:52:09 +00:00
* Loader Class .
2019-04-11 18:31:31 +00:00
*/
2019-08-12 21:52:09 +00:00
class Loader {
2019-05-07 19:48:34 +00:00
/**
* App entry point .
*/
const APP_ENTRY_POINT = 'wc-admin' ;
2019-04-11 18:31:31 +00:00
/**
* Class instance .
*
2019-08-12 21:52:09 +00:00
* @ var Loader instance
2019-04-11 18:31:31 +00:00
*/
protected static $instance = null ;
/**
* An array of classes to load from the includes folder .
*
* @ var array
*/
protected static $classes = array ();
2019-12-10 14:04:39 +00:00
/**
* WordPress capability required to use analytics features .
*
* @ var string
*/
protected static $required_capability = null ;
2019-04-11 18:31:31 +00:00
/**
* Get class instance .
*/
public static function get_instance () {
if ( ! self :: $instance ) {
self :: $instance = new self ();
}
return self :: $instance ;
}
/**
* Constructor .
* Hooks added here should be removed in `wc_admin_initialize` via the feature plugin .
*/
public function __construct () {
2021-01-21 00:26:40 +00:00
Features :: get_instance ();
2019-10-01 23:35:37 +00:00
add_action ( 'init' , array ( __CLASS__ , 'define_tables' ) );
2019-10-02 13:25:31 +00:00
add_action ( 'admin_enqueue_scripts' , array ( __CLASS__ , 'register_scripts' ) );
2019-09-23 21:47:08 +00:00
add_action ( 'admin_enqueue_scripts' , array ( __CLASS__ , 'inject_wc_settings_dependencies' ), 14 );
2019-08-12 18:11:28 +00:00
add_action ( 'admin_enqueue_scripts' , array ( __CLASS__ , 'load_scripts' ), 15 );
2019-10-02 13:25:31 +00:00
// Old settings injection.
2019-09-23 21:47:08 +00:00
add_filter ( 'woocommerce_components_settings' , array ( __CLASS__ , 'add_component_settings' ) );
2019-10-02 13:25:31 +00:00
// New settings injection.
2019-09-23 21:47:08 +00:00
add_filter ( 'woocommerce_shared_settings' , array ( __CLASS__ , 'add_component_settings' ) );
2019-08-12 18:11:28 +00:00
add_filter ( 'admin_body_class' , array ( __CLASS__ , 'add_admin_body_classes' ) );
add_action ( 'admin_menu' , array ( __CLASS__ , 'register_page_handler' ) );
2020-08-27 12:10:23 +00:00
add_action ( 'admin_menu' , array ( __CLASS__ , 'register_store_details_page' ) );
2019-08-12 18:11:28 +00:00
add_filter ( 'admin_title' , array ( __CLASS__ , 'update_admin_title' ) );
add_action ( 'rest_api_init' , array ( __CLASS__ , 'register_user_data' ) );
add_action ( 'in_admin_header' , array ( __CLASS__ , 'embed_page_header' ) );
add_filter ( 'woocommerce_settings_groups' , array ( __CLASS__ , 'add_settings_group' ) );
add_filter ( 'woocommerce_settings-wc_admin' , array ( __CLASS__ , 'add_settings' ) );
add_action ( 'admin_head' , array ( __CLASS__ , 'remove_notices' ) );
2020-08-27 01:46:53 +00:00
add_action ( 'admin_head' , array ( __CLASS__ , 'smart_app_banner' ) );
2019-10-02 13:25:31 +00:00
add_action ( 'admin_notices' , array ( __CLASS__ , 'inject_before_notices' ), - 9999 );
2019-08-12 18:11:28 +00:00
add_action ( 'admin_notices' , array ( __CLASS__ , 'inject_after_notices' ), PHP_INT_MAX );
2019-04-11 18:31:31 +00:00
2020-03-31 14:57:01 +00:00
// Added this hook to delete the field woocommerce_onboarding_homepage_post_id when deleting the homepage.
add_action ( 'trashed_post' , array ( __CLASS__ , 'delete_homepage' ) );
2019-04-11 18:31:31 +00:00
// priority is 20 to run after https://github.com/woocommerce/woocommerce/blob/a55ae325306fc2179149ba9b97e66f32f84fdd9c/includes/admin/class-wc-admin-menus.php#L165.
2019-08-12 18:11:28 +00:00
add_action ( 'admin_head' , array ( __CLASS__ , 'remove_app_entry_page_menu_item' ), 20 );
2019-05-16 13:21:11 +00:00
/*
* Remove the emoji script as it always defaults to replacing emojis with Twemoji images .
* Gutenberg has also disabled emojis . More on that here -> https :// github . com / WordPress / gutenberg / pull / 6151
*/
remove_action ( 'admin_print_scripts' , 'print_emoji_detection_script' );
2020-09-07 16:46:39 +00:00
// Combine JSON translation files (from chunks) when language packs are updated.
add_action ( 'upgrader_process_complete' , array ( __CLASS__ , 'combine_translation_chunk_files' ), 10 , 2 );
2021-01-14 05:22:12 +00:00
// Handler for WooCommerce and WooCommerce Admin plugin activation.
add_action ( 'woocommerce_activated_plugin' , array ( __CLASS__ , 'activated_plugin' ) );
add_action ( 'activated_plugin' , array ( __CLASS__ , 'activated_plugin' ) );
}
/**
* Run when plugin is activated ( can be WooCommerce or WooCommerce Admin ) .
*
* @ param string $filename Activated plugin filename .
*/
public static function activated_plugin ( $filename ) {
$plugin_domain = explode ( '/' , plugin_basename ( __FILE__ ) )[ 0 ];
$activated_plugin_domain = explode ( '/' , $filename )[ 0 ];
// Ensure we're only running only on activation hook that originates from our plugin.
if ( $plugin_domain === $activated_plugin_domain ) {
self :: generate_translation_strings ();
}
2019-04-11 18:31:31 +00:00
}
2019-10-01 23:35:37 +00:00
/**
* Add custom tables to $wpdb object .
*/
public static function define_tables () {
global $wpdb ;
// List of tables without prefixes.
$tables = array (
'wc_category_lookup' => 'wc_category_lookup' ,
);
foreach ( $tables as $name => $table ) {
$wpdb -> $name = $wpdb -> prefix . $table ;
$wpdb -> tables [] = $table ;
}
}
2019-04-11 18:31:31 +00:00
/**
2020-06-11 00:26:20 +00:00
* Gets a build configured array of enabled WooCommerce Admin features / sections .
2019-04-11 18:31:31 +00:00
*
2020-06-11 00:26:20 +00:00
* @ return array Enabled Woocommerce Admin features / sections .
2021-01-21 00:26:40 +00:00
*
* @ deprecated since 1.9 . 0 , use Features :: get_features ()
2019-04-11 18:31:31 +00:00
*/
public static function get_features () {
2021-01-21 00:26:40 +00:00
return Features :: get_features ();
2019-04-11 18:31:31 +00:00
}
2019-12-10 14:04:39 +00:00
/**
* Gets WordPress capability required to use analytics features .
*
* @ return string
*/
public static function get_analytics_capability () {
if ( null === static :: $required_capability ) {
/**
* Filters the required capability to use the analytics features .
*
* @ param string $capability WordPress capability .
*/
static :: $required_capability = apply_filters ( 'woocommerce_analytics_menu_capability' , 'view_woocommerce_reports' );
}
return static :: $required_capability ;
}
/**
* Helper function indicating whether the current user has the required analytics capability .
*
* @ return bool
*/
public static function user_can_analytics () {
return current_user_can ( static :: get_analytics_capability () );
}
2019-04-11 18:31:31 +00:00
/**
* Returns if a specific wc - admin feature is enabled .
*
* @ param string $feature Feature slug .
* @ return bool Returns true if the feature is enabled .
2021-01-21 00:26:40 +00:00
*
* @ deprecated since 1.9 . 0 , use Features :: exists ( $feature )
2019-04-11 18:31:31 +00:00
*/
public static function is_feature_enabled ( $feature ) {
2021-01-21 00:26:40 +00:00
return Features :: exists ( $feature );
2019-04-11 18:31:31 +00:00
}
2020-07-06 17:39:58 +00:00
/**
* Determines if a minified JS file should be served .
*
* @ param boolean $script_debug Only serve unminified files if script debug is on .
* @ return boolean If js asset should use minified version .
*/
public static function should_use_minified_js_file ( $script_debug ) {
2020-09-15 15:36:58 +00:00
// minified files are only shipped in non-core versions of wc-admin, return false if minified files are not available.
2021-01-21 00:26:40 +00:00
if ( ! Features :: exists ( 'minified-js' ) ) {
2020-09-15 15:36:58 +00:00
return false ;
2020-07-06 17:39:58 +00:00
}
// Otherwise we will serve un-minified files if SCRIPT_DEBUG is on, or if anything truthy is passed in-lieu of SCRIPT_DEBUG.
return ! $script_debug ;
}
2019-04-11 18:31:31 +00:00
/**
* Gets the URL to an asset file .
*
2020-04-29 18:01:27 +00:00
* @ param string $file File name ( without extension ) .
* @ param string $ext File extension .
2019-04-11 18:31:31 +00:00
* @ return string URL to asset .
*/
2020-04-29 18:01:27 +00:00
public static function get_url ( $file , $ext ) {
$suffix = '' ;
// Potentially enqueue minified JavaScript.
if ( 'js' === $ext ) {
2020-07-06 17:39:58 +00:00
$script_debug = defined ( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ;
2020-07-22 18:24:33 +00:00
$suffix = self :: should_use_minified_js_file ( $script_debug ) ? '.min' : '' ;
2020-04-29 18:01:27 +00:00
}
return plugins_url ( self :: get_path ( $ext ) . $file . $suffix . '.' . $ext , WC_ADMIN_PLUGIN_FILE );
2019-04-11 18:31:31 +00:00
}
/**
* Gets the file modified time as a cache buster if we ' re in dev mode , or the plugin version otherwise .
*
2020-04-29 18:01:27 +00:00
* @ param string $ext File extension .
2019-04-11 18:31:31 +00:00
* @ return string The cache buster value to use for the given file .
*/
2020-04-29 18:01:27 +00:00
public static function get_file_version ( $ext ) {
2019-04-11 18:31:31 +00:00
if ( defined ( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
2020-04-29 18:01:27 +00:00
return filemtime ( WC_ADMIN_ABSPATH . self :: get_path ( $ext ) );
2019-04-11 18:31:31 +00:00
}
return WC_ADMIN_VERSION_NUMBER ;
}
/**
* Gets the path for the asset depending on file type .
*
2020-04-29 18:01:27 +00:00
* @ param string $ext File extension .
2019-04-11 18:31:31 +00:00
* @ return string Folder path of asset .
*/
2020-04-29 18:01:27 +00:00
private static function get_path ( $ext ) {
return ( 'css' === $ext ) ? WC_ADMIN_DIST_CSS_FOLDER : WC_ADMIN_DIST_JS_FOLDER ;
2019-04-11 18:31:31 +00:00
}
/**
2020-09-14 23:44:46 +00:00
* Connects existing WooCommerce pages .
2019-04-11 18:31:31 +00:00
*
* @ todo The entry point for the embed needs moved to this class as well .
*/
public static function register_page_handler () {
2019-08-12 18:22:32 +00:00
require_once WC_ADMIN_ABSPATH . 'includes/connect-existing-pages.php' ;
2019-04-11 18:31:31 +00:00
}
2020-07-16 15:17:10 +00:00
/**
2020-08-27 12:10:23 +00:00
* Registers the store details ( profiler ) page .
2020-07-16 15:17:10 +00:00
*/
2020-08-27 12:10:23 +00:00
public static function register_store_details_page () {
2020-07-16 15:17:10 +00:00
wc_admin_register_page (
array (
2020-08-27 12:10:23 +00:00
'title' => __ ( 'Setup Wizard' , 'woocommerce-admin' ),
2020-07-22 18:24:33 +00:00
'parent' => '' ,
2020-08-27 12:10:23 +00:00
'path' => '/setup-wizard' ,
2020-07-16 15:17:10 +00:00
)
);
}
2019-04-11 18:31:31 +00:00
/**
2019-05-07 19:48:34 +00:00
* Remove the menu item for the app entry point page .
2019-04-11 18:31:31 +00:00
*/
2019-05-07 19:48:34 +00:00
public static function remove_app_entry_page_menu_item () {
2019-04-11 18:31:31 +00:00
global $submenu ;
// User does not have capabilites to see the submenu.
2019-04-29 09:57:33 +00:00
if ( ! current_user_can ( 'manage_woocommerce' ) || empty ( $submenu [ 'woocommerce' ] ) ) {
2019-04-11 18:31:31 +00:00
return ;
}
$wc_admin_key = null ;
foreach ( $submenu [ 'woocommerce' ] as $submenu_key => $submenu_item ) {
2019-05-07 19:48:34 +00:00
// Our app entry page menu item has no title.
if ( is_null ( $submenu_item [ 0 ] ) && self :: APP_ENTRY_POINT === $submenu_item [ 2 ] ) {
2019-04-11 18:31:31 +00:00
$wc_admin_key = $submenu_key ;
break ;
}
}
if ( ! $wc_admin_key ) {
return ;
}
unset ( $submenu [ 'woocommerce' ][ $wc_admin_key ] );
}
/**
* Registers all the neccessary scripts and styles to show the admin experience .
*/
public static function register_scripts () {
2019-04-26 18:39:37 +00:00
if ( ! function_exists ( 'wp_set_script_translations' ) ) {
return ;
}
2020-04-29 18:01:27 +00:00
$js_file_version = self :: get_file_version ( 'js' );
$css_file_version = self :: get_file_version ( 'css' );
2019-04-11 18:31:31 +00:00
wp_register_script (
'wc-csv' ,
2020-04-29 18:01:27 +00:00
self :: get_url ( 'csv-export/index' , 'js' ),
2019-12-17 13:35:51 +00:00
array ( 'moment' ),
2020-04-29 18:01:27 +00:00
$js_file_version ,
2019-04-11 18:31:31 +00:00
true
);
wp_register_script (
'wc-currency' ,
2020-04-29 18:01:27 +00:00
self :: get_url ( 'currency/index' , 'js' ),
2019-04-11 18:31:31 +00:00
array ( 'wc-number' ),
2020-04-29 18:01:27 +00:00
$js_file_version ,
2019-04-11 18:31:31 +00:00
true
);
wp_set_script_translations ( 'wc-currency' , 'woocommerce-admin' );
2020-10-30 06:52:52 +00:00
wp_register_script (
'wc-customer-effort-score' ,
self :: get_url ( 'customer-effort-score/index' , 'js' ),
2020-12-01 22:36:13 +00:00
array (
'wp-components' ,
'wp-compose' ,
'wp-data' ,
'wp-element' ,
'wp-i18n' ,
'wp-notices' ,
),
2020-10-30 06:52:52 +00:00
$js_file_version ,
true
);
2019-04-11 18:31:31 +00:00
wp_register_script (
'wc-navigation' ,
2020-04-29 18:01:27 +00:00
self :: get_url ( 'navigation/index' , 'js' ),
2020-12-21 01:57:55 +00:00
array ( 'wp-url' , 'wp-hooks' , 'wp-element' , 'wp-data' , 'moment' , 'wp-components' ),
2020-04-29 18:01:27 +00:00
$js_file_version ,
2019-04-11 18:31:31 +00:00
true
);
2020-11-09 07:17:08 +00:00
// NOTE: This should be removed when Gutenberg is updated and
// the notices package is removed from WooCommerce Admin.
wp_register_script (
'wc-notices' ,
self :: get_url ( 'notices/index' , 'js' ),
array (),
$js_file_version ,
true
);
2019-04-11 18:31:31 +00:00
wp_register_script (
'wc-number' ,
2020-04-29 18:01:27 +00:00
self :: get_url ( 'number/index' , 'js' ),
2019-04-11 18:31:31 +00:00
array (),
2020-04-29 18:01:27 +00:00
$js_file_version ,
2019-04-11 18:31:31 +00:00
true
);
2020-08-20 04:59:52 +00:00
wp_register_script (
'wc-tracks' ,
self :: get_url ( 'tracks/index' , 'js' ),
array (),
$js_file_version ,
true
);
2019-04-11 18:31:31 +00:00
wp_register_script (
'wc-date' ,
2020-04-29 18:01:27 +00:00
self :: get_url ( 'date/index' , 'js' ),
2019-12-17 13:35:51 +00:00
array ( 'moment' , 'wp-date' , 'wp-i18n' ),
2020-04-29 18:01:27 +00:00
$js_file_version ,
2019-04-11 18:31:31 +00:00
true
);
2020-03-25 03:20:17 +00:00
wp_register_script (
'wc-store-data' ,
2020-04-29 18:01:27 +00:00
self :: get_url ( 'data/index' , 'js' ),
2020-11-23 23:21:26 +00:00
array ( 'wp-data' ),
2020-04-29 18:01:27 +00:00
$js_file_version ,
2020-03-25 03:20:17 +00:00
true
);
2019-04-11 18:31:31 +00:00
wp_set_script_translations ( 'wc-date' , 'woocommerce-admin' );
wp_register_script (
'wc-components' ,
2020-04-29 18:01:27 +00:00
self :: get_url ( 'components/index' , 'js' ),
2019-04-11 18:31:31 +00:00
array (
2019-12-17 13:35:51 +00:00
'moment' ,
2019-06-20 08:53:02 +00:00
'wp-api-fetch' ,
2019-04-11 18:31:31 +00:00
'wp-data' ,
2020-03-25 03:20:17 +00:00
'wp-data-controls' ,
2019-04-11 18:31:31 +00:00
'wp-element' ,
'wp-hooks' ,
2019-11-19 19:17:15 +00:00
'wp-html-entities' ,
2019-04-11 18:31:31 +00:00
'wp-i18n' ,
'wp-keycodes' ,
'wc-csv' ,
'wc-currency' ,
2020-10-30 06:52:52 +00:00
'wc-customer-effort-score' ,
2019-04-11 18:31:31 +00:00
'wc-date' ,
'wc-navigation' ,
2020-11-09 07:17:08 +00:00
// NOTE: This should be removed when Gutenberg is updated and
// the notices package is removed from WooCommerce Admin.
'wc-notices' ,
2019-04-11 18:31:31 +00:00
'wc-number' ,
2020-03-25 03:20:17 +00:00
'wc-store-data' ,
2020-12-21 01:57:55 +00:00
'wp-components' ,
2019-04-11 18:31:31 +00:00
),
2020-04-29 18:01:27 +00:00
$js_file_version ,
2019-04-11 18:31:31 +00:00
true
);
wp_set_script_translations ( 'wc-components' , 'woocommerce-admin' );
wp_register_style (
'wc-components' ,
2020-04-29 18:01:27 +00:00
self :: get_url ( 'components/style' , 'css' ),
2019-11-20 20:36:44 +00:00
array (),
2020-04-29 18:01:27 +00:00
$css_file_version
2019-04-11 18:31:31 +00:00
);
wp_style_add_data ( 'wc-components' , 'rtl' , 'replace' );
wp_register_style (
'wc-components-ie' ,
2020-04-29 18:01:27 +00:00
self :: get_url ( 'components/ie' , 'css' ),
2019-11-20 20:36:44 +00:00
array (),
2020-04-29 18:01:27 +00:00
$css_file_version
2019-04-11 18:31:31 +00:00
);
wp_style_add_data ( 'wc-components-ie' , 'rtl' , 'replace' );
2020-10-30 06:52:52 +00:00
wp_register_style (
'wc-customer-effort-score' ,
self :: get_url ( 'customer-effort-score/style' , 'css' ),
array (),
$css_file_version
);
wp_style_add_data ( 'wc-customer-effort-score' , 'rtl' , 'replace' );
2019-04-11 18:31:31 +00:00
wp_register_script (
WC_ADMIN_APP ,
2020-04-29 18:01:27 +00:00
self :: get_url ( 'app/index' , 'js' ),
2020-06-10 16:46:46 +00:00
array (
'wp-core-data' ,
2020-12-21 01:57:55 +00:00
'wp-components' ,
2020-06-10 16:46:46 +00:00
'wc-components' ,
'wp-date' ,
2020-10-13 01:40:53 +00:00
'wp-plugins' ,
2020-08-20 04:59:52 +00:00
'wc-tracks' ,
2020-10-22 03:01:25 +00:00
'wc-navigation' ,
2020-06-10 16:46:46 +00:00
),
2020-04-29 18:01:27 +00:00
$js_file_version ,
2019-04-11 18:31:31 +00:00
true
);
2020-04-29 18:01:27 +00:00
wp_localize_script (
WC_ADMIN_APP ,
'wcAdminAssets' ,
array (
2020-10-06 12:58:15 +00:00
'path' => plugins_url ( self :: get_path ( 'js' ), WC_ADMIN_PLUGIN_FILE ),
'version' => $js_file_version ,
2020-04-29 18:01:27 +00:00
)
);
2019-04-11 18:31:31 +00:00
wp_set_script_translations ( WC_ADMIN_APP , 'woocommerce-admin' );
2020-06-10 23:06:17 +00:00
// The "app" RTL files are in a different format than the components.
$rtl = is_rtl () ? '.rtl' : '' ;
2019-04-11 18:31:31 +00:00
wp_register_style (
WC_ADMIN_APP ,
2020-06-10 23:06:17 +00:00
self :: get_url ( " app/style { $rtl } " , 'css' ),
2020-12-21 01:57:55 +00:00
array ( 'wc-components' , 'wc-customer-effort-score' , 'wp-components' ),
2020-04-29 18:01:27 +00:00
$css_file_version
2019-04-11 18:31:31 +00:00
);
2019-07-18 10:11:21 +00:00
2019-10-08 22:02:26 +00:00
wp_register_style (
'wc-admin-ie' ,
2020-06-10 23:06:17 +00:00
self :: get_url ( " ie/style { $rtl } " , 'css' ),
2019-10-08 22:02:26 +00:00
array ( WC_ADMIN_APP ),
2020-04-29 18:01:27 +00:00
$css_file_version
2019-10-08 22:02:26 +00:00
);
2019-07-18 10:11:21 +00:00
wp_register_style (
'wc-material-icons' ,
'https://fonts.googleapis.com/icon?family=Material+Icons+Outlined' ,
array (),
2020-04-29 18:01:27 +00:00
$css_file_version
2019-07-18 10:11:21 +00:00
);
2019-04-11 18:31:31 +00:00
}
2020-08-05 19:29:05 +00:00
/**
* Generate a filename to cache translations from JS chunks .
*
* @ param string $domain Text domain .
* @ param string $locale Locale being retrieved .
* @ return string Filename .
*/
public static function get_combined_translation_filename ( $domain , $locale ) {
2020-09-07 16:46:39 +00:00
$filename = implode ( '-' , array ( $domain , $locale , WC_ADMIN_APP ) ) . '.json' ;
2020-08-05 19:29:05 +00:00
return $filename ;
}
/**
* Find and combine translation chunk files .
*
* Only targets files that aren ' t represented by a registered script ( e . g . not passed to wp_register_script ()) .
*
* @ param string $lang_dir Path to language files .
* @ param string $domain Text domain .
* @ param string $locale Locale being retrieved .
* @ return array Combined translation chunk data .
*/
public static function get_translation_chunk_data ( $lang_dir , $domain , $locale ) {
2020-09-07 16:46:39 +00:00
// So long as this function is called during the 'upgrader_process_complete' action,
// the filesystem object should be hooked up.
2020-08-05 19:29:05 +00:00
global $wp_filesystem ;
// Grab all JSON files in the current language pack.
$json_i18n_filenames = glob ( $lang_dir . $domain . '-' . $locale . '-*.json' );
$combined_translation_data = array ();
2020-09-07 16:46:39 +00:00
if ( false === $json_i18n_filenames ) {
return $combined_translation_data ;
}
2020-08-05 19:29:05 +00:00
foreach ( $json_i18n_filenames as $json_filename ) {
if ( ! $wp_filesystem -> is_readable ( $json_filename ) ) {
continue ;
}
$file_contents = $wp_filesystem -> get_contents ( $json_filename );
$chunk_data = \json_decode ( $file_contents , true );
if ( empty ( $chunk_data ) ) {
continue ;
}
if ( ! isset ( $chunk_data [ 'comment' ][ 'reference' ] ) ) {
continue ;
}
$reference_file = $chunk_data [ 'comment' ][ 'reference' ];
// Only combine "app" files (not scripts registered with WP).
if (
false === strpos ( $reference_file , 'dist/chunks/' ) &&
false === strpos ( $reference_file , 'dist/app/index.js' )
) {
continue ;
}
if ( empty ( $combined_translation_data ) ) {
// Use the first translation file as the base structure.
$combined_translation_data = $chunk_data ;
} else {
// Combine all messages from all chunk files.
$combined_translation_data [ 'locale_data' ][ 'messages' ] = array_merge (
$combined_translation_data [ 'locale_data' ][ 'messages' ],
$chunk_data [ 'locale_data' ][ 'messages' ]
);
}
}
// Remove inaccurate reference comment.
unset ( $combined_translation_data [ 'comment' ] );
return $combined_translation_data ;
}
2021-01-14 05:22:12 +00:00
/**
* Combine translation chunks when plugin is activated .
*
* This function combines JSON translation data auto - extracted by GlotPress
* from Webpack - generated JS chunks into a single file . This is necessary
* since the JS chunks are not known to WordPress via wp_register_script ()
* and wp_set_script_translations () .
*/
public static function generate_translation_strings () {
$plugin_domain = explode ( '/' , plugin_basename ( __FILE__ ) )[ 0 ];
$locale = determine_locale ();
$lang_dir = WP_LANG_DIR . '/plugins/' ;
// Bail early if not localized.
if ( 'en_US' === $locale ) {
return ;
}
if ( ! function_exists ( 'get_filesystem_method' ) ) {
require_once ABSPATH . 'wp-admin/includes/file.php' ;
}
$access_type = get_filesystem_method ();
if ( 'direct' === $access_type ) {
\WP_Filesystem ();
self :: build_and_save_translations ( $lang_dir , $plugin_domain , $locale );
} else {
// I'm reluctant to add support for other filesystems here as it would require
// user's input on activating plugin - which I don't think is common.
return ;
}
}
/**
* Combine and save translations for a specific locale .
*
* Note that this assumes \WP_Filesystem is already initialized with write access .
*
* @ param string $language_dir Path to language files .
* @ param string $plugin_domain Text domain .
* @ param string $locale Locale being retrieved .
*/
public static function build_and_save_translations ( $language_dir , $plugin_domain , $locale ) {
global $wp_filesystem ;
$translations_from_chunks = self :: get_translation_chunk_data ( $language_dir , $plugin_domain , $locale );
if ( empty ( $translations_from_chunks ) ) {
return ;
}
$cache_filename = self :: get_combined_translation_filename ( $plugin_domain , $locale );
$chunk_translations_json = wp_json_encode ( $translations_from_chunks );
// Cache combined translations strings to a file.
$wp_filesystem -> put_contents ( $language_dir . $cache_filename , $chunk_translations_json );
}
2020-08-05 19:29:05 +00:00
/**
2020-09-07 16:46:39 +00:00
* Combine translation chunks when files are updated .
2020-08-05 19:29:05 +00:00
*
* This function combines JSON translation data auto - extracted by GlotPress
* from Webpack - generated JS chunks into a single file that can be used in
* subsequent requests . This is necessary since the JS chunks are not known
* to WordPress via wp_register_script () and wp_set_script_translations () .
*
2020-09-07 16:46:39 +00:00
* @ param Language_Pack_Upgrader $instance Upgrader instance .
* @ param array $hook_extra Info about the upgraded language packs .
*/
public static function combine_translation_chunk_files ( $instance , $hook_extra ) {
if (
! is_a ( $instance , 'Language_Pack_Upgrader' ) ||
! isset ( $hook_extra [ 'translations' ] ) ||
! is_array ( $hook_extra [ 'translations' ] )
) {
return ;
}
// Make sure we're handing the correct domain (could be woocommerce or woocommerce-admin).
$plugin_domain = explode ( '/' , plugin_basename ( __FILE__ ) )[ 0 ];
$locales = array ();
$language_dir = WP_LANG_DIR . '/plugins/' ;
// Gather the locales that were updated in this operation.
foreach ( $hook_extra [ 'translations' ] as $translation ) {
if (
'plugin' === $translation [ 'type' ] &&
$plugin_domain === $translation [ 'slug' ]
) {
$locales [] = $translation [ 'language' ];
}
}
// Build combined translation files for all updated locales.
foreach ( $locales as $locale ) {
2021-01-14 05:22:12 +00:00
// So long as this function is hooked to the 'upgrader_process_complete' action,
// WP_Filesystem should be hooked up to be able to call build_and_save_translations.
self :: build_and_save_translations ( $language_dir , $plugin_domain , $locale );
2020-09-07 16:46:39 +00:00
}
}
/**
* Load translation strings from language packs for dynamic imports .
*
2020-08-05 19:29:05 +00:00
* @ param string $file File location for the script being translated .
* @ param string $handle Script handle .
* @ param string $domain Text domain .
*
2020-09-07 16:46:39 +00:00
* @ return string New file location for the script being translated .
2020-08-05 19:29:05 +00:00
*/
2020-09-07 16:46:39 +00:00
public static function load_script_translation_file ( $file , $handle , $domain ) {
2020-08-05 19:29:05 +00:00
// Make sure the main app script is being loaded.
if ( WC_ADMIN_APP !== $handle ) {
2020-09-07 16:46:39 +00:00
return $file ;
2020-08-05 19:29:05 +00:00
}
// Make sure we're handing the correct domain (could be woocommerce or woocommerce-admin).
$plugin_domain = explode ( '/' , plugin_basename ( __FILE__ ) )[ 0 ];
if ( $plugin_domain !== $domain ) {
2020-09-07 16:46:39 +00:00
return $file ;
2020-08-05 19:29:05 +00:00
}
$locale = determine_locale ();
$cache_filename = self :: get_combined_translation_filename ( $domain , $locale );
2020-09-07 16:46:39 +00:00
return WP_LANG_DIR . '/plugins/' . $cache_filename ;
2020-08-05 19:29:05 +00:00
}
2019-04-11 18:31:31 +00:00
/**
* Loads the required scripts on the correct pages .
*/
public static function load_scripts () {
2020-03-31 23:38:42 +00:00
if ( ! self :: is_admin_or_embed_page () ) {
2019-04-11 18:31:31 +00:00
return ;
}
2019-12-10 14:04:39 +00:00
if ( ! static :: user_can_analytics () ) {
return ;
}
2020-08-05 19:29:05 +00:00
// Grab translation strings from Webpack-generated chunks.
2020-09-07 16:46:39 +00:00
add_filter ( 'load_script_translation_file' , array ( __CLASS__ , 'load_script_translation_file' ), 10 , 3 );
2020-08-05 19:29:05 +00:00
2019-04-11 18:31:31 +00:00
wp_enqueue_script ( WC_ADMIN_APP );
wp_enqueue_style ( WC_ADMIN_APP );
2019-07-18 10:11:21 +00:00
wp_enqueue_style ( 'wc-material-icons' );
2019-04-11 18:31:31 +00:00
// Use server-side detection to prevent unneccessary stylesheet loading in other browsers.
2019-11-20 14:52:24 +00:00
$user_agent = isset ( $_SERVER [ 'HTTP_USER_AGENT' ] ) ? $_SERVER [ 'HTTP_USER_AGENT' ] : '' ; // phpcs:ignore sanitization ok.
2019-04-11 18:31:31 +00:00
preg_match ( '/MSIE (.*?);/' , $user_agent , $matches );
if ( count ( $matches ) < 2 ) {
preg_match ( '/Trident\/\d{1,2}.\d{1,2}; rv:([0-9]*)/' , $user_agent , $matches );
}
if ( count ( $matches ) > 1 ) {
wp_enqueue_style ( 'wc-components-ie' );
2019-10-08 22:02:26 +00:00
wp_enqueue_style ( 'wc-admin-ie' );
2019-04-11 18:31:31 +00:00
}
2020-04-29 18:01:27 +00:00
// Preload our assets.
self :: output_header_preload_tags ();
}
/**
* Render a preload link tag for a dependency , optionally
2020-07-23 19:02:31 +00:00
* checked against a provided allowlist .
2020-04-29 18:01:27 +00:00
*
* See : https :// macarthur . me / posts / preloading - javascript - in - wordpress
*
* @ param WP_Dependency $dependency The WP_Dependency being preloaded .
* @ param string $type Dependency type - 'script' or 'style' .
2020-07-23 19:02:31 +00:00
* @ param array $allowlist Optional . List of allowed dependency handles .
2020-04-29 18:01:27 +00:00
*/
2020-07-23 19:02:31 +00:00
public static function maybe_output_preload_link_tag ( $dependency , $type , $allowlist = array () ) {
if ( ! empty ( $allowlist ) && ! in_array ( $dependency -> handle , $allowlist , true ) ) {
2020-04-29 18:01:27 +00:00
return ;
}
$source = $dependency -> ver ? add_query_arg ( 'ver' , $dependency -> ver , $dependency -> src ) : $dependency -> src ;
echo '<link rel="preload" href="' , esc_url ( $source ), '" as="' , esc_attr ( $type ), '" />' , " \n " ;
}
/**
* Output a preload link tag for dependencies ( and their sub dependencies )
2020-07-23 19:02:31 +00:00
* with an optional allowlist .
2020-04-29 18:01:27 +00:00
*
* See : https :// macarthur . me / posts / preloading - javascript - in - wordpress
*
* @ param string $type Dependency type - 'script' or 'style' .
2020-07-23 19:02:31 +00:00
* @ param array $allowlist Optional . List of allowed dependency handles .
2020-04-29 18:01:27 +00:00
*/
2020-07-23 19:02:31 +00:00
public static function output_header_preload_tags_for_type ( $type , $allowlist = array () ) {
2020-04-29 18:01:27 +00:00
if ( 'script' === $type ) {
$dependencies_of_type = wp_scripts ();
} elseif ( 'style' === $type ) {
$dependencies_of_type = wp_styles ();
} else {
return ;
}
foreach ( $dependencies_of_type -> queue as $dependency_handle ) {
2020-07-23 19:02:31 +00:00
$dependency = $dependencies_of_type -> query ( $dependency_handle , 'registered' );
if ( false === $dependency ) {
continue ;
}
2020-04-29 18:01:27 +00:00
// Preload the subdependencies first.
foreach ( $dependency -> deps as $sub_dependency_handle ) {
2020-07-23 19:02:31 +00:00
$sub_dependency = $dependencies_of_type -> query ( $sub_dependency_handle , 'registered' );
if ( $sub_dependency ) {
self :: maybe_output_preload_link_tag ( $sub_dependency , $type , $allowlist );
}
2020-04-29 18:01:27 +00:00
}
2020-07-23 19:02:31 +00:00
self :: maybe_output_preload_link_tag ( $dependency , $type , $allowlist );
2020-04-29 18:01:27 +00:00
}
}
/**
* Output preload link tags for all enqueued stylesheets and scripts .
*
* See : https :// macarthur . me / posts / preloading - javascript - in - wordpress
*/
public static function output_header_preload_tags () {
$wc_admin_scripts = array (
WC_ADMIN_APP ,
'wc-components' ,
);
$wc_admin_styles = array (
WC_ADMIN_APP ,
'wc-components' ,
'wc-components-ie' ,
'wc-admin-ie' ,
'wc-material-icons' ,
);
// Preload styles.
self :: output_header_preload_tags_for_type ( 'style' , $wc_admin_styles );
// Preload scripts.
self :: output_header_preload_tags_for_type ( 'script' , $wc_admin_scripts );
2019-04-11 18:31:31 +00:00
}
2020-03-31 23:38:42 +00:00
/**
* Returns true if we are on a JS powered admin page or
* a " classic " ( non JS app ) powered admin page ( an embedded page ) .
*/
public static function is_admin_or_embed_page () {
return self :: is_admin_page () || self :: is_embed_page ();
}
2019-04-11 18:31:31 +00:00
/**
* Returns true if we are on a JS powered admin page .
*/
public static function is_admin_page () {
2019-05-07 22:08:18 +00:00
return wc_admin_is_registered_page ();
2019-04-11 18:31:31 +00:00
}
/**
* Returns true if we are on a " classic " ( non JS app ) powered admin page .
*
2019-10-01 23:35:37 +00:00
* TODO : See usage in `admin.php` . This needs refactored and implemented properly in core .
2019-04-11 18:31:31 +00:00
*/
public static function is_embed_page () {
2021-01-21 00:26:40 +00:00
return wc_admin_is_connected_page () || ( ! self :: is_admin_page () && class_exists ( 'Automattic\WooCommerce\Admin\Features\Navigation\Screen' ) && Screen :: is_woocommerce_page () );
2019-04-11 18:31:31 +00:00
}
/**
* Returns breadcrumbs for the current page .
*/
private static function get_embed_breadcrumbs () {
2019-05-08 14:41:35 +00:00
return wc_admin_get_breadcrumbs ();
2019-04-11 18:31:31 +00:00
}
/**
* Outputs breadcrumbs via PHP for the initial load of an embedded page .
*
* @ param array $section Section to create breadcrumb from .
*/
2020-10-06 20:42:46 +00:00
private static function output_heading ( $section ) {
2019-12-10 14:04:39 +00:00
if ( ! static :: user_can_analytics () ) {
return ;
}
2020-10-06 20:42:46 +00:00
echo esc_html ( $section );
2019-04-11 18:31:31 +00:00
}
/**
* Set up a div for the header embed to render into .
* The initial contents here are meant as a place loader for when the PHP page initialy loads .
*/
public static function embed_page_header () {
2020-04-27 09:30:32 +00:00
if ( ! self :: is_admin_page () && ! self :: is_embed_page () ) {
2019-04-11 18:31:31 +00:00
return ;
}
2019-12-10 14:04:39 +00:00
if ( ! static :: user_can_analytics () ) {
return ;
}
2020-04-27 09:30:32 +00:00
if ( ! self :: is_embed_page () ) {
return ;
}
2019-04-11 18:31:31 +00:00
$sections = self :: get_embed_breadcrumbs ();
$sections = is_array ( $sections ) ? $sections : array ( $sections );
?>
2019-05-23 09:29:14 +00:00
< div id = " woocommerce-embedded-root " class = " is-embed-loading " >
2019-04-11 18:31:31 +00:00
< div class = " woocommerce-layout " >
< div class = " woocommerce-layout__header is-embed-loading " >
2020-10-06 20:42:46 +00:00
< h1 class = " woocommerce-layout__header-heading " >
< ? php self :: output_heading ( end ( $sections ) ); ?>
2019-04-11 18:31:31 +00:00
</ h1 >
</ div >
</ div >
</ div >
< ? php
}
/**
* Adds body classes to the main wp - admin wrapper , allowing us to better target elements in specific scenarios .
*
* @ param string $admin_body_class Body class to add .
*/
public static function add_admin_body_classes ( $admin_body_class = '' ) {
2020-03-31 23:38:42 +00:00
if ( ! self :: is_admin_or_embed_page () ) {
2019-04-11 18:31:31 +00:00
return $admin_body_class ;
}
$classes = explode ( ' ' , trim ( $admin_body_class ) );
$classes [] = 'woocommerce-page' ;
if ( self :: is_embed_page () ) {
$classes [] = 'woocommerce-embed-page' ;
}
2020-05-06 12:56:23 +00:00
/**
* Some routes or features like onboarding hide the wp - admin navigation and masterbar .
* Setting `woocommerce_admin_is_loading` to true allows us to premeptively hide these
* elements while the JS app loads .
* This class needs to be removed by those feature components ( like < ProfileWizard /> ) .
*
* @ param bool $is_loading If WooCommerce Admin is loading a fullscreen view .
*/
$is_loading = apply_filters ( 'woocommerce_admin_is_loading' , false );
if ( self :: is_admin_page () && $is_loading ) {
2019-05-28 10:38:01 +00:00
$classes [] = 'woocommerce-admin-is-loading' ;
}
2019-04-11 18:31:31 +00:00
$admin_body_class = implode ( ' ' , array_unique ( $classes ) );
return " $admin_body_class " ;
}
2020-08-27 01:46:53 +00:00
/**
* Adds an iOS " Smart App Banner " for display on iOS Safari .
* See https :// developer . apple . com / library / archive / documentation / AppleApplications / Reference / SafariWebContent / PromotingAppswithAppBanners / PromotingAppswithAppBanners . html
*/
public static function smart_app_banner () {
2020-10-09 02:17:11 +00:00
if ( self :: is_admin_or_embed_page () ) {
2020-08-27 01:46:53 +00:00
echo "
< meta name = 'apple-itunes-app' content = 'app-id=1389130815' >
" ;
}
}
2019-04-11 18:31:31 +00:00
/**
* Removes notices that should not be displayed on WC Admin pages .
*/
public static function remove_notices () {
2020-03-31 23:38:42 +00:00
if ( ! self :: is_admin_or_embed_page () ) {
2019-04-11 18:31:31 +00:00
return ;
}
// Hello Dolly.
if ( function_exists ( 'hello_dolly' ) ) {
remove_action ( 'admin_notices' , 'hello_dolly' );
}
}
/**
* Runs before admin notices action and hides them .
*/
public static function inject_before_notices () {
2020-03-31 23:38:42 +00:00
if ( ! self :: is_admin_or_embed_page () ) {
2019-04-11 18:31:31 +00:00
return ;
}
2020-03-31 23:38:42 +00:00
// Wrap the notices in a hidden div to prevent flickering before
// they are moved elsewhere in the page by WordPress Core.
2019-04-11 18:31:31 +00:00
echo '<div class="woocommerce-layout__notice-list-hide" id="wp__notice-list">' ;
2020-03-31 23:38:42 +00:00
if ( self :: is_admin_page () ) {
// Capture all notices and hide them. WordPress Core looks for
// `.wp-header-end` and appends notices after it if found.
// https://github.com/WordPress/WordPress/blob/f6a37e7d39e2534d05b9e542045174498edfe536/wp-admin/js/common.js#L737 .
echo '<div class="wp-header-end" id="woocommerce-layout__notice-catcher"></div>' ;
}
2019-04-11 18:31:31 +00:00
}
/**
* Runs after admin notices and closes div .
*/
public static function inject_after_notices () {
2020-03-31 23:38:42 +00:00
if ( ! self :: is_admin_or_embed_page () ) {
2019-04-11 18:31:31 +00:00
return ;
}
2020-03-31 23:38:42 +00:00
// Close the hidden div used to prevent notices from flickering before
// they are inserted elsewhere in the page.
2019-04-11 18:31:31 +00:00
echo '</div>' ;
}
/**
* Edits Admin title based on section of wc - admin .
*
* @ param string $admin_title Modifies admin title .
* @ todo Can we do some URL rewriting so we can figure out which page they are on server side ?
*/
public static function update_admin_title ( $admin_title ) {
2019-08-02 14:32:52 +00:00
if (
! did_action ( 'current_screen' ) ||
2020-01-20 17:34:24 +00:00
! self :: is_admin_page ()
2019-08-02 14:32:52 +00:00
) {
2019-04-11 18:31:31 +00:00
return $admin_title ;
}
2019-05-08 14:41:35 +00:00
$sections = self :: get_embed_breadcrumbs ();
$pieces = array ();
2019-04-11 18:31:31 +00:00
2019-05-08 14:41:35 +00:00
foreach ( $sections as $section ) {
$pieces [] = is_array ( $section ) ? $section [ 1 ] : $section ;
2019-04-11 18:31:31 +00:00
}
2019-05-08 14:41:35 +00:00
$pieces = array_reverse ( $pieces );
$title = implode ( ' ‹ ' , $pieces );
2019-04-11 18:31:31 +00:00
/* translators: %1$s: updated title, %2$s: blog info name */
2019-05-08 14:41:35 +00:00
return sprintf ( __ ( '%1$s ‹ %2$s' , 'woocommerce-admin' ), $title , get_bloginfo ( 'name' ) );
2019-04-11 18:31:31 +00:00
}
/**
* Set up a div for the app to render into .
*/
public static function page_wrapper () {
?>
< div class = " wrap " >
< div id = " root " ></ div >
</ div >
< ? php
}
/**
* Hooks extra neccessary data into the component settings array already set in WooCommerce core .
*
* @ param array $settings Array of component settings .
* @ return array Array of component settings .
*/
public static function add_component_settings ( $settings ) {
2019-09-25 17:59:11 +00:00
if ( ! is_admin () ) {
return $settings ;
}
2019-10-02 13:25:31 +00:00
2019-09-23 21:47:08 +00:00
if ( ! function_exists ( 'wc_blocks_container' ) ) {
global $wp_locale ;
// inject data not available via older versions of wc_blocks/woo.
2019-10-02 13:25:31 +00:00
$settings [ 'orderStatuses' ] = self :: get_order_statuses ( wc_get_order_statuses () );
2020-01-17 00:42:02 +00:00
$settings [ 'stockStatuses' ] = self :: get_order_statuses ( wc_get_product_stock_status_options () );
2019-10-02 13:25:31 +00:00
$settings [ 'currency' ] = self :: get_currency_settings ();
$settings [ 'locale' ] = [
'siteLocale' => isset ( $settings [ 'siteLocale' ] )
2019-09-23 21:47:08 +00:00
? $settings [ 'siteLocale' ]
: get_locale (),
2019-10-02 13:25:31 +00:00
'userLocale' => isset ( $settings [ 'l10n' ][ 'userLocale' ] )
2019-09-23 21:47:08 +00:00
? $settings [ 'l10n' ][ 'userLocale' ]
: get_user_locale (),
'weekdaysShort' => isset ( $settings [ 'l10n' ][ 'weekdaysShort' ] )
? $settings [ 'l10n' ][ 'weekdaysShort' ]
2019-10-02 13:25:31 +00:00
: array_values ( $wp_locale -> weekday_abbrev ),
2019-09-23 21:47:08 +00:00
];
}
2019-09-25 17:59:11 +00:00
2019-04-11 18:31:31 +00:00
$preload_data_endpoints = apply_filters ( 'woocommerce_component_settings_preload_endpoints' , array ( '/wc/v3' ) );
2020-04-16 23:58:36 +00:00
if ( class_exists ( 'Jetpack' ) ) {
$preload_data_endpoints [ 'jetpackStatus' ] = '/jetpack/v4/connection' ;
}
2019-04-11 18:31:31 +00:00
if ( ! empty ( $preload_data_endpoints ) ) {
$preload_data = array_reduce (
array_values ( $preload_data_endpoints ),
'rest_preload_api_request'
);
}
2019-10-03 16:03:29 +00:00
$preload_options = apply_filters ( 'woocommerce_admin_preload_options' , array () );
if ( ! empty ( $preload_options ) ) {
foreach ( $preload_options as $option ) {
$settings [ 'preloadOptions' ][ $option ] = get_option ( $option );
}
}
2019-11-05 00:05:20 +00:00
$preload_settings = apply_filters ( 'woocommerce_admin_preload_settings' , array () );
if ( ! empty ( $preload_settings ) ) {
2019-11-07 18:31:02 +00:00
$setting_options = new \WC_REST_Setting_Options_V2_Controller ();
2019-11-05 00:05:20 +00:00
foreach ( $preload_settings as $group ) {
$group_settings = $setting_options -> get_group_settings ( $group );
$preload_settings = [];
2019-11-07 18:31:02 +00:00
foreach ( $group_settings as $option ) {
$preload_settings [ $option [ 'id' ] ] = $option [ 'value' ];
2019-11-05 00:05:20 +00:00
}
$settings [ 'preloadSettings' ][ $group ] = $preload_settings ;
}
}
2020-06-10 16:46:46 +00:00
$user_controller = new \WP_REST_Users_Controller ();
$user_response = $user_controller -> get_current_item ( new \WP_REST_Request () );
$current_user_data = is_wp_error ( $user_response ) ? ( object ) array () : $user_response -> get_data ();
2019-06-27 09:21:43 +00:00
$settings [ 'currentUserData' ] = $current_user_data ;
$settings [ 'reviewsEnabled' ] = get_option ( 'woocommerce_enable_reviews' );
$settings [ 'manageStock' ] = get_option ( 'woocommerce_manage_stock' );
$settings [ 'commentModeration' ] = get_option ( 'comment_moderation' );
$settings [ 'notifyLowStockAmount' ] = get_option ( 'woocommerce_notify_low_stock_amount' );
2019-04-18 08:38:42 +00:00
// @todo On merge, once plugin images are added to core WooCommerce, `wcAdminAssetUrl` can be retired,
// and `wcAssetUrl` can be used in its place throughout the codebase.
2020-08-24 21:51:41 +00:00
$settings [ 'wcAdminAssetUrl' ] = plugins_url ( 'images/' , dirname ( __DIR__ ) . '/woocommerce-admin.php' );
$settings [ 'wcVersion' ] = WC_VERSION ;
$settings [ 'siteUrl' ] = site_url ();
2021-01-29 12:44:38 +00:00
$settings [ 'shopUrl' ] = get_permalink ( wc_get_page_id ( 'shop' ) );
2020-08-24 21:51:41 +00:00
$settings [ 'dateFormat' ] = get_option ( 'date_format' );
$settings [ 'plugins' ] = array (
2020-04-16 23:58:36 +00:00
'installedPlugins' => PluginsHelper :: get_installed_plugin_slugs (),
2020-04-29 18:01:27 +00:00
'activePlugins' => Plugins :: get_active_plugins (),
2020-04-16 23:58:36 +00:00
);
2020-03-23 22:57:16 +00:00
// Plugins that depend on changing the translation work on the server but not the client -
// WooCommerce Branding is an example of this - so pass through the translation of
// 'WooCommerce' to wcSettings.
$settings [ 'woocommerceTranslation' ] = __ ( 'WooCommerce' , 'woocommerce-admin' );
2020-04-10 14:42:03 +00:00
// We may have synced orders with a now-unregistered status.
// E.g An extension that added statuses is now inactive or removed.
$settings [ 'unregisteredOrderStatuses' ] = self :: get_unregistered_order_statuses ();
2020-09-25 13:57:48 +00:00
// The separator used for attributes found in Variation titles.
$settings [ 'variationTitleAttributesSeparator' ] = apply_filters ( 'woocommerce_product_variation_title_attributes_separator' , ' - ' , new \WC_Product () );
2019-04-11 18:31:31 +00:00
if ( ! empty ( $preload_data_endpoints ) ) {
2019-09-23 21:47:08 +00:00
$settings [ 'dataEndpoints' ] = isset ( $settings [ 'dataEndpoints' ] )
? $settings [ 'dataEndpoints' ]
: [];
2019-04-11 18:31:31 +00:00
foreach ( $preload_data_endpoints as $key => $endpoint ) {
2019-06-13 20:54:10 +00:00
// Handle error case: rest_do_request() doesn't guarantee success.
if ( empty ( $preload_data [ $endpoint ] ) ) {
$settings [ 'dataEndpoints' ][ $key ] = array ();
} else {
$settings [ 'dataEndpoints' ][ $key ] = $preload_data [ $endpoint ][ 'body' ];
}
2019-04-11 18:31:31 +00:00
}
}
$settings = self :: get_custom_settings ( $settings );
if ( self :: is_embed_page () ) {
$settings [ 'embedBreadcrumbs' ] = self :: get_embed_breadcrumbs ();
}
2020-04-24 22:41:57 +00:00
$settings [ 'allowMarketplaceSuggestions' ] = WC_Marketplace_Suggestions :: allow_suggestions ();
2020-05-20 05:33:58 +00:00
$settings [ 'connectNonce' ] = wp_create_nonce ( 'connect' );
2020-04-24 22:41:57 +00:00
2019-04-11 18:31:31 +00:00
return $settings ;
}
/**
* Format order statuses by removing a leading 'wc-' if present .
*
* @ param array $statuses Order statuses .
* @ return array formatted statuses .
*/
public static function get_order_statuses ( $statuses ) {
$formatted_statuses = array ();
foreach ( $statuses as $key => $value ) {
$formatted_key = preg_replace ( '/^wc-/' , '' , $key );
$formatted_statuses [ $formatted_key ] = $value ;
}
return $formatted_statuses ;
}
2020-04-10 14:42:03 +00:00
/**
* Get all order statuses present in analytics tables that aren ' t registered .
*
* @ return array Unregistered order statuses .
*/
public static function get_unregistered_order_statuses () {
$registered_statuses = wc_get_order_statuses ();
$all_synced_statuses = OrdersDataStore :: get_all_statuses ();
$unregistered_statuses = array_diff ( $all_synced_statuses , array_keys ( $registered_statuses ) );
$formatted_status_keys = self :: get_order_statuses ( array_fill_keys ( $unregistered_statuses , '' ) );
$formatted_statuses = array_keys ( $formatted_status_keys );
return array_combine ( $formatted_statuses , $formatted_statuses );
}
2019-04-11 18:31:31 +00:00
/**
* Register the admin settings for use in the WC REST API
*
* @ param array $groups Array of setting groups .
* @ return array
*/
public static function add_settings_group ( $groups ) {
$groups [] = array (
'id' => 'wc_admin' ,
'label' => __ ( 'WooCommerce Admin' , 'woocommerce-admin' ),
'description' => __ ( 'Settings for WooCommerce admin reporting.' , 'woocommerce-admin' ),
);
return $groups ;
}
/**
* Add WC Admin specific settings
*
* @ param array $settings Array of settings in wc admin group .
* @ return array
*/
public static function add_settings ( $settings ) {
2020-04-10 14:42:03 +00:00
$unregistered_statuses = self :: get_unregistered_order_statuses ();
$registered_statuses = self :: get_order_statuses ( wc_get_order_statuses () );
$all_statuses = array_merge ( $unregistered_statuses , $registered_statuses );
2019-04-11 18:31:31 +00:00
$settings [] = array (
'id' => 'woocommerce_excluded_report_order_statuses' ,
'option_key' => 'woocommerce_excluded_report_order_statuses' ,
'label' => __ ( 'Excluded report order statuses' , 'woocommerce-admin' ),
'description' => __ ( 'Statuses that should not be included when calculating report totals.' , 'woocommerce-admin' ),
'default' => array ( 'pending' , 'cancelled' , 'failed' ),
'type' => 'multiselect' ,
2020-04-10 14:42:03 +00:00
'options' => $all_statuses ,
2019-04-11 18:31:31 +00:00
);
$settings [] = array (
'id' => 'woocommerce_actionable_order_statuses' ,
'option_key' => 'woocommerce_actionable_order_statuses' ,
'label' => __ ( 'Actionable order statuses' , 'woocommerce-admin' ),
'description' => __ ( 'Statuses that require extra action on behalf of the store admin.' , 'woocommerce-admin' ),
'default' => array ( 'processing' , 'on-hold' ),
'type' => 'multiselect' ,
2020-04-10 14:42:03 +00:00
'options' => $all_statuses ,
2019-04-11 18:31:31 +00:00
);
2019-05-22 21:43:04 +00:00
$settings [] = array (
'id' => 'woocommerce_default_date_range' ,
'option_key' => 'woocommerce_default_date_range' ,
'label' => __ ( 'Default Date Range' , 'woocommerce-admin' ),
'description' => __ ( 'Default Date Range' , 'woocommerce-admin' ),
'default' => 'period=month&compare=previous_year' ,
'type' => 'text' ,
);
2019-04-11 18:31:31 +00:00
return $settings ;
}
/**
* Gets custom settings used for WC Admin .
*
* @ param array $settings Array of settings to merge into .
* @ return array
*/
public static function get_custom_settings ( $settings ) {
2019-08-12 18:11:28 +00:00
$wc_rest_settings_options_controller = new \WC_REST_Setting_Options_Controller ();
2019-04-11 18:31:31 +00:00
$wc_admin_group_settings = $wc_rest_settings_options_controller -> get_group_settings ( 'wc_admin' );
$settings [ 'wcAdminSettings' ] = array ();
foreach ( $wc_admin_group_settings as $setting ) {
2019-07-05 14:12:03 +00:00
if ( ! empty ( $setting [ 'id' ] ) ) {
2019-04-11 18:31:31 +00:00
$settings [ 'wcAdminSettings' ][ $setting [ 'id' ] ] = $setting [ 'value' ];
}
}
return $settings ;
}
/**
* Return an object defining the currecy options for the site ' s current currency
*
* @ return array Settings for the current currency {
* Array of settings .
*
* @ type string $code Currency code .
* @ type string $precision Number of decimals .
* @ type string $symbol Symbol for currency .
* }
*/
public static function get_currency_settings () {
$code = get_woocommerce_currency ();
return apply_filters (
'wc_currency_settings' ,
array (
2019-09-23 21:47:08 +00:00
'code' => $code ,
'precision' => wc_get_price_decimals (),
'symbol' => html_entity_decode ( get_woocommerce_currency_symbol ( $code ) ),
'symbolPosition' => get_option ( 'woocommerce_currency_pos' ),
'decimalSeparator' => wc_get_price_decimal_separator (),
'thousandSeparator' => wc_get_price_thousand_separator (),
'priceFormat' => html_entity_decode ( get_woocommerce_price_format () ),
2019-04-11 18:31:31 +00:00
)
);
}
/**
* Registers WooCommerce specific user data to the WordPress user API .
*/
public static function register_user_data () {
register_rest_field (
'user' ,
'woocommerce_meta' ,
array (
2019-08-12 18:11:28 +00:00
'get_callback' => array ( __CLASS__ , 'get_user_data_values' ),
'update_callback' => array ( __CLASS__ , 'update_user_data_values' ),
2019-04-11 18:31:31 +00:00
'schema' => null ,
)
);
}
/**
2019-08-12 21:52:09 +00:00
* For all the registered user data fields ( Loader :: get_user_data_fields ), fetch the data
2019-04-11 18:31:31 +00:00
* for returning via the REST API .
*
* @ param WP_User $user Current user .
*/
public static function get_user_data_values ( $user ) {
$values = array ();
foreach ( self :: get_user_data_fields () as $field ) {
2020-01-17 00:08:29 +00:00
$values [ $field ] = self :: get_user_data_field ( $user [ 'id' ], $field );
2019-04-11 18:31:31 +00:00
}
return $values ;
}
/**
2019-08-12 21:52:09 +00:00
* For all the registered user data fields ( Loader :: get_user_data_fields ), update the data
2019-04-11 18:31:31 +00:00
* for the REST API .
*
* @ param array $values The new values for the meta .
* @ param WP_User $user The current user .
* @ param string $field_id The field id for the user meta .
*/
public static function update_user_data_values ( $values , $user , $field_id ) {
if ( empty ( $values ) || ! is_array ( $values ) || 'woocommerce_meta' !== $field_id ) {
return ;
}
$fields = self :: get_user_data_fields ();
$updates = array ();
foreach ( $values as $field => $value ) {
if ( in_array ( $field , $fields , true ) ) {
$updates [ $field ] = $value ;
2020-01-17 00:08:29 +00:00
self :: update_user_data_field ( $user -> ID , $field , $value );
2019-04-11 18:31:31 +00:00
}
}
return $updates ;
}
/**
* We store some WooCommerce specific user meta attached to users endpoint ,
* so that we can track certain preferences or values such as the inbox activity panel last open time .
* Additional fields can be added in the function below , and then used via wc - admin ' s currentUser data .
*
* @ return array Fields to expose over the WP user endpoint .
*/
public static function get_user_data_fields () {
2019-12-05 23:06:11 +00:00
return apply_filters ( 'woocommerce_admin_get_user_data_fields' , array () );
2019-04-11 18:31:31 +00:00
}
2019-09-23 21:47:08 +00:00
2020-01-17 00:08:29 +00:00
/**
* Helper to update user data fields .
*
* @ param int $user_id User ID .
* @ param string $field Field name .
* @ param mixed $value Field value .
*/
public static function update_user_data_field ( $user_id , $field , $value ) {
update_user_meta ( $user_id , 'woocommerce_admin_' . $field , $value );
}
/**
* Helper to retrive user data fields .
*
* Migrates old key prefixes as well .
*
* @ param int $user_id User ID .
* @ param string $field Field name .
* @ return mixed The user field value .
*/
public static function get_user_data_field ( $user_id , $field ) {
$meta_value = get_user_meta ( $user_id , 'woocommerce_admin_' . $field , true );
// Migrate old meta values (prefix changed from `wc_admin_` to `woocommerce_admin_`).
if ( '' === $meta_value ) {
$old_meta_value = get_user_meta ( $user_id , 'wc_admin_' . $field , true );
if ( '' !== $old_meta_value ) {
self :: update_user_data_field ( $user_id , $field , $old_meta_value );
delete_user_meta ( $user_id , 'wc_admin_' . $field );
$meta_value = $old_meta_value ;
}
}
return $meta_value ;
}
2019-09-23 21:47:08 +00:00
/**
* Injects wp - shared - settings as a dependency if it ' s present .
*/
public static function inject_wc_settings_dependencies () {
if ( wp_script_is ( 'wc-settings' , 'registered' ) ) {
$handles_for_injection = [
'wc-csv' ,
'wc-currency' ,
2020-10-30 06:52:52 +00:00
'wc-customer-effort-score' ,
2019-09-23 21:47:08 +00:00
'wc-navigation' ,
2020-11-09 07:17:08 +00:00
// NOTE: This should be removed when Gutenberg is updated and
// the notices package is removed from WooCommerce Admin.
'wc-notices' ,
2019-09-23 21:47:08 +00:00
'wc-number' ,
'wc-date' ,
'wc-components' ,
2020-08-20 04:59:52 +00:00
'wc-tracks' ,
2019-09-23 21:47:08 +00:00
];
2019-10-02 13:25:31 +00:00
foreach ( $handles_for_injection as $handle ) {
2019-09-23 21:47:08 +00:00
$script = wp_scripts () -> query ( $handle , 'registered' );
if ( $script instanceof _WP_Dependency ) {
$script -> deps [] = 'wc-settings' ;
}
}
}
}
2020-03-31 14:57:01 +00:00
/**
* Delete woocommerce_onboarding_homepage_post_id field when the homepage is deleted
*
* @ param int $post_id The deleted post id .
*/
public static function delete_homepage ( $post_id ) {
if ( 'page' !== get_post_type ( $post_id ) ) {
return ;
}
$homepage_id = intval ( get_option ( 'woocommerce_onboarding_homepage_post_id' , false ) );
if ( $homepage_id === $post_id ) {
delete_option ( 'woocommerce_onboarding_homepage_post_id' );
}
}
2019-04-11 18:31:31 +00:00
}