This commit is contained in:
Rachit Bhargava
2024-01-10 11:53:33 -05:00
parent 83d223b0df
commit 054b4fffc9
16481 changed files with 0 additions and 3473867 deletions

View File

@@ -1,86 +0,0 @@
<?php
/**
* WooCommerce Async Product Editor Category Field.
*/
namespace Automattic\WooCommerce\Admin\Features\AsyncProductEditorCategoryField;
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Automattic\WooCommerce\Admin\PageController;
/**
* Loads assets related to the async category field for the product editor.
*/
class Init {
const FEATURE_ID = 'async-product-editor-category-field';
/**
* Constructor
*/
public function __construct() {
if ( Features::is_enabled( self::FEATURE_ID ) ) {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
add_filter( 'woocommerce_taxonomy_args_product_cat', array( $this, 'add_metabox_args' ) );
}
}
/**
* Adds meta_box_cb callback arguments for custom metabox.
*
* @param array $args Category taxonomy args.
* @return array $args category taxonomy args.
*/
public function add_metabox_args( $args ) {
if ( ! isset( $args['meta_box_cb'] ) ) {
$args['meta_box_cb'] = 'WC_Meta_Box_Product_Categories::output';
$args['meta_box_sanitize_cb'] = 'taxonomy_meta_box_sanitize_cb_checkboxes';
}
return $args;
}
/**
* Enqueue scripts needed for the product form block editor.
*/
public function enqueue_scripts() {
if ( ! PageController::is_embed_page() ) {
return;
}
WCAdminAssets::register_script( 'wp-admin-scripts', 'product-category-metabox', true );
wp_localize_script(
'wc-admin-product-category-metabox',
'wc_product_category_metabox_params',
array(
'search_categories_nonce' => wp_create_nonce( 'search-categories' ),
'search_taxonomy_terms_nonce' => wp_create_nonce( 'search-taxonomy-terms' ),
)
);
wp_enqueue_script( 'product-category-metabox' );
}
/**
* Enqueue styles needed for the rich text editor.
*/
public function enqueue_styles() {
if ( ! PageController::is_embed_page() ) {
return;
}
$version = Constants::get_constant( 'WC_VERSION' );
wp_register_style(
'woocommerce_admin_product_category_metabox_styles',
WCAdminAssets::get_url( 'product-category-metabox/style', 'css' ),
array(),
$version
);
wp_style_add_data( 'woocommerce_admin_product_category_metabox_styles', 'rtl', 'replace' );
wp_enqueue_style( 'woocommerce_admin_product_category_metabox_styles' );
}
}

View File

@@ -1,380 +0,0 @@
<?php
/**
* Features loader for features developed in WooCommerce Admin.
*/
namespace Automattic\WooCommerce\Admin\Features;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Internal\Admin\Loader;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
/**
* Features Class.
*/
class Features {
/**
* Class instance.
*
* @var Loader instance
*/
protected static $instance = null;
/**
* Optional features
*
* @var array
*/
protected static $optional_features = array(
'navigation' => array( 'default' => 'no' ),
'settings' => array( 'default' => 'no' ),
'analytics' => array( 'default' => 'yes' ),
'remote-inbox-notifications' => array( 'default' => 'yes' ),
);
/**
* Beta features
*
* @var array
*/
protected static $beta_features = array(
'navigation',
'new-product-management-experience',
'settings',
);
/**
* Get class instance.
*/
public static function get_instance() {
if ( ! self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor.
*/
public function __construct() {
$this->register_internal_class_aliases();
// Load feature before WooCommerce update hooks.
add_action( 'init', array( __CLASS__, 'load_features' ), 4 );
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'maybe_load_beta_features_modal' ) );
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'load_scripts' ), 15 );
add_filter( 'admin_body_class', array( __CLASS__, 'add_admin_body_classes' ) );
add_filter( 'update_option_woocommerce_allow_tracking', array( __CLASS__, 'maybe_disable_features' ), 10, 2 );
}
/**
* Gets a build configured array of enabled WooCommerce Admin features/sections, but does not respect optionally disabled features.
*
* @return array Enabled Woocommerce Admin features/sections.
*/
public static function get_features() {
return apply_filters( 'woocommerce_admin_features', array() );
}
/**
* Gets the optional feature options as an associative array that can be toggled on or off.
*
* @return array
*/
public static function get_optional_feature_options() {
$features = [];
foreach ( array_keys( self::$optional_features ) as $optional_feature_key ) {
$feature_class = self::get_feature_class( $optional_feature_key );
if ( $feature_class ) {
$features[ $optional_feature_key ] = $feature_class::TOGGLE_OPTION_NAME;
}
}
return $features;
}
/**
* Returns if a specific wc-admin feature exists in the current environment.
*
* @param string $feature Feature slug.
* @return bool Returns true if the feature exists.
*/
public static function exists( $feature ) {
$features = self::get_features();
return in_array( $feature, $features, true );
}
/**
* Get the feature class as a string.
*
* @param string $feature Feature name.
* @return string|null
*/
public static function get_feature_class( $feature ) {
$feature = str_replace( '-', '', ucwords( strtolower( $feature ), '-' ) );
$feature_class = 'Automattic\\WooCommerce\\Admin\\Features\\' . $feature;
if ( class_exists( $feature_class ) ) {
return $feature_class;
}
// Handle features contained in subdirectory.
if ( class_exists( $feature_class . '\\Init' ) ) {
return $feature_class . '\\Init';
}
return null;
}
/**
* Class loader for enabled WooCommerce Admin features/sections.
*/
public static function load_features() {
$features = self::get_features();
foreach ( $features as $feature ) {
$feature_class = self::get_feature_class( $feature );
if ( $feature_class ) {
new $feature_class();
}
}
}
/**
* Gets a build configured array of enabled WooCommerce Admin respecting optionally disabled features.
*
* @return array Enabled Woocommerce Admin features/sections.
*/
public static function get_available_features() {
$features = self::get_features();
$optional_feature_keys = array_keys( self::$optional_features );
$optional_features_unavailable = [];
/**
* Filter allowing WooCommerce Admin optional features to be disabled.
*
* @param bool $disabled False.
*/
if ( apply_filters( 'woocommerce_admin_disabled', false ) ) {
return array_values( array_diff( $features, $optional_feature_keys ) );
}
foreach ( $optional_feature_keys as $optional_feature_key ) {
$feature_class = self::get_feature_class( $optional_feature_key );
if ( $feature_class ) {
$default = isset( self::$optional_features[ $optional_feature_key ]['default'] ) ?
self::$optional_features[ $optional_feature_key ]['default'] :
'no';
// Check if the feature is currently being enabled, if it is continue.
/* phpcs:disable WordPress.Security.NonceVerification */
$feature_option = $feature_class::TOGGLE_OPTION_NAME;
if ( isset( $_POST[ $feature_option ] ) && '1' === $_POST[ $feature_option ] ) {
continue;
}
if ( 'yes' !== get_option( $feature_class::TOGGLE_OPTION_NAME, $default ) ) {
$optional_features_unavailable[] = $optional_feature_key;
}
}
}
return array_values( array_diff( $features, $optional_features_unavailable ) );
}
/**
* Check if a feature is enabled.
*
* @param string $feature Feature slug.
* @return bool
*/
public static function is_enabled( $feature ) {
$available_features = self::get_available_features();
return in_array( $feature, $available_features, true );
}
/**
* Enable a toggleable optional feature.
*
* @param string $feature Feature name.
* @return bool
*/
public static function enable( $feature ) {
$features = self::get_optional_feature_options();
if ( isset( $features[ $feature ] ) ) {
update_option( $features[ $feature ], 'yes' );
return true;
}
return false;
}
/**
* Disable a toggleable optional feature.
*
* @param string $feature Feature name.
* @return bool
*/
public static function disable( $feature ) {
$features = self::get_optional_feature_options();
if ( isset( $features[ $feature ] ) ) {
update_option( $features[ $feature ], 'no' );
return true;
}
return false;
}
/**
* Disable features when opting out of tracking.
*
* @param string $old_value Old value.
* @param string $value New value.
*/
public static function maybe_disable_features( $old_value, $value ) {
if ( 'yes' === $value ) {
return;
}
foreach ( self::$beta_features as $feature ) {
self::disable( $feature );
}
}
/**
* Adds the Features section to the advanced tab of WooCommerce Settings
*
* @deprecated 7.0 The WooCommerce Admin features are now handled by the WooCommerce features engine (see the FeaturesController class).
*
* @param array $sections Sections.
* @return array
*/
public static function add_features_section( $sections ) {
return $sections;
}
/**
* Adds the Features settings.
*
* @deprecated 7.0 The WooCommerce Admin features are now handled by the WooCommerce features engine (see the FeaturesController class).
*
* @param array $settings Settings.
* @param string $current_section Current section slug.
* @return array
*/
public static function add_features_settings( $settings, $current_section ) {
return $settings;
}
/**
* Conditionally loads the beta features tracking modal.
*
* @param string $hook Page hook.
*/
public static function maybe_load_beta_features_modal( $hook ) {
if (
'woocommerce_page_wc-settings' !== $hook ||
! isset( $_GET['tab'] ) || 'advanced' !== $_GET['tab'] || // phpcs:ignore CSRF ok.
! isset( $_GET['section'] ) || 'features' !== $_GET['section'] // phpcs:ignore CSRF ok.
) {
return;
}
$tracking_enabled = get_option( 'woocommerce_allow_tracking', 'no' );
if ( empty( self::$beta_features ) ) {
return;
}
if ( 'yes' === $tracking_enabled ) {
return;
}
$rtl = is_rtl() ? '.rtl' : '';
wp_enqueue_style(
'wc-admin-beta-features-tracking-modal',
WCAdminAssets::get_url( "beta-features-tracking-modal/style{$rtl}", 'css' ),
array( 'wp-components' ),
WCAdminAssets::get_file_version( 'css' )
);
wp_enqueue_script(
'wc-admin-beta-features-tracking-modal',
WCAdminAssets::get_url( 'wp-admin-scripts/beta-features-tracking-modal', 'js' ),
array( 'wp-i18n', 'wp-element', WC_ADMIN_APP ),
WCAdminAssets::get_file_version( 'js' ),
true
);
}
/**
* Loads the required scripts on the correct pages.
*/
public static function load_scripts() {
if ( ! PageController::is_admin_or_embed_page() ) {
return;
}
$features = self::get_features();
$enabled_features = array();
foreach ( $features as $key ) {
$enabled_features[ $key ] = self::is_enabled( $key );
}
wp_add_inline_script( WC_ADMIN_APP, 'window.wcAdminFeatures = ' . wp_json_encode( $enabled_features ), 'before' );
}
/**
* 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 = '' ) {
if ( ! PageController::is_admin_or_embed_page() ) {
return $admin_body_class;
}
$classes = explode( ' ', trim( $admin_body_class ) );
$features = self::get_features();
foreach ( $features as $feature_key ) {
$classes[] = sanitize_html_class( 'woocommerce-feature-enabled-' . $feature_key );
}
$admin_body_class = implode( ' ', array_unique( $classes ) );
return " $admin_body_class ";
}
/**
* Alias internal features classes to make them backward compatible.
* We've moved our feature classes to src-internal as part of merging this
* repository with WooCommerce Core to form a monorepo.
* See https://wp.me/p90Yrv-2HY for details.
*/
private function register_internal_class_aliases() {
$aliases = array(
// new class => original class (this will be aliased).
'Automattic\WooCommerce\Internal\Admin\WCPayPromotion\Init' => 'Automattic\WooCommerce\Admin\Features\WcPayPromotion\Init',
'Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions\Init' => 'Automattic\WooCommerce\Admin\Features\RemoteFreeExtensions\Init',
'Automattic\WooCommerce\Internal\Admin\ActivityPanels' => 'Automattic\WooCommerce\Admin\Features\ActivityPanels',
'Automattic\WooCommerce\Internal\Admin\Analytics' => 'Automattic\WooCommerce\Admin\Features\Analytics',
'Automattic\WooCommerce\Internal\Admin\Coupons' => 'Automattic\WooCommerce\Admin\Features\Coupons',
'Automattic\WooCommerce\Internal\Admin\CouponsMovedTrait' => 'Automattic\WooCommerce\Admin\Features\CouponsMovedTrait',
'Automattic\WooCommerce\Internal\Admin\CustomerEffortScoreTracks' => 'Automattic\WooCommerce\Admin\Features\CustomerEffortScoreTracks',
'Automattic\WooCommerce\Internal\Admin\Homescreen' => 'Automattic\WooCommerce\Admin\Features\Homescreen',
'Automattic\WooCommerce\Internal\Admin\Marketing' => 'Automattic\WooCommerce\Admin\Features\Marketing',
'Automattic\WooCommerce\Internal\Admin\MobileAppBanner' => 'Automattic\WooCommerce\Admin\Features\MobileAppBanner',
'Automattic\WooCommerce\Internal\Admin\RemoteInboxNotifications' => 'Automattic\WooCommerce\Admin\Features\RemoteInboxNotifications',
'Automattic\WooCommerce\Internal\Admin\SettingsNavigationFeature' => 'Automattic\WooCommerce\Admin\Features\Settings',
'Automattic\WooCommerce\Internal\Admin\ShippingLabelBanner' => 'Automattic\WooCommerce\Admin\Features\ShippingLabelBanner',
'Automattic\WooCommerce\Internal\Admin\ShippingLabelBannerDisplayRules' => 'Automattic\WooCommerce\Admin\Features\ShippingLabelBannerDisplayRules',
'Automattic\WooCommerce\Internal\Admin\WcPayWelcomePage' => 'Automattic\WooCommerce\Admin\Features\WcPayWelcomePage',
);
foreach ( $aliases as $new_class => $orig_class ) {
class_alias( $new_class, $orig_class );
}
}
}

View File

@@ -1,463 +0,0 @@
<?php
/**
* WooCommerce Navigation Core Menu
*
* @package Woocommerce Admin
*/
namespace Automattic\WooCommerce\Admin\Features\Navigation;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\Navigation\Menu;
use Automattic\WooCommerce\Admin\Features\Navigation\Screen;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists;
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
/**
* CoreMenu class. Handles registering Core menu items.
*/
class CoreMenu {
/**
* Class instance.
*
* @var Menu instance
*/
protected static $instance = null;
/**
* Get class instance.
*/
final public static function instance() {
if ( ! static::$instance ) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Init.
*/
public function init() {
add_action( 'admin_menu', array( $this, 'register_post_types' ) );
// Add this after we've finished migrating menu items to avoid hiding these items.
add_action( 'admin_menu', array( $this, 'add_dashboard_menu_items' ), PHP_INT_MAX );
}
/**
* Add registered admin settings as menu items.
*/
public static function get_setting_items() {
// Let the Settings feature add pages to the navigation if enabled.
if ( Features::is_enabled( 'settings' ) ) {
return array();
}
// Calling this method adds pages to the below tabs filter on non-settings pages.
\WC_Admin_Settings::get_settings_pages();
$tabs = apply_filters( 'woocommerce_settings_tabs_array', array() );
$menu_items = array();
$order = 0;
foreach ( $tabs as $key => $setting ) {
$order += 10;
$menu_items[] = (
array(
'parent' => 'woocommerce-settings',
'title' => $setting,
'capability' => 'manage_woocommerce',
'id' => 'settings-' . $key,
'url' => 'admin.php?page=wc-settings&tab=' . $key,
'order' => $order,
)
);
}
return $menu_items;
}
/**
* Get unfulfilled order count
*
* @return array
*/
public static function get_shop_order_count() {
$status_counts = array_map( 'wc_orders_count', array( 'processing', 'on-hold' ) );
return array_sum( $status_counts );
}
/**
* Get all menu categories.
*
* @return array
*/
public static function get_categories() {
$analytics_enabled = Features::is_enabled( 'analytics' );
return array(
array(
'title' => __( 'Orders', 'woocommerce' ),
'id' => 'woocommerce-orders',
'badge' => self::get_shop_order_count(),
'order' => 10,
),
array(
'title' => __( 'Products', 'woocommerce' ),
'id' => 'woocommerce-products',
'order' => 20,
),
$analytics_enabled ?
array(
'title' => __( 'Analytics', 'woocommerce' ),
'id' => 'woocommerce-analytics',
'order' => 30,
) : null,
$analytics_enabled ?
array(
'title' => __( 'Reports', 'woocommerce' ),
'id' => 'woocommerce-reports',
'parent' => 'woocommerce-analytics',
'order' => 200,
) : null,
array(
'title' => __( 'Marketing', 'woocommerce' ),
'id' => 'woocommerce-marketing',
'order' => 40,
),
array(
'title' => __( 'Settings', 'woocommerce' ),
'id' => 'woocommerce-settings',
'menuId' => 'secondary',
'order' => 20,
'url' => 'admin.php?page=wc-settings',
),
array(
'title' => __( 'Tools', 'woocommerce' ),
'id' => 'woocommerce-tools',
'menuId' => 'secondary',
'order' => 30,
),
);
}
/**
* Get all menu items.
*
* @return array
*/
public static function get_items() {
$order_items = self::get_order_menu_items();
$product_items = Menu::get_post_type_items( 'product', array( 'parent' => 'woocommerce-products' ) );
$product_tag_items = Menu::get_taxonomy_items(
'product_tag',
array(
'parent' => 'woocommerce-products',
'order' => 30,
)
);
$product_cat_items = Menu::get_taxonomy_items(
'product_cat',
array(
'parent' => 'woocommerce-products',
'order' => 20,
)
);
$coupon_items = Menu::get_post_type_items( 'shop_coupon', array( 'parent' => 'woocommerce-marketing' ) );
$setting_items = self::get_setting_items();
$wca_items = array();
$wca_pages = \Automattic\WooCommerce\Admin\PageController::get_instance()->get_pages();
foreach ( $wca_pages as $page ) {
if ( ! isset( $page['nav_args'] ) ) {
continue;
}
$path = isset( $page['path'] ) ? $page['path'] : null;
$item = array_merge(
array(
'id' => $page['id'],
'url' => $path,
'title' => $page['title'][0],
'capability' => isset( $page['capability'] ) ? $page['capability'] : 'manage_woocommerce',
),
$page['nav_args']
);
// Don't allow top-level items to be added to the primary menu.
if ( ! isset( $item['parent'] ) || 'woocommerce' === $item['parent'] ) {
$item['menuId'] = 'plugins';
}
$wca_items[] = $item;
}
$home_item = array();
$setup_tasks_remaining = TaskLists::setup_tasks_remaining();
if ( defined( '\Automattic\WooCommerce\Internal\Admin\Homescreen::MENU_SLUG' ) ) {
$home_item = array(
'id' => 'woocommerce-home',
'title' => __( 'Home', 'woocommerce' ),
'url' => \Automattic\WooCommerce\Internal\Admin\Homescreen::MENU_SLUG,
'order' => 0,
'matchExpression' => 'page=wc-admin((?!path=).)*$',
'badge' => $setup_tasks_remaining ? $setup_tasks_remaining : null,
);
}
$customers_item = array();
if ( Features::is_enabled( 'analytics' ) ) {
$customers_item = array(
'id' => 'woocommerce-analytics-customers',
'title' => __( 'Customers', 'woocommerce' ),
'url' => 'wc-admin&path=/customers',
'order' => 50,
);
}
$add_product_mvp = array();
if ( Features::is_enabled( 'new-product-management-experience' ) ) {
$add_product_mvp = array(
'id' => 'woocommerce-add-product-mbp',
'title' => __( 'Add New (MVP)', 'woocommerce' ),
'url' => 'admin.php?page=wc-admin&path=/add-product',
'parent' => 'woocommerce-products',
'order' => 50,
);
}
return array_merge(
array(
$home_item,
$customers_item,
$order_items['all'],
$order_items['new'],
$product_items['all'],
$product_cat_items['default'],
$product_tag_items['default'],
array(
'id' => 'woocommerce-product-attributes',
'title' => __( 'Attributes', 'woocommerce' ),
'url' => 'edit.php?post_type=product&page=product_attributes',
'capability' => 'manage_product_terms',
'order' => 40,
'parent' => 'woocommerce-products',
'matchExpression' => 'edit.php(?=.*[?|&]page=product_attributes(&|$|#))|edit-tags.php(?=.*[?|&]taxonomy=pa_)(?=.*[?|&]post_type=product(&|$|#))',
),
array_merge( $product_items['new'], array( 'order' => 50 ) ),
$coupon_items['default'],
// Marketplace category.
array(
'title' => __( 'Marketplace', 'woocommerce' ),
'capability' => 'manage_woocommerce',
'id' => 'woocommerce-marketplace',
'url' => 'wc-addons',
'menuId' => 'secondary',
'order' => 10,
),
$add_product_mvp,
),
// Tools category.
self::get_tool_items(),
// WooCommerce Admin items.
$wca_items,
// Settings category.
$setting_items,
// Legacy report items.
self::get_legacy_report_items()
);
}
/**
* Supplies menu items for orders.
*
* This varies depending on whether we are actively using traditional post type-based orders or the new custom
* table-based orders.
*
* @return ?array
*/
private static function get_order_menu_items(): ?array {
if ( ! wc_get_container()->get( CustomOrdersTableController::class )->custom_orders_table_usage_is_enabled() ) {
return Menu::get_post_type_items( 'shop_order', array( 'parent' => 'woocommerce-orders' ) );
}
$main_orders_menu = array(
'title' => __( 'Orders', 'woocommerce' ),
'capability' => 'edit_others_shop_orders',
'id' => 'woocommerce-orders-default',
'url' => 'admin.php?page=wc-orders',
'parent' => 'woocommerce-orders',
);
$all_orders_entry = $main_orders_menu;
$all_orders_entry['id'] = 'woocommerce-orders-all-items';
$all_orders_entry['order'] = 10;
$new_orders_entry = $main_orders_menu;
$new_orders_entry['title'] = __( 'Add order', 'woocommerce' );
$new_orders_entry['id'] = 'woocommerce-orders-add-item';
$new_orders_entry['url'] = 'admin.php?page=TBD';
$new_orders_entry['order'] = 20;
return array(
'default' => $main_orders_menu,
'all' => $all_orders_entry,
'new' => $new_orders_entry,
);
}
/**
* Get items for tools category.
*
* @return array
*/
public static function get_tool_items() {
$tabs = array(
'status' => __( 'System status', 'woocommerce' ),
'tools' => __( 'Utilities', 'woocommerce' ),
'logs' => __( 'Logs', 'woocommerce' ),
);
$tabs = apply_filters( 'woocommerce_admin_status_tabs', $tabs );
$order = 1;
$items = array(
array(
'parent' => 'woocommerce-tools',
'title' => __( 'Import / Export', 'woocommerce' ),
'capability' => 'import',
'id' => 'tools-import-export',
'url' => 'import.php',
'migrate' => false,
'order' => 0,
),
);
foreach ( $tabs as $key => $tab ) {
$items[] = array(
'parent' => 'woocommerce-tools',
'title' => $tab,
'capability' => 'manage_woocommerce',
'id' => 'tools-' . $key,
'url' => 'wc-status&tab=' . $key,
'order' => $order,
);
$order++;
}
return $items;
}
/**
* Get legacy report items.
*
* @return array
*/
public static function get_legacy_report_items() {
$reports = \WC_Admin_Reports::get_reports();
$menu_items = array();
$order = 0;
foreach ( $reports as $key => $report ) {
$menu_items[] = array(
'parent' => 'woocommerce-reports',
'title' => $report['title'],
'capability' => 'view_woocommerce_reports',
'id' => $key,
'url' => 'wc-reports&tab=' . $key,
'order' => $order,
);
$order++;
}
return $menu_items;
}
/**
* Register all core post types.
*/
public function register_post_types() {
Screen::register_post_type( 'shop_order' );
Screen::register_post_type( 'product' );
Screen::register_post_type( 'shop_coupon' );
}
/**
* Add the dashboard items to the WP menu to create a quick-access flyout menu.
*/
public function add_dashboard_menu_items() {
global $submenu, $menu;
$mapped_items = Menu::get_mapped_menu_items();
$top_level = $mapped_items['woocommerce'];
// phpcs:disable
if ( ! isset( $submenu['woocommerce'] ) || empty( $top_level ) ) {
return;
}
$menuIds = array(
'primary',
'secondary',
'favorites',
);
foreach ( $menuIds as $menuId ) {
foreach( $top_level[ $menuId ] as $item ) {
// Skip specific categories.
if (
in_array(
$item['id'],
array(
'woocommerce-tools',
),
true
)
) {
continue;
}
// Use the link from the first item if it's a category.
if ( ! isset( $item['url'] ) ) {
$categoryMenuId = $menuId === 'favorites' ? 'plugins' : $menuId;
$category_items = $mapped_items[ $item['id'] ][ $categoryMenuId ];
if ( ! empty( $category_items ) ) {
$first_item = $category_items[0];
$submenu['woocommerce'][] = array(
$item['title'],
$first_item['capability'],
isset( $first_item['url'] ) ? $first_item['url'] : null,
$item['title'],
);
}
continue;
}
// Show top-level items.
$submenu['woocommerce'][] = array(
$item['title'],
$item['capability'],
isset( $item['url'] ) ? $item['url'] : null,
$item['title'],
);
}
}
// phpcs:enable
}
/**
* Get items excluded from WooCommerce menu migration.
*
* @return array
*/
public static function get_excluded_items() {
$excluded_items = array(
'woocommerce',
'wc-reports',
'wc-settings',
'wc-status',
);
return apply_filters( 'woocommerce_navigation_core_excluded_items', $excluded_items );
}
}

View File

@@ -1,112 +0,0 @@
<?php
/**
* WooCommerce Navigation Favorite
*
* @package Woocommerce Navigation
*/
namespace Automattic\WooCommerce\Admin\Features\Navigation;
use Automattic\WooCommerce\Internal\Admin\WCAdminUser;
/**
* Contains logic for the WooCommerce Navigation menu.
*/
class Favorites {
/**
* Array index of menu capability.
*
* @var int
*/
const META_NAME = 'navigation_favorites';
/**
* Favorites instance.
*
* @var Favorites|null
*/
protected static $instance = null;
/**
* Get class instance.
*/
final public static function instance() {
if ( ! static::$instance ) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Set given favorites string to the user meta data.
*
* @param string|number $user_id User id.
* @param array $favorites Array of favorite values to set.
*/
private static function set_meta_value( $user_id, $favorites ) {
WCAdminUser::update_user_data_field( $user_id, self::META_NAME, wp_json_encode( (array) $favorites ) );
}
/**
* Add item to favorites
*
* @param string $item_id Identifier of item to add.
* @param string|number $user_id Identifier of user to add to.
* @return WP_Error|Boolean Throws exception if item already exists.
*/
public static function add_item( $item_id, $user_id ) {
$all_favorites = self::get_all( $user_id );
if ( in_array( $item_id, $all_favorites, true ) ) {
return new \WP_Error(
'woocommerce_favorites_already_exists',
__( 'Favorite already exists', 'woocommerce' )
);
}
$all_favorites[] = $item_id;
self::set_meta_value( $user_id, $all_favorites );
return true;
}
/**
* Remove item from favorites
*
* @param string $item_id Identifier of item to remove.
* @param string|number $user_id Identifier of user to remove from.
* @return \WP_Error|Boolean Throws exception if item does not exist.
*/
public static function remove_item( $item_id, $user_id ) {
$all_favorites = self::get_all( $user_id );
if ( ! in_array( $item_id, $all_favorites, true ) ) {
return new \WP_Error(
'woocommerce_favorites_does_not_exist',
__( 'Favorite item not found', 'woocommerce' )
);
}
$remaining = array_values( array_diff( $all_favorites, [ $item_id ] ) );
self::set_meta_value( $user_id, $remaining );
return true;
}
/**
* Get all registered favorites.
*
* @param string|number $user_id Identifier of user to query.
* @return WP_Error|Array
*/
public static function get_all( $user_id ) {
$response = WCAdminUser::get_user_data_field( $user_id, self::META_NAME );
return $response ? json_decode( $response, true ) : array();
}
}

View File

@@ -1,144 +0,0 @@
<?php
/**
* Navigation Experience
*
* @package Woocommerce Admin
*/
namespace Automattic\WooCommerce\Admin\Features\Navigation;
use Automattic\WooCommerce\Internal\Admin\Survey;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\Navigation\Screen;
use Automattic\WooCommerce\Admin\Features\Navigation\Menu;
use Automattic\WooCommerce\Admin\Features\Navigation\CoreMenu;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
/**
* Contains logic for the Navigation
*/
class Init {
/**
* Option name used to toggle this feature.
*/
const TOGGLE_OPTION_NAME = 'woocommerce_navigation_enabled';
/**
* Determines if the feature has been toggled on or off.
*
* @var boolean
*/
protected static $is_updated = false;
/**
* Hook into WooCommerce.
*/
public function __construct() {
add_action( 'update_option_' . self::TOGGLE_OPTION_NAME, array( $this, 'reload_page_on_toggle' ), 10, 2 );
add_action( 'woocommerce_settings_saved', array( $this, 'maybe_reload_page' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'maybe_enqueue_opt_out_scripts' ) );
if ( Features::is_enabled( 'navigation' ) ) {
Menu::instance()->init();
CoreMenu::instance()->init();
Screen::instance()->init();
}
}
/**
* Add the feature toggle to the features settings.
*
* @deprecated 7.0 The WooCommerce Admin features are now handled by the WooCommerce features engine (see the FeaturesController class).
*
* @param array $features Feature sections.
* @return array
*/
public static function add_feature_toggle( $features ) {
return $features;
}
/**
* Determine if sufficient versions are present to support Navigation feature
*/
public function is_nav_compatible() {
include_once ABSPATH . 'wp-admin/includes/plugin.php';
$gutenberg_minimum_version = '9.0.0'; // https://github.com/WordPress/gutenberg/releases/tag/v9.0.0.
$wp_minimum_version = '5.6';
$has_gutenberg = is_plugin_active( 'gutenberg/gutenberg.php' );
$gutenberg_version = $has_gutenberg ? get_plugin_data( WP_PLUGIN_DIR . '/gutenberg/gutenberg.php' )['Version'] : false;
if ( $gutenberg_version && version_compare( $gutenberg_version, $gutenberg_minimum_version, '>=' ) ) {
return true;
}
// Get unmodified $wp_version.
include ABSPATH . WPINC . '/version.php';
// Strip '-src' from the version string. Messes up version_compare().
$wp_version = str_replace( '-src', '', $wp_version );
if ( version_compare( $wp_version, $wp_minimum_version, '>=' ) ) {
return true;
}
return false;
}
/**
* Reloads the page when the option is toggled to make sure all nav features are loaded.
*
* @param string $old_value Old value.
* @param string $value New value.
*/
public static function reload_page_on_toggle( $old_value, $value ) {
if ( $old_value === $value ) {
return;
}
if ( 'yes' !== $value ) {
update_option( 'woocommerce_navigation_show_opt_out', 'yes' );
}
self::$is_updated = true;
}
/**
* Reload the page if the setting has been updated.
*/
public static function maybe_reload_page() {
if ( ! isset( $_SERVER['REQUEST_URI'] ) || ! self::$is_updated ) {
return;
}
wp_safe_redirect( wp_unslash( $_SERVER['REQUEST_URI'] ) );
exit();
}
/**
* Enqueue the opt out scripts.
*/
public function maybe_enqueue_opt_out_scripts() {
if ( get_option( 'woocommerce_navigation_show_opt_out', 'no' ) !== 'yes' ) {
return;
}
$rtl = is_rtl() ? '.rtl' : '';
wp_enqueue_style(
'wc-admin-navigation-opt-out',
WCAdminAssets::get_url( "navigation-opt-out/style{$rtl}", 'css' ),
array( 'wp-components' ),
WCAdminAssets::get_file_version( 'css' )
);
WCAdminAssets::register_script( 'wp-admin-scripts', 'navigation-opt-out', true );
wp_localize_script(
'wc-admin-navigation-opt-out',
'surveyData',
array(
'url' => Survey::get_url( '/new-navigation-opt-out' ),
)
);
delete_option( 'woocommerce_navigation_show_opt_out' );
}
}

View File

@@ -1,796 +0,0 @@
<?php
/**
* WooCommerce Navigation Menu
*
* @package Woocommerce Navigation
*/
namespace Automattic\WooCommerce\Admin\Features\Navigation;
use Automattic\WooCommerce\Admin\Features\Navigation\Favorites;
use Automattic\WooCommerce\Admin\Features\Navigation\Screen;
use Automattic\WooCommerce\Admin\Features\Navigation\CoreMenu;
/**
* Contains logic for the WooCommerce Navigation menu.
*/
class Menu {
/**
* Class instance.
*
* @var Menu instance
*/
protected static $instance = null;
/**
* Array index of menu capability.
*
* @var int
*/
const CAPABILITY = 1;
/**
* Array index of menu callback.
*
* @var int
*/
const CALLBACK = 2;
/**
* Array index of menu callback.
*
* @var int
*/
const SLUG = 3;
/**
* Array index of menu CSS class string.
*
* @var int
*/
const CSS_CLASSES = 4;
/**
* Array of usable menu IDs.
*/
const MENU_IDS = array(
'primary',
'favorites',
'plugins',
'secondary',
);
/**
* Store menu items.
*
* @var array
*/
protected static $menu_items = array();
/**
* Store categories with menu item IDs.
*
* @var array
*/
protected static $categories = array(
'woocommerce' => array(),
);
/**
* Registered callbacks or URLs with migration boolean as key value pairs.
*
* @var array
*/
protected static $callbacks = array();
/**
* Get class instance.
*/
final public static function instance() {
if ( ! static::$instance ) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Init.
*/
public function init() {
add_action( 'admin_menu', array( $this, 'add_core_items' ), 100 );
add_filter( 'admin_enqueue_scripts', array( $this, 'enqueue_data' ), 20 );
add_filter( 'admin_menu', array( $this, 'migrate_core_child_items' ), PHP_INT_MAX - 1 );
add_filter( 'admin_menu', array( $this, 'migrate_menu_items' ), PHP_INT_MAX - 2 );
}
/**
* Convert a WordPress menu callback to a URL.
*
* @param string $callback Menu callback.
* @return string
*/
public static function get_callback_url( $callback ) {
// Return the full URL.
if ( strpos( $callback, 'http' ) === 0 ) {
return $callback;
}
$pos = strpos( $callback, '?' );
$file = $pos > 0 ? substr( $callback, 0, $pos ) : $callback;
if ( file_exists( ABSPATH . "/wp-admin/$file" ) ) {
return $callback;
}
return 'admin.php?page=' . $callback;
}
/**
* Get the parent key if one exists.
*
* @param string $callback Callback or URL.
* @return string|null
*/
public static function get_parent_key( $callback ) {
global $submenu;
if ( ! $submenu ) {
return null;
}
// This is already a parent item.
if ( isset( $submenu[ $callback ] ) ) {
return null;
}
foreach ( $submenu as $key => $menu ) {
foreach ( $menu as $item ) {
if ( $item[ self::CALLBACK ] === $callback ) {
return $key;
}
}
}
return null;
}
/**
* Adds a top level menu item to the navigation.
*
* @param array $args Array containing the necessary arguments.
* $args = array(
* 'id' => (string) The unique ID of the menu item. Required.
* 'title' => (string) Title of the menu item. Required.
* 'url' => (string) URL or callback to be used. Required.
* 'order' => (int) Menu item order.
* 'migrate' => (bool) Whether or not to hide the item in the wp admin menu.
* 'menuId' => (string) The ID of the menu to add the category to.
* ).
*/
private static function add_category( $args ) {
if ( ! isset( $args['id'] ) || isset( self::$menu_items[ $args['id'] ] ) ) {
return;
}
$defaults = array(
'id' => '',
'title' => '',
'order' => 100,
'migrate' => true,
'menuId' => 'primary',
'isCategory' => true,
);
$menu_item = wp_parse_args( $args, $defaults );
$menu_item['title'] = wp_strip_all_tags( wp_specialchars_decode( $menu_item['title'] ) );
unset( $menu_item['url'] );
unset( $menu_item['capability'] );
if ( ! isset( $menu_item['parent'] ) ) {
$menu_item['parent'] = 'woocommerce';
$menu_item['backButtonLabel'] = __(
'WooCommerce Home',
'woocommerce'
);
}
self::$menu_items[ $menu_item['id'] ] = $menu_item;
self::$categories[ $menu_item['id'] ] = array();
self::$categories[ $menu_item['parent'] ][] = $menu_item['id'];
if ( isset( $args['url'] ) ) {
self::$callbacks[ $args['url'] ] = $menu_item['migrate'];
}
}
/**
* Adds a child menu item to the navigation.
*
* @param array $args Array containing the necessary arguments.
* $args = array(
* 'id' => (string) The unique ID of the menu item. Required.
* 'title' => (string) Title of the menu item. Required.
* 'parent' => (string) Parent menu item ID.
* 'capability' => (string) Capability to view this menu item.
* 'url' => (string) URL or callback to be used. Required.
* 'order' => (int) Menu item order.
* 'migrate' => (bool) Whether or not to hide the item in the wp admin menu.
* 'menuId' => (string) The ID of the menu to add the item to.
* 'matchExpression' => (string) A regular expression used to identify if the menu item is active.
* ).
*/
private static function add_item( $args ) {
if ( ! isset( $args['id'] ) ) {
return;
}
if ( isset( self::$menu_items[ $args['id'] ] ) ) {
error_log( // phpcs:ignore
sprintf(
/* translators: 1: Duplicate menu item path. */
esc_html__( 'You have attempted to register a duplicate item with WooCommerce Navigation: %1$s', 'woocommerce' ),
'`' . $args['id'] . '`'
)
);
return;
}
$defaults = array(
'id' => '',
'title' => '',
'capability' => 'manage_woocommerce',
'url' => '',
'order' => 100,
'migrate' => true,
'menuId' => 'primary',
);
$menu_item = wp_parse_args( $args, $defaults );
$menu_item['title'] = wp_strip_all_tags( wp_specialchars_decode( $menu_item['title'] ) );
$menu_item['url'] = self::get_callback_url( $menu_item['url'] );
if ( ! isset( $menu_item['parent'] ) ) {
$menu_item['parent'] = 'woocommerce';
}
$menu_item['menuId'] = self::get_item_menu_id( $menu_item );
self::$menu_items[ $menu_item['id'] ] = $menu_item;
self::$categories[ $menu_item['parent'] ][] = $menu_item['id'];
if ( isset( $args['url'] ) ) {
self::$callbacks[ $args['url'] ] = $menu_item['migrate'];
}
}
/**
* Get an item's menu ID from its parent.
*
* @param array $item Item args.
* @return string
*/
public static function get_item_menu_id( $item ) {
$favorites = Favorites::get_all( get_current_user_id() );
if ( is_array( $favorites ) && ! empty( $favorites ) && in_array( $item['id'], $favorites, true ) ) {
return 'favorites';
}
if ( isset( $item['parent'] ) && isset( self::$menu_items[ $item['parent'] ] ) ) {
$menu_id = self::$menu_items[ $item['parent'] ]['menuId'];
return 'favorites' === $menu_id
? 'plugins'
: $menu_id;
}
return $item['menuId'];
}
/**
* Adds a plugin category.
*
* @param array $args Array containing the necessary arguments.
* $args = array(
* 'id' => (string) The unique ID of the menu item. Required.
* 'title' => (string) Title of the menu item. Required.
* 'url' => (string) URL or callback to be used. Required.
* 'migrate' => (bool) Whether or not to hide the item in the wp admin menu.
* 'order' => (int) Menu item order.
* ).
*/
public static function add_plugin_category( $args ) {
$category_args = array_merge(
$args,
array(
'menuId' => 'plugins',
)
);
if ( ! isset( $category_args['parent'] ) ) {
unset( $category_args['order'] );
}
$menu_id = self::get_item_menu_id( $category_args );
if ( ! in_array( $menu_id, array( 'plugins', 'favorites' ), true ) ) {
return;
}
$category_args['menuId'] = $menu_id;
self::add_category( $category_args );
}
/**
* Adds a plugin item.
*
* @param array $args Array containing the necessary arguments.
* $args = array(
* 'id' => (string) The unique ID of the menu item. Required.
* 'title' => (string) Title of the menu item. Required.
* 'parent' => (string) Parent menu item ID.
* 'capability' => (string) Capability to view this menu item.
* 'url' => (string) URL or callback to be used. Required.
* 'migrate' => (bool) Whether or not to hide the item in the wp admin menu.
* 'order' => (int) Menu item order.
* 'matchExpression' => (string) A regular expression used to identify if the menu item is active.
* ).
*/
public static function add_plugin_item( $args ) {
if ( ! isset( $args['parent'] ) ) {
unset( $args['order'] );
}
$item_args = array_merge(
$args,
array(
'menuId' => 'plugins',
)
);
$menu_id = self::get_item_menu_id( $item_args );
if ( 'plugins' !== $menu_id ) {
return;
}
self::add_item( $item_args );
}
/**
* Adds a plugin setting item.
*
* @param array $args Array containing the necessary arguments.
* $args = array(
* 'id' => (string) The unique ID of the menu item. Required.
* 'title' => (string) Title of the menu item. Required.
* 'capability' => (string) Capability to view this menu item.
* 'url' => (string) URL or callback to be used. Required.
* 'migrate' => (bool) Whether or not to hide the item in the wp admin menu.
* ).
*/
public static function add_setting_item( $args ) {
unset( $args['order'] );
if ( isset( $args['parent'] ) || isset( $args['menuId'] ) ) {
error_log( // phpcs:ignore
sprintf(
/* translators: 1: Duplicate menu item path. */
esc_html__( 'The item ID %1$s attempted to register using an invalid option. The arguments `menuId` and `parent` are not allowed for add_setting_item()', 'woocommerce' ),
'`' . $args['id'] . '`'
)
);
}
$item_args = array_merge(
$args,
array(
'menuId' => 'secondary',
'parent' => 'woocommerce-settings',
)
);
self::add_item( $item_args );
}
/**
* Get menu item templates for a given post type.
*
* @param string $post_type Post type to add.
* @param array $menu_args Arguments merged with the returned menu items.
* @return array
*/
public static function get_post_type_items( $post_type, $menu_args = array() ) {
$post_type_object = get_post_type_object( $post_type );
if ( ! $post_type_object || ! $post_type_object->show_in_menu ) {
return;
}
$parent = isset( $menu_args['parent'] ) ? $menu_args['parent'] . '-' : '';
$match_expression = isset( $_GET['post'] ) && get_post_type( intval( $_GET['post'] ) ) === $post_type // phpcs:ignore WordPress.Security.NonceVerification
? '(edit.php|post.php)'
: null;
return array(
'default' => array_merge(
array(
'title' => esc_attr( $post_type_object->labels->menu_name ),
'capability' => $post_type_object->cap->edit_posts,
'id' => $parent . $post_type,
'url' => "edit.php?post_type={$post_type}",
'matchExpression' => $match_expression,
),
$menu_args
),
'all' => array_merge(
array(
'title' => esc_attr( $post_type_object->labels->all_items ),
'capability' => $post_type_object->cap->edit_posts,
'id' => "{$parent}{$post_type}-all-items",
'url' => "edit.php?post_type={$post_type}",
'order' => 10,
'matchExpression' => $match_expression,
),
$menu_args
),
'new' => array_merge(
array(
'title' => esc_attr( $post_type_object->labels->add_new ),
'capability' => $post_type_object->cap->create_posts,
'id' => "{$parent}{$post_type}-add-new",
'url' => "post-new.php?post_type={$post_type}",
'order' => 20,
),
$menu_args
),
);
}
/**
* Get menu item templates for a given taxonomy.
*
* @param string $taxonomy Taxonomy to add.
* @param array $menu_args Arguments merged with the returned menu items.
* @return array
*/
public static function get_taxonomy_items( $taxonomy, $menu_args = array() ) {
$taxonomy_object = get_taxonomy( $taxonomy );
if ( ! $taxonomy_object || ! $taxonomy_object->show_in_menu ) {
return;
}
$parent = isset( $menu_args['parent'] ) ? $menu_args['parent'] . '-' : '';
$product_type_query = ! empty( $taxonomy_object->object_type )
? "&post_type={$taxonomy_object->object_type[0]}"
: '';
$match_expression = 'term.php'; // Match term.php pages.
$match_expression .= "(?=.*[?|&]taxonomy={$taxonomy}(&|$|#))"; // Lookahead to match a taxonomy URL param.
$match_expression .= '|'; // Or.
$match_expression .= 'edit-tags.php'; // Match edit-tags.php pages.
$match_expression .= "(?=.*[?|&]taxonomy={$taxonomy}(&|$|#))"; // Lookahead to match a taxonomy URL param.
return array(
'default' => array_merge(
array(
'title' => esc_attr( $taxonomy_object->labels->menu_name ),
'capability' => $taxonomy_object->cap->edit_terms,
'id' => $parent . $taxonomy,
'url' => "edit-tags.php?taxonomy={$taxonomy}{$product_type_query}",
'matchExpression' => $match_expression,
),
$menu_args
),
'all' => array_merge(
array(
'title' => esc_attr( $taxonomy_object->labels->all_items ),
'capability' => $taxonomy_object->cap->edit_terms,
'id' => "{$parent}{$taxonomy}-all-items",
'url' => "edit-tags.php?taxonomy={$taxonomy}{$product_type_query}",
'matchExpression' => $match_expression,
'order' => 10,
),
$menu_args
),
);
}
/**
* Add core menu items.
*/
public function add_core_items() {
$categories = CoreMenu::get_categories();
foreach ( $categories as $category ) {
self::add_category( $category );
}
$items = CoreMenu::get_items();
foreach ( $items as $item ) {
if ( isset( $item['is_category'] ) && $item['is_category'] ) {
self::add_category( $item );
} else {
self::add_item( $item );
}
}
}
/**
* Add an item or taxonomy.
*
* @param array $menu_item Menu item.
*/
public function add_item_and_taxonomy( $menu_item ) {
if ( in_array( $menu_item[2], CoreMenu::get_excluded_items(), true ) ) {
return;
}
$menu_item[2] = htmlspecialchars_decode( $menu_item[2] );
// Don't add already added items.
$callbacks = self::get_callbacks();
if ( array_key_exists( $menu_item[2], $callbacks ) ) {
return;
}
// Don't add these Product submenus because they are added elsewhere.
if ( in_array( $menu_item[2], array( 'product_importer', 'product_exporter', 'product_attributes' ), true ) ) {
return;
}
self::add_plugin_item(
array(
'title' => $menu_item[0],
'capability' => $menu_item[1],
'id' => sanitize_title( $menu_item[0] ),
'url' => $menu_item[2],
)
);
// Determine if migrated items are a taxonomy or post_type. If they are, register them.
$parsed_url = wp_parse_url( $menu_item[2] );
$query_string = isset( $parsed_url['query'] ) ? $parsed_url['query'] : false;
if ( $query_string ) {
$query = array();
parse_str( $query_string, $query );
if ( isset( $query['taxonomy'] ) ) {
Screen::register_taxonomy( $query['taxonomy'] );
} elseif ( isset( $query['post_type'] ) ) {
Screen::register_post_type( $query['post_type'] );
}
}
}
/**
* Migrate any remaining WooCommerce child items.
*
* @param array $menu Menu items.
* @return array
*/
public function migrate_core_child_items( $menu ) {
global $submenu;
if ( ! isset( $submenu['woocommerce'] ) && ! isset( $submenu['edit.php?post_type=product'] ) ) {
return $menu;
}
$main_items = isset( $submenu['woocommerce'] ) ? $submenu['woocommerce'] : array();
$product_items = isset( $submenu['edit.php?post_type=product'] ) ? $submenu['edit.php?post_type=product'] : array();
foreach ( $main_items as $key => $menu_item ) {
self::add_item_and_taxonomy( $menu_item );
// phpcs:disable
if ( ! isset( $menu_item[ self::CSS_CLASSES ] ) ) {
$submenu['woocommerce'][ $key ][] .= ' hide-if-js';
} else if ( strpos( $submenu['woocommerce'][ $key ][ self::CSS_CLASSES ], 'hide-if-js' ) !== false ) {
continue;
} else {
$submenu['woocommerce'][ $key ][ self::CSS_CLASSES ] .= ' hide-if-js';
}
// phpcs:enable
}
foreach ( $product_items as $key => $menu_item ) {
self::add_item_and_taxonomy( $menu_item );
}
return $menu;
}
/**
* Check if a menu item's callback is registered in the menu.
*
* @param array $menu_item Menu item args.
* @return bool
*/
public static function has_callback( $menu_item ) {
if ( ! $menu_item || ! isset( $menu_item[ self::CALLBACK ] ) ) {
return false;
}
$callback = $menu_item[ self::CALLBACK ];
if (
isset( self::$callbacks[ $callback ] ) &&
self::$callbacks[ $callback ]
) {
return true;
}
if (
isset( self::$callbacks[ self::get_callback_url( $callback ) ] ) &&
self::$callbacks[ self::get_callback_url( $callback ) ]
) {
return true;
}
return false;
}
/**
* Hides all WP admin menus items and adds screen IDs to check for new items.
*/
public static function migrate_menu_items() {
global $menu, $submenu;
foreach ( $menu as $key => $menu_item ) {
if ( self::has_callback( $menu_item ) ) {
// Disable phpcs since we need to override submenu classes.
// Note that `phpcs:ignore WordPress.Variables.GlobalVariables.OverrideProhibited` does not work to disable this check.
// phpcs:disable
$menu[ $key ][ self::CSS_CLASSES ] .= ' hide-if-js';
// phps:enable
continue;
}
// WordPress core menus make the parent item the same URL as the first child.
$has_children = isset( $submenu[ $menu_item[ self::CALLBACK ] ] ) && isset( $submenu[ $menu_item[ self::CALLBACK ] ][0] );
$first_child = $has_children ? $submenu[ $menu_item[ self::CALLBACK ] ][0] : null;
if ( 'woocommerce' !== $menu_item[2] && self::has_callback( $first_child ) ) {
// Disable phpcs since we need to override submenu classes.
// Note that `phpcs:ignore WordPress.Variables.GlobalVariables.OverrideProhibited` does not work to disable this check.
// phpcs:disable
$menu[ $key ][ self::CSS_CLASSES ] .= ' hide-if-js';
// phps:enable
}
}
// Remove excluded submenu items
if ( isset( $submenu['woocommerce'] ) ) {
foreach ( $submenu['woocommerce'] as $key => $submenu_item ) {
if ( in_array( $submenu_item[ self::CALLBACK ], CoreMenu::get_excluded_items(), true ) ) {
if ( isset( $submenu['woocommerce'][ $key ][ self::CSS_CLASSES ] ) ) {
$submenu['woocommerce'][ $key ][ self::CSS_CLASSES ] .= ' hide-if-js';
} else {
$submenu['woocommerce'][ $key ][] = 'hide-if-js';
}
}
}
}
foreach ( $submenu as $parent_key => $parent ) {
foreach ( $parent as $key => $menu_item ) {
if ( self::has_callback( $menu_item ) ) {
// Disable phpcs since we need to override submenu classes.
// Note that `phpcs:ignore WordPress.Variables.GlobalVariables.OverrideProhibited` does not work to disable this check.
// phpcs:disable
if ( ! isset( $menu_item[ self::SLUG ] ) ) {
$submenu[ $parent_key ][ $key ][] = '';
}
if ( ! isset( $menu_item[ self::CSS_CLASSES ] ) ) {
$submenu[ $parent_key ][ $key ][] .= ' hide-if-js';
} else {
$submenu[ $parent_key ][ $key ][ self::CSS_CLASSES ] .= ' hide-if-js';
}
// phps:enable
}
}
}
foreach ( array_keys( self::$callbacks ) as $callback ) {
Screen::add_screen( $callback );
}
}
/**
* Add a callback to identify and hide pages in the WP menu.
*/
public static function hide_wp_menu_item( $callback ) {
self::$callbacks[ $callback ] = true;
}
/**
* Get registered menu items.
*
* @return array
*/
public static function get_items() {
return apply_filters( 'woocommerce_navigation_menu_items', self::$menu_items );
}
/**
* Get registered menu items.
*
* @return array
*/
public static function get_category_items( $category ) {
if ( ! isset( self::$categories[ $category ] ) ) {
return array();
}
$menu_item_ids = self::$categories[ $category ];
$category_menu_items = array();
foreach ( $menu_item_ids as $id ) {
if ( isset( self::$menu_items[ $id ] ) ) {
$category_menu_items[] = self::$menu_items[ $id ];
}
}
return apply_filters( 'woocommerce_navigation_menu_category_items', $category_menu_items );
}
/**
* Get registered callbacks.
*
* @return array
*/
public static function get_callbacks() {
return apply_filters( 'woocommerce_navigation_callbacks', self::$callbacks );
}
/**
* Gets the menu item data mapped by category and menu ID.
*
* @return array
*/
public static function get_mapped_menu_items() {
$menu_items = self::get_items();
$mapped_items = array();
// Sort the items by order and title.
$order = array_column( $menu_items, 'order' );
$title = array_column( $menu_items, 'title' );
array_multisort( $order, SORT_ASC, $title, SORT_ASC, $menu_items );
foreach ( $menu_items as $id => $menu_item ) {
$category_id = $menu_item[ 'parent' ];
$menu_id = $menu_item[ 'menuId' ];
if ( ! isset( $mapped_items[ $category_id ] ) ) {
$mapped_items[ $category_id ] = array();
foreach ( self::MENU_IDS as $available_menu_id ) {
$mapped_items[ $category_id ][ $available_menu_id ] = array();
}
}
// Incorrect menu ID.
if ( ! isset( $mapped_items[ $category_id ][ $menu_id ] ) ) {
continue;
}
// Remove the item if the user cannot access it.
if ( isset( $menu_item[ 'capability' ] ) && ! current_user_can( $menu_item[ 'capability' ] ) ) {
continue;
}
$mapped_items[ $category_id ][ $menu_id ][] = $menu_item;
}
return $mapped_items;
}
/**
* Add the menu to the page output.
*
* @param array $menu Menu items.
* @return array
*/
public function enqueue_data( $menu ) {
$data = array(
'menuItems' => array_values( self::get_items() ),
'rootBackUrl' => get_dashboard_url(),
);
wp_add_inline_script( WC_ADMIN_APP, 'window.wcNavigation = ' . wp_json_encode( $data ), 'before' );
}
}

View File

@@ -1,240 +0,0 @@
<?php
/**
* WooCommerce Navigation Screen
*
* @package Woocommerce Navigation
*/
namespace Automattic\WooCommerce\Admin\Features\Navigation;
use Automattic\WooCommerce\Admin\Features\Navigation\Menu;
/**
* Contains logic for the WooCommerce Navigation menu.
*/
class Screen {
/**
* Class instance.
*
* @var Screen instance
*/
protected static $instance = null;
/**
* Screen IDs of registered pages.
*
* @var array
*/
protected static $screen_ids = array();
/**
* Registered post types.
*
* @var array
*/
protected static $post_types = array();
/**
* Registered taxonomies.
*
* @var array
*/
protected static $taxonomies = array();
/**
* Get class instance.
*/
final public static function instance() {
if ( ! static::$instance ) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Init.
*/
public function init() {
add_filter( 'admin_body_class', array( $this, 'add_body_class' ) );
}
/**
* Returns an array of filtered screen ids.
*/
public static function get_screen_ids() {
return apply_filters( 'woocommerce_navigation_screen_ids', self::$screen_ids );
}
/**
* Returns an array of registered post types.
*/
public static function get_post_types() {
return apply_filters( 'woocommerce_navigation_post_types', self::$post_types );
}
/**
* Returns an array of registered post types.
*/
public static function get_taxonomies() {
return apply_filters( 'woocommerce_navigation_taxonomies', self::$taxonomies );
}
/**
* Check if we're on a WooCommerce page
*
* @return bool
*/
public static function is_woocommerce_page() {
global $pagenow;
// Get taxonomy if on a taxonomy screen.
$taxonomy = '';
if ( in_array( $pagenow, array( 'edit-tags.php', 'term.php' ), true ) ) {
if ( isset( $_GET['taxonomy'] ) ) { // phpcs:ignore CSRF ok.
$taxonomy = sanitize_text_field( wp_unslash( $_GET['taxonomy'] ) ); // phpcs:ignore CSRF ok.
}
}
$taxonomies = self::get_taxonomies();
// Get post type if on a post screen.
$post_type = '';
if ( in_array( $pagenow, array( 'edit.php', 'post.php', 'post-new.php' ), true ) ) {
if ( isset( $_GET['post'] ) ) { // phpcs:ignore CSRF ok.
$post_type = get_post_type( (int) $_GET['post'] ); // phpcs:ignore CSRF ok.
} elseif ( isset( $_GET['post_type'] ) ) { // phpcs:ignore CSRF ok.
$post_type = sanitize_text_field( wp_unslash( $_GET['post_type'] ) ); // phpcs:ignore CSRF ok.
}
}
$post_types = self::get_post_types();
// Get current screen ID.
$current_screen = get_current_screen();
$screen_ids = self::get_screen_ids();
$current_screen_id = $current_screen ? $current_screen->id : null;
if (
in_array( $post_type, $post_types, true ) ||
in_array( $taxonomy, $taxonomies, true ) ||
self::is_woocommerce_core_taxonomy( $taxonomy ) ||
in_array( $current_screen_id, $screen_ids, true )
) {
return true;
}
return false;
}
/**
* Check if a given taxonomy is a WooCommerce core related taxonomy.
*
* @param string $taxonomy Taxonomy.
* @return bool
*/
public static function is_woocommerce_core_taxonomy( $taxonomy ) {
if ( in_array( $taxonomy, array( 'product_cat', 'product_tag' ), true ) ) {
return true;
}
if ( 'pa_' === substr( $taxonomy, 0, 3 ) ) {
return true;
}
return false;
}
/**
* Add navigation classes to body.
*
* @param string $classes Classes.
* @return string
*/
public function add_body_class( $classes ) {
if ( self::is_woocommerce_page() ) {
$classes .= ' has-woocommerce-navigation';
/**
* Adds the ability to skip disabling of the WP toolbar.
*
* @param boolean $bool WP Toolbar disabled.
*/
if ( apply_filters( 'woocommerce_navigation_wp_toolbar_disabled', true ) ) {
$classes .= ' is-wp-toolbar-disabled';
}
}
return $classes;
}
/**
* Adds a screen ID to the list of screens that use the navigtion.
* Finds the parent if none is given to grab the correct screen ID.
*
* @param string $callback Callback or URL for page.
* @param string|null $parent Parent screen ID.
*/
public static function add_screen( $callback, $parent = null ) {
global $submenu;
$plugin_page = self::get_plugin_page( $callback );
if ( ! $parent ) {
$parent = Menu::get_parent_key( $callback );
}
$screen_id = get_plugin_page_hookname( $plugin_page, $parent );
// This screen has already been added.
if ( in_array( $screen_id, self::$screen_ids, true ) ) {
return;
}
self::$screen_ids[] = $screen_id;
}
/**
* Get the plugin page slug.
*
* @param string $callback Callback.
* @return string
*/
public static function get_plugin_page( $callback ) {
$url = Menu::get_callback_url( $callback );
$parts = wp_parse_url( $url );
if ( ! isset( $parts['query'] ) ) {
return $callback;
}
parse_str( $parts['query'], $query );
if ( ! isset( $query['page'] ) ) {
return $callback;
}
$plugin_page = wp_unslash( $query['page'] );
$plugin_page = plugin_basename( $plugin_page );
return $plugin_page;
}
/**
* Register post type for use in WooCommerce Navigation screens.
*
* @param string $post_type Post type to add.
*/
public static function register_post_type( $post_type ) {
if ( ! in_array( $post_type, self::$post_types, true ) ) {
self::$post_types[] = $post_type;
}
}
/**
* Register taxonomy for use in WooCommerce Navigation screens.
*
* @param string $taxonomy Taxonomy to add.
*/
public static function register_taxonomy( $taxonomy ) {
if ( ! in_array( $taxonomy, self::$taxonomies, true ) ) {
self::$taxonomies[] = $taxonomy;
}
}
}

View File

@@ -1,97 +0,0 @@
<?php
/**
* WooCommerce New Product Management Experience
*/
namespace Automattic\WooCommerce\Admin\Features;
use Automattic\WooCommerce\Admin\Features\TransientNotices;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Internal\Admin\Loader;
use WP_Block_Editor_Context;
/**
* Loads assets related to the new product management experience page.
*/
class NewProductManagementExperience {
/**
* Option name used to toggle this feature.
*/
const TOGGLE_OPTION_NAME = 'woocommerce_new_product_management_enabled';
/**
* Constructor
*/
public function __construct() {
$this->maybe_show_disabled_notice();
if ( ! Features::is_enabled( 'new-product-management-experience' ) ) {
return;
}
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles' ) );
add_action( 'get_edit_post_link', array( $this, 'update_edit_product_link' ), 10, 2 );
}
/**
* Maybe show disabled notice.
*/
public function maybe_show_disabled_notice() {
$new_product_experience_param = 'new-product-experience-disabled';
if ( isset( $_GET[ $new_product_experience_param ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
TransientNotices::add(
array(
'user_id' => get_current_user_id(),
'id' => 'new-product-experience-disbled',
'status' => 'success',
'content' => __( '🌟‎ Thanks for the feedback. Well put it to good use!', 'woocommerce' ),
)
);
$url = isset( $_SERVER['REQUEST_URI'] ) ? wc_clean( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
$url = remove_query_arg( 'new-product-experience-disabled', $url );
wp_safe_redirect( $url );
exit;
}
}
/**
* Enqueue styles needed for the rich text editor.
*/
public function enqueue_styles() {
if ( ! PageController::is_admin_or_embed_page() ) {
return;
}
wp_enqueue_style( 'wp-edit-blocks' );
wp_enqueue_style( 'wp-format-library' );
wp_enqueue_editor();
/**
* Enqueue any block editor related assets.
*
* @since 7.1.0
*/
do_action( 'enqueue_block_editor_assets' );
}
/**
* Update the edit product links when the new experience is enabled.
*
* @param string $link The edit link.
* @param int $post_id Post ID.
* @return string
*/
public function update_edit_product_link( $link, $post_id ) {
$product = wc_get_product( $post_id );
if ( ! $product ) {
return $link;
}
if ( $product->get_type() === 'simple' ) {
return admin_url( 'admin.php?page=wc-admin&path=/product/' . $product->get_id() );
}
return $link;
}
}

View File

@@ -1,103 +0,0 @@
<?php
/**
* WooCommerce Onboarding
*/
namespace Automattic\WooCommerce\Admin\Features;
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
/**
* Contains backend logic for the onboarding profile and checklist feature.
*
* @deprecated since 6.3.0, use WooCommerce\Internal\Admin\Onboarding.
*/
class Onboarding extends DeprecatedClassFacade {
/**
* The name of the non-deprecated class that this facade covers.
*
* @var string
*/
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\Features\Onboarding';
/**
* The version that this class was deprecated in.
*
* @var string
*/
protected static $deprecated_in_version = '6.3.0';
/**
* Hook into WooCommerce.
*/
public function __construct() {
}
/**
* Get a list of allowed industries for the onboarding wizard.
*
* @deprecated 6.3.0
* @return array
*/
public static function get_allowed_industries() {
wc_deprecated_function( 'get_allowed_industries', '6.3', '\Automattic\WooCommerce\Internal\Admin\OnboardingIndustries::get_allowed_industries()' );
return \Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingIndustries::get_allowed_industries();
}
/**
* Get a list of allowed product types for the onboarding wizard.
*
* @deprecated 6.3.0
* @return array
*/
public static function get_allowed_product_types() {
wc_deprecated_function( 'get_allowed_product_types', '6.3', '\Automattic\WooCommerce\Internal\Admin\OnboardingProducts::get_allowed_product_types()' );
return \Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProducts::get_allowed_product_types();
}
/**
* Get a list of themes for the onboarding wizard.
*
* @deprecated 6.3.0
* @return array
*/
public static function get_themes() {
wc_deprecated_function( 'get_themes', '6.3', '\Automattic\WooCommerce\Internal\Admin\OnboardingThemes::get_themes()' );
return \Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingThemes::get_themes();
}
/**
* Get theme data used in onboarding theme browser.
*
* @deprecated 6.3.0
* @param WP_Theme $theme Theme to gather data from.
* @return array
*/
public static function get_theme_data( $theme ) {
wc_deprecated_function( 'get_theme_data', '6.3', '\Automattic\WooCommerce\Internal\Admin\OnboardingThemes::get_theme_data()' );
return \Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingThemes::get_theme_data();
}
/**
* Gets an array of themes that can be installed & activated via the onboarding wizard.
*
* @deprecated 6.3.0
* @return array
*/
public static function get_allowed_themes() {
wc_deprecated_function( 'get_allowed_themes', '6.3', '\Automattic\WooCommerce\Internal\Admin\OnboardingThemes::get_allowed_themes()' );
return \Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingThemes::get_allowed_themes();
}
/**
* Get dynamic product data from API.
*
* @deprecated 6.3.0
* @param array $product_types Array of product types.
* @return array
*/
public static function get_product_data( $product_types ) {
wc_deprecated_function( 'get_product_data', '6.3', '\Automattic\WooCommerce\Internal\Admin\OnboardingProducts::get_product_data()' );
return \Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProducts::get_product_data();
}
}

View File

@@ -1,208 +0,0 @@
<?php
/**
* A temporary class for creating tasks on the fly from deprecated tasks.
*/
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
/**
* DeprecatedExtendedTask class.
*/
class DeprecatedExtendedTask extends Task {
/**
* ID.
*
* @var string
*/
public $id = '';
/**
* Additional info.
*
* @var string|null
*/
public $additional_info = '';
/**
* Content.
*
* @var string
*/
public $content = '';
/**
* Whether the task is complete or not.
*
* @var boolean
*/
public $is_complete = false;
/**
* Snoozeable.
*
* @var boolean
*/
public $is_snoozeable = false;
/**
* Dismissable.
*
* @var boolean
*/
public $is_dismissable = false;
/**
* Whether the store is capable of viewing the task.
*
* @var bool
*/
public $can_view = true;
/**
* Level.
*
* @var int
*/
public $level = 3;
/**
* Time.
*
* @var string|null
*/
public $time;
/**
* Title.
*
* @var string
*/
public $title = '';
/**
* Constructor.
*
* @param TaskList $task_list Parent task list.
* @param array $args Array of task args.
*/
public function __construct( $task_list, $args ) {
parent::__construct( $task_list );
$task_args = wp_parse_args(
$args,
array(
'id' => null,
'is_dismissable' => false,
'is_snoozeable' => false,
'can_view' => true,
'level' => 3,
'additional_info' => null,
'content' => '',
'title' => '',
'is_complete' => false,
'time' => null,
)
);
$this->id = $task_args['id'];
$this->additional_info = $task_args['additional_info'];
$this->content = $task_args['content'];
$this->is_complete = $task_args['is_complete'];
$this->is_dismissable = $task_args['is_dismissable'];
$this->is_snoozeable = $task_args['is_snoozeable'];
$this->can_view = $task_args['can_view'];
$this->level = $task_args['level'];
$this->time = $task_args['time'];
$this->title = $task_args['title'];
}
/**
* ID.
*
* @return string
*/
public function get_id() {
return $this->id;
}
/**
* Additional info.
*
* @return string
*/
public function get_additional_info() {
return $this->additional_info;
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return $this->content;
}
/**
* Level.
*
* @return int
*/
public function get_level() {
return $this->level;
}
/**
* Title
*
* @return string
*/
public function get_title() {
return $this->title;
}
/**
* Time
*
* @return string|null
*/
public function get_time() {
return $this->time;
}
/**
* Check if a task is snoozeable.
*
* @return bool
*/
public function is_snoozeable() {
return $this->is_snoozeable;
}
/**
* Check if a task is dismissable.
*
* @return bool
*/
public function is_dismissable() {
return $this->is_dismissable;
}
/**
* Check if a task is dismissable.
*
* @return bool
*/
public function is_complete() {
return $this->is_complete;
}
/**
* Check if a task is dismissable.
*
* @return bool
*/
public function can_view() {
return $this->can_view;
}
}

View File

@@ -1,75 +0,0 @@
<?php
/**
* Filters for maintaining backwards compatibility with deprecated options.
*/
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\TaskList;
use WC_Install;
/**
* DeprecatedOptions class.
*/
class DeprecatedOptions {
/**
* Initialize.
*/
public static function init() {
add_filter( 'pre_option_woocommerce_task_list_hidden', array( __CLASS__, 'get_deprecated_options' ), 10, 2 );
add_filter( 'pre_option_woocommerce_extended_task_list_hidden', array( __CLASS__, 'get_deprecated_options' ), 10, 2 );
add_action( 'pre_update_option_woocommerce_task_list_hidden', array( __CLASS__, 'update_deprecated_options' ), 10, 3 );
add_action( 'pre_update_option_woocommerce_extended_task_list_hidden', array( __CLASS__, 'update_deprecated_options' ), 10, 3 );
}
/**
* Get the values from the correct source when attempting to retrieve deprecated options.
*
* @param string $pre_option Pre option value.
* @param string $option Option name.
* @return string
*/
public static function get_deprecated_options( $pre_option, $option ) {
if ( defined( 'WC_INSTALLING' ) && WC_INSTALLING === true ) {
return $pre_option;
}
$hidden = get_option( 'woocommerce_task_list_hidden_lists', array() );
switch ( $option ) {
case 'woocommerce_task_list_hidden':
return in_array( 'setup', $hidden, true ) ? 'yes' : 'no';
case 'woocommerce_extended_task_list_hidden':
return in_array( 'extended', $hidden, true ) ? 'yes' : 'no';
}
}
/**
* Updates the new option names when deprecated options are updated.
* This is a temporary fallback until we can fully remove the old task list components.
*
* @param string $value New value.
* @param string $old_value Old value.
* @param string $option Option name.
* @return string
*/
public static function update_deprecated_options( $value, $old_value, $option ) {
switch ( $option ) {
case 'woocommerce_task_list_hidden':
$task_list = TaskLists::get_list( 'setup' );
if ( ! $task_list ) {
return;
}
$update = 'yes' === $value ? $task_list->hide() : $task_list->unhide();
delete_option( 'woocommerce_task_list_hidden' );
return false;
case 'woocommerce_extended_task_list_hidden':
$task_list = TaskLists::get_list( 'extended' );
if ( ! $task_list ) {
return;
}
$update = 'yes' === $value ? $task_list->hide() : $task_list->unhide();
delete_option( 'woocommerce_extended_task_list_hidden' );
return false;
}
}
}

View File

@@ -1,56 +0,0 @@
<?php
/**
* WooCommerce Onboarding Tasks
*/
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\DeprecatedOptions;
/**
* Contains the logic for completing onboarding tasks.
*/
class Init {
/**
* Class instance.
*
* @var OnboardingTasks instance
*/
protected static $instance = null;
/**
* Get class instance.
*/
public static function get_instance() {
if ( ! self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
public function __construct() {
DeprecatedOptions::init();
TaskLists::init();
}
/**
* Get task item data for settings filter.
*
* @return array
*/
public static function get_settings() {
$settings = array();
$wc_pay_is_connected = false;
if ( class_exists( '\WC_Payments' ) ) {
$wc_payments_gateway = \WC_Payments::get_gateway();
$wc_pay_is_connected = method_exists( $wc_payments_gateway, 'is_connected' )
? $wc_payments_gateway->is_connected()
: false;
}
return $settings;
}
}

View File

@@ -1,607 +0,0 @@
<?php
/**
* Handles task related methods.
*/
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
use Automattic\WooCommerce\Internal\Admin\WCAdminUser;
/**
* Task class.
*/
abstract class Task {
/**
* Task traits.
*/
use TaskTraits;
/**
* Name of the dismiss option.
*
* @var string
*/
const DISMISSED_OPTION = 'woocommerce_task_list_dismissed_tasks';
/**
* Name of the snooze option.
*
* @var string
*
* @deprecated 7.2.0
*/
const SNOOZED_OPTION = 'woocommerce_task_list_remind_me_later_tasks';
/**
* Name of the actioned option.
*
* @var string
*/
const ACTIONED_OPTION = 'woocommerce_task_list_tracked_completed_actions';
/**
* Option name of completed tasks.
*
* @var string
*/
const COMPLETED_OPTION = 'woocommerce_task_list_tracked_completed_tasks';
/**
* Name of the active task transient.
*
* @var string
*/
const ACTIVE_TASK_TRANSIENT = 'wc_onboarding_active_task';
/**
* Parent task list.
*
* @var TaskList
*/
protected $task_list;
/**
* Duration to milisecond mapping.
*
* @var string
*/
protected $duration_to_ms = array(
'day' => DAY_IN_SECONDS * 1000,
'hour' => HOUR_IN_SECONDS * 1000,
'week' => WEEK_IN_SECONDS * 1000,
);
/**
* Constructor
*
* @param TaskList|null $task_list Parent task list.
*/
public function __construct( $task_list = null ) {
$this->task_list = $task_list;
}
/**
* ID.
*
* @return string
*/
abstract public function get_id();
/**
* Title.
*
* @return string
*/
abstract public function get_title();
/**
* Content.
*
* @return string
*/
abstract public function get_content();
/**
* Time.
*
* @return string
*/
abstract public function get_time();
/**
* Parent ID.
*
* @return string
*/
public function get_parent_id() {
if ( ! $this->task_list ) {
return '';
}
return $this->task_list->get_list_id();
}
/**
* Get task list options.
*
* @return array
*/
public function get_parent_options() {
if ( ! $this->task_list ) {
return array();
}
return $this->task_list->options;
}
/**
* Get custom option.
*
* @param string $option_name name of custom option.
* @return mixed|null
*/
public function get_parent_option( $option_name ) {
if ( $this->task_list && isset( $this->task_list->options[ $option_name ] ) ) {
return $this->task_list->options[ $option_name ];
}
return null;
}
/**
* Prefix event for track event naming.
*
* @param string $event_name Event name.
* @return string
*/
public function prefix_event( $event_name ) {
if ( ! $this->task_list ) {
return '';
}
return $this->task_list->prefix_event( $event_name );
}
/**
* Additional info.
*
* @return string
*/
public function get_additional_info() {
return '';
}
/**
* Additional data.
*
* @return mixed
*/
public function get_additional_data() {
return null;
}
/**
* Badge.
*
* @return string
*/
public function get_badge() {
return '';
}
/**
* Level.
*
* @deprecated 7.2.0
*
* @return string
*/
public function get_level() {
wc_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '7.2.0' );
return 3;
}
/**
* Action label.
*
* @return string
*/
public function get_action_label() {
return __( "Let's go", 'woocommerce' );
}
/**
* Action URL.
*
* @return string
*/
public function get_action_url() {
return null;
}
/**
* Check if a task is dismissable.
*
* @return bool
*/
public function is_dismissable() {
return false;
}
/**
* Bool for task dismissal.
*
* @return bool
*/
public function is_dismissed() {
if ( ! $this->is_dismissable() ) {
return false;
}
$dismissed = get_option( self::DISMISSED_OPTION, array() );
return in_array( $this->get_id(), $dismissed, true );
}
/**
* Dismiss the task.
*
* @return bool
*/
public function dismiss() {
if ( ! $this->is_dismissable() ) {
return false;
}
$dismissed = get_option( self::DISMISSED_OPTION, array() );
$dismissed[] = $this->get_id();
$update = update_option( self::DISMISSED_OPTION, array_unique( $dismissed ) );
if ( $update ) {
$this->record_tracks_event( 'dismiss_task', array( 'task_name' => $this->get_id() ) );
}
return $update;
}
/**
* Undo task dismissal.
*
* @return bool
*/
public function undo_dismiss() {
$dismissed = get_option( self::DISMISSED_OPTION, array() );
$dismissed = array_diff( $dismissed, array( $this->get_id() ) );
$update = update_option( self::DISMISSED_OPTION, $dismissed );
if ( $update ) {
$this->record_tracks_event( 'undo_dismiss_task', array( 'task_name' => $this->get_id() ) );
}
return $update;
}
/**
* Check if a task is snoozeable.
*
* @deprecated 7.2.0
*
* @return bool
*/
public function is_snoozeable() {
wc_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '7.2.0' );
return false;
}
/**
* Get the snoozed until datetime.
*
* @deprecated 7.2.0
*
* @return string
*/
public function get_snoozed_until() {
wc_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '7.2.0' );
$snoozed_tasks = get_option( self::SNOOZED_OPTION, array() );
if ( isset( $snoozed_tasks[ $this->get_id() ] ) ) {
return $snoozed_tasks[ $this->get_id() ];
}
return null;
}
/**
* Bool for task snoozed.
*
* @deprecated 7.2.0
*
* @return bool
*/
public function is_snoozed() {
wc_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '7.2.0' );
if ( ! $this->is_snoozeable() ) {
return false;
}
$snoozed = get_option( self::SNOOZED_OPTION, array() );
return isset( $snoozed[ $this->get_id() ] ) && $snoozed[ $this->get_id() ] > ( time() * 1000 );
}
/**
* Snooze the task.
*
* @param string $duration Duration to snooze. day|hour|week.
*
* @deprecated 7.2.0
*
* @return bool
*/
public function snooze( $duration = 'day' ) {
wc_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '7.2.0' );
if ( ! $this->is_snoozeable() ) {
return false;
}
$snoozed = get_option( self::SNOOZED_OPTION, array() );
$snoozed_until = $this->duration_to_ms[ $duration ] + ( time() * 1000 );
$snoozed[ $this->get_id() ] = $snoozed_until;
$update = update_option( self::SNOOZED_OPTION, $snoozed );
if ( $update ) {
if ( $update ) {
$this->record_tracks_event( 'remindmelater_task', array( 'task_name' => $this->get_id() ) );
}
}
return $update;
}
/**
* Undo task snooze.
*
* @deprecated 7.2.0
*
* @return bool
*/
public function undo_snooze() {
wc_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '7.2.0' );
$snoozed = get_option( self::SNOOZED_OPTION, array() );
unset( $snoozed[ $this->get_id() ] );
$update = update_option( self::SNOOZED_OPTION, $snoozed );
if ( $update ) {
$this->record_tracks_event( 'undo_remindmelater_task', array( 'task_name' => $this->get_id() ) );
}
return $update;
}
/**
* Check if a task list has previously been marked as complete.
*
* @return bool
*/
public function has_previously_completed() {
$complete = get_option( self::COMPLETED_OPTION, array() );
return in_array( $this->get_id(), $complete, true );
}
/**
* Track task completion if task is viewable.
*/
public function possibly_track_completion() {
if ( ! $this->is_complete() ) {
return;
}
if ( $this->has_previously_completed() ) {
return;
}
$completed_tasks = get_option( self::COMPLETED_OPTION, array() );
$completed_tasks[] = $this->get_id();
update_option( self::COMPLETED_OPTION, $completed_tasks );
$this->record_tracks_event( 'task_completed', array( 'task_name' => $this->get_id() ) );
}
/**
* Set this as the active task across page loads.
*/
public function set_active() {
if ( $this->is_complete() ) {
return;
}
set_transient(
self::ACTIVE_TASK_TRANSIENT,
$this->get_id(),
DAY_IN_SECONDS
);
}
/**
* Check if this is the active task.
*/
public function is_active() {
return get_transient( self::ACTIVE_TASK_TRANSIENT ) === $this->get_id();
}
/**
* Check if the store is capable of viewing the task.
*
* @return bool
*/
public function can_view() {
return true;
}
/**
* Check if task is disabled.
*
* @deprecated 7.2.0
*
* @return bool
*/
public function is_disabled() {
wc_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '7.2.0' );
return false;
}
/**
* Check if the task is complete.
*
* @return bool
*/
public function is_complete() {
return self::is_actioned();
}
/**
* Check if the task has been visited.
*
* @return bool
*/
public function is_visited() {
$user_id = get_current_user_id();
$response = WCAdminUser::get_user_data_field( $user_id, 'task_list_tracked_started_tasks' );
$tracked_tasks = $response ? json_decode( $response, true ) : array();
return isset( $tracked_tasks[ $this->get_id() ] ) && $tracked_tasks[ $this->get_id() ] > 0;
}
/**
* Check if should record event when task is viewed
*
* @return bool
*/
public function get_record_view_event(): bool {
return false;
}
/**
* Get the task as JSON.
*
* @return array
*/
public function get_json() {
$this->possibly_track_completion();
return array(
'id' => $this->get_id(),
'parentId' => $this->get_parent_id(),
'title' => $this->get_title(),
'badge' => $this->get_badge(),
'canView' => $this->can_view(),
'content' => $this->get_content(),
'additionalInfo' => $this->get_additional_info(),
'actionLabel' => $this->get_action_label(),
'actionUrl' => $this->get_action_url(),
'isComplete' => $this->is_complete(),
'time' => $this->get_time(),
'level' => 3,
'isActioned' => $this->is_actioned(),
'isDismissed' => $this->is_dismissed(),
'isDismissable' => $this->is_dismissable(),
'isSnoozed' => false,
'isSnoozeable' => false,
'isVisited' => $this->is_visited(),
'isDisabled' => false,
'snoozedUntil' => null,
'additionalData' => self::convert_object_to_camelcase( $this->get_additional_data() ),
'eventPrefix' => $this->prefix_event( '' ),
'recordViewEvent' => $this->get_record_view_event(),
);
}
/**
* Convert object keys to camelcase.
*
* @param array $data Data to convert.
* @return object
*/
public static function convert_object_to_camelcase( $data ) {
if ( ! is_array( $data ) ) {
return $data;
}
$new_object = (object) array();
foreach ( $data as $key => $value ) {
$new_key = lcfirst( implode( '', array_map( 'ucfirst', explode( '_', $key ) ) ) );
$new_object->$new_key = $value;
}
return $new_object;
}
/**
* Mark a task as actioned. Used to verify an action has taken place in some tasks.
*
* @return bool
*/
public function mark_actioned() {
$actioned = get_option( self::ACTIONED_OPTION, array() );
$actioned[] = $this->get_id();
$update = update_option( self::ACTIONED_OPTION, array_unique( $actioned ) );
if ( $update ) {
$this->record_tracks_event( 'actioned_task', array( 'task_name' => $this->get_id() ) );
}
return $update;
}
/**
* Check if a task has been actioned.
*
* @return bool
*/
public function is_actioned() {
return self::is_task_actioned( $this->get_id() );
}
/**
* Check if a provided task ID has been actioned.
*
* @param string $id Task ID.
* @return bool
*/
public static function is_task_actioned( $id ) {
$actioned = get_option( self::ACTIONED_OPTION, array() );
return in_array( $id, $actioned, true );
}
/**
* Sorting function for tasks.
*
* @param Task $a Task a.
* @param Task $b Task b.
* @param array $sort_by list of columns with sort order.
* @return int
*/
public static function sort( $a, $b, $sort_by = array() ) {
$result = 0;
foreach ( $sort_by as $data ) {
$key = $data['key'];
$a_val = $a->$key ?? false;
$b_val = $b->$key ?? false;
if ( 'asc' === $data['order'] ) {
$result = $a_val <=> $b_val;
} else {
$result = $b_val <=> $a_val;
}
if ( 0 !== $result ) {
break;
}
}
return $result;
}
}

View File

@@ -1,424 +0,0 @@
<?php
/**
* Handles storage and retrieval of a task list
*/
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\WCAdminHelper;
/**
* Task List class.
*/
class TaskList {
/**
* Task traits.
*/
use TaskTraits;
/**
* Option name hidden task lists.
*/
const HIDDEN_OPTION = 'woocommerce_task_list_hidden_lists';
/**
* Option name of completed task lists.
*/
const COMPLETED_OPTION = 'woocommerce_task_list_completed_lists';
/**
* Option name of hidden reminder bar.
*/
const REMINDER_BAR_HIDDEN_OPTION = 'woocommerce_task_list_reminder_bar_hidden';
/**
* ID.
*
* @var string
*/
public $id = '';
/**
* ID.
*
* @var string
*/
public $hidden_id = '';
/**
* ID.
*
* @var boolean
*/
public $display_progress_header = false;
/**
* Title.
*
* @var string
*/
public $title = '';
/**
* Tasks.
*
* @var array
*/
public $tasks = array();
/**
* Sort keys.
*
* @var array
*/
public $sort_by = array();
/**
* Event prefix.
*
* @var string|null
*/
public $event_prefix = null;
/**
* Task list visibility.
*
* @var boolean
*/
public $visible = true;
/**
* Array of custom options.
*
* @var array
*/
public $options = array();
/**
* Array of TaskListSection.
*
* @deprecated 7.2.0
*
* @var array
*/
private $sections = array();
/**
* Key value map of task class and id used for sections.
*
* @deprecated 7.2.0
*
* @var array
*/
public $task_class_id_map = array();
/**
* Constructor
*
* @param array $data Task list data.
*/
public function __construct( $data = array() ) {
$defaults = array(
'id' => null,
'hidden_id' => null,
'title' => '',
'tasks' => array(),
'sort_by' => array(),
'event_prefix' => null,
'options' => array(),
'visible' => true,
'display_progress_header' => false,
);
$data = wp_parse_args( $data, $defaults );
$this->id = $data['id'];
$this->hidden_id = $data['hidden_id'];
$this->title = $data['title'];
$this->sort_by = $data['sort_by'];
$this->event_prefix = $data['event_prefix'];
$this->options = $data['options'];
$this->visible = $data['visible'];
$this->display_progress_header = $data['display_progress_header'];
foreach ( $data['tasks'] as $task_name ) {
$class = 'Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\\' . $task_name;
$task = new $class( $this );
$this->add_task( $task );
}
$this->possibly_remove_reminder_bar();
}
/**
* Check if the task list is hidden.
*
* @return bool
*/
public function is_hidden() {
$hidden = get_option( self::HIDDEN_OPTION, array() );
return in_array( $this->hidden_id ? $this->hidden_id : $this->id, $hidden, true );
}
/**
* Check if the task list is visible.
*
* @return bool
*/
public function is_visible() {
if ( ! $this->visible || ! count( $this->get_viewable_tasks() ) > 0 ) {
return false;
}
return ! $this->is_hidden();
}
/**
* Hide the task list.
*
* @return bool
*/
public function hide() {
if ( $this->is_hidden() ) {
return;
}
$viewable_tasks = $this->get_viewable_tasks();
$completed_count = array_reduce(
$viewable_tasks,
function( $total, $task ) {
return $task->is_complete() ? $total + 1 : $total;
},
0
);
$this->record_tracks_event(
'completed',
array(
'action' => 'remove_card',
'completed_task_count' => $completed_count,
'incomplete_task_count' => count( $viewable_tasks ) - $completed_count,
)
);
$hidden = get_option( self::HIDDEN_OPTION, array() );
$hidden[] = $this->hidden_id ? $this->hidden_id : $this->id;
$this->maybe_set_default_layout( $hidden );
return update_option( self::HIDDEN_OPTION, array_unique( $hidden ) );
}
/**
* Sets the default homepage layout to two_columns if "setup" tasklist is completed or hidden.
*
* @param array $completed_or_hidden_tasklist_ids Array of tasklist ids.
*/
public function maybe_set_default_layout( $completed_or_hidden_tasklist_ids ) {
if ( in_array( 'setup', $completed_or_hidden_tasklist_ids, true ) ) {
update_option( 'woocommerce_default_homepage_layout', 'two_columns' );
}
}
/**
* Undo hiding of the task list.
*
* @return bool
*/
public function unhide() {
$hidden = get_option( self::HIDDEN_OPTION, array() );
$hidden = array_diff( $hidden, array( $this->hidden_id ? $this->hidden_id : $this->id ) );
return update_option( self::HIDDEN_OPTION, $hidden );
}
/**
* Check if all viewable tasks are complete.
*
* @return bool
*/
public function is_complete() {
foreach ( $this->get_viewable_tasks() as $viewable_task ) {
if ( $viewable_task->is_complete() === false ) {
return false;
}
}
return true;
}
/**
* Check if a task list has previously been marked as complete.
*
* @return bool
*/
public function has_previously_completed() {
$complete = get_option( self::COMPLETED_OPTION, array() );
return in_array( $this->get_list_id(), $complete, true );
}
/**
* Add task to the task list.
*
* @param Task $task Task class.
*/
public function add_task( $task ) {
if ( ! is_subclass_of( $task, 'Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task' ) ) {
return new \WP_Error(
'woocommerce_task_list_invalid_task',
__( 'Task is not a subclass of `Task`', 'woocommerce' )
);
}
if ( array_search( $task, $this->tasks, true ) ) {
return;
}
$this->tasks[] = $task;
}
/**
* Get only visible tasks in list.
*
* @param string $task_id id of task.
* @return Task
*/
public function get_task( $task_id ) {
return current(
array_filter(
$this->tasks,
function( $task ) use ( $task_id ) {
return $task->get_id() === $task_id;
}
)
);
}
/**
* Get only visible tasks in list.
*
* @return array
*/
public function get_viewable_tasks() {
return array_values(
array_filter(
$this->tasks,
function( $task ) {
return $task->can_view();
}
)
);
}
/**
* Get task list sections.
*
* @deprecated 7.2.0
*
* @return array
*/
public function get_sections() {
wc_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '7.2.0' );
return $this->sections;
}
/**
* Track list completion of viewable tasks.
*/
public function possibly_track_completion() {
if ( ! $this->is_complete() ) {
return;
}
if ( $this->has_previously_completed() ) {
return;
}
$completed_lists = get_option( self::COMPLETED_OPTION, array() );
$completed_lists[] = $this->get_list_id();
update_option( self::COMPLETED_OPTION, $completed_lists );
$this->maybe_set_default_layout( $completed_lists );
$this->record_tracks_event( 'tasks_completed' );
}
/**
* Sorts the attached tasks array.
*
* @param array $sort_by list of columns with sort order.
* @return TaskList returns $this, for chaining.
*/
public function sort_tasks( $sort_by = array() ) {
$sort_by = count( $sort_by ) > 0 ? $sort_by : $this->sort_by;
if ( 0 !== count( $sort_by ) ) {
usort(
$this->tasks,
function( $a, $b ) use ( $sort_by ) {
return Task::sort( $a, $b, $sort_by );
}
);
}
return $this;
}
/**
* Prefix event for track event naming.
*
* @param string $event_name Event name.
* @return string
*/
public function prefix_event( $event_name ) {
if ( null !== $this->event_prefix ) {
return $this->event_prefix . $event_name;
}
return $this->get_list_id() . '_tasklist_' . $event_name;
}
/**
* Returns option to keep completed task list.
*
* @return string
*/
public function get_keep_completed_task_list() {
return get_option( 'woocommerce_task_list_keep_completed', 'no' );
}
/**
* Remove reminder bar four weeks after store creation.
*/
public static function possibly_remove_reminder_bar() {
$bar_hidden = get_option( self::REMINDER_BAR_HIDDEN_OPTION, 'no' );
$active_for_four_weeks = WCAdminHelper::is_wc_admin_active_for( WEEK_IN_SECONDS * 4 );
if ( 'yes' === $bar_hidden || ! $active_for_four_weeks ) {
return;
}
update_option( self::REMINDER_BAR_HIDDEN_OPTION, 'yes' );
}
/**
* Get the list for use in JSON.
*
* @return array
*/
public function get_json() {
$this->possibly_track_completion();
$tasks_json = array();
foreach ( $this->tasks as $task ) {
$json = $task->get_json();
if ( $json['canView'] ) {
$tasks_json[] = $json;
}
}
return array(
'id' => $this->get_list_id(),
'title' => $this->title,
'isHidden' => $this->is_hidden(),
'isVisible' => $this->is_visible(),
'isComplete' => $this->is_complete(),
'tasks' => $tasks_json,
'eventPrefix' => $this->prefix_event( '' ),
'displayProgressHeader' => $this->display_progress_header,
'keepCompletedTaskList' => $this->get_keep_completed_task_list(),
);
}
}

View File

@@ -1,124 +0,0 @@
<?php
/**
* Handles storage and retrieval of a task list section
*/
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
/**
* Task List section class.
*
* @deprecated 7.2.0
*/
class TaskListSection {
/**
* Title.
*
* @var string
*/
public $id = '';
/**
* Title.
*
* @var string
*/
public $title = '';
/**
* Description.
*
* @var string
*/
public $description = '';
/**
* Image.
*
* @var string
*/
public $image = '';
/**
* Tasks.
*
* @var array
*/
public $task_names = array();
/**
* Parent task list.
*
* @var TaskList
*/
protected $task_list;
/**
* Constructor
*
* @param array $data Task list data.
* @param TaskList|null $task_list Parent task list.
*/
public function __construct( $data = array(), $task_list = null ) {
$defaults = array(
'id' => '',
'title' => '',
'description' => '',
'image' => '',
'tasks' => array(),
);
$data = wp_parse_args( $data, $defaults );
$this->task_list = $task_list;
$this->id = $data['id'];
$this->title = $data['title'];
$this->description = $data['description'];
$this->image = $data['image'];
$this->task_names = $data['task_names'];
}
/**
* Returns if section is complete.
*
* @return boolean;
*/
private function is_complete() {
$complete = true;
foreach ( $this->task_names as $task_name ) {
if ( null !== $this->task_list && isset( $this->task_list->task_class_id_map[ $task_name ] ) ) {
$task = $this->task_list->get_task( $this->task_list->task_class_id_map[ $task_name ] );
if ( $task->can_view() && ! $task->is_complete() ) {
$complete = false;
break;
}
}
}
return $complete;
}
/**
* Get the list for use in JSON.
*
* @return array
*/
public function get_json() {
return array(
'id' => $this->id,
'title' => $this->title,
'description' => $this->description,
'image' => $this->image,
'tasks' => array_map(
function( $task_name ) {
if ( null !== $this->task_list && isset( $this->task_list->task_class_id_map[ $task_name ] ) ) {
return $this->task_list->task_class_id_map[ $task_name ];
}
return '';
},
$this->task_names
),
'isComplete' => $this->is_complete(),
);
}
}

View File

@@ -1,459 +0,0 @@
<?php
/**
* Handles storage and retrieval of task lists
*/
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\DeprecatedExtendedTask;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\ReviewShippingOptions;
/**
* Task Lists class.
*/
class TaskLists {
/**
* Class instance.
*
* @var TaskLists instance
*/
protected static $instance = null;
/**
* An array of all registered lists.
*
* @var array
*/
protected static $lists = array();
/**
* Boolean value to indicate if default tasks have been added.
*
* @var boolean
*/
protected static $default_tasks_loaded = false;
/**
* The contents of this array is used in init_tasks() to run their init() methods.
* If the classes do not have an init() method then nothing is executed.
* Beyond that, adding tasks to this list has no effect, see init_default_lists() for the list of tasks.
* that are added for each task list.
*
* @var array
*/
const DEFAULT_TASKS = array(
'StoreDetails',
'Products',
'WooCommercePayments',
'Payments',
'Tax',
'Shipping',
'Marketing',
'Appearance',
'AdditionalPayments',
'ReviewShippingOptions',
'GetMobileApp',
);
/**
* Get class instance.
*/
final public static function instance() {
if ( ! static::$instance ) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Initialize the task lists.
*/
public static function init() {
self::init_default_lists();
add_action( 'admin_init', array( __CLASS__, 'set_active_task' ), 5 );
add_action( 'init', array( __CLASS__, 'init_tasks' ) );
add_action( 'admin_menu', array( __CLASS__, 'menu_task_count' ) );
add_filter( 'woocommerce_admin_shared_settings', array( __CLASS__, 'task_list_preloaded_settings' ), 20 );
}
/**
* Check if an experiment is the treatment or control.
*
* @param string $name Name prefix of experiment.
* @return bool
*/
public static function is_experiment_treatment( $name ) {
$anon_id = isset( $_COOKIE['tk_ai'] ) ? sanitize_text_field( wp_unslash( $_COOKIE['tk_ai'] ) ) : '';
$allow_tracking = 'yes' === get_option( 'woocommerce_allow_tracking' );
$abtest = new \WooCommerce\Admin\Experimental_Abtest(
$anon_id,
'woocommerce',
$allow_tracking
);
$date = new \DateTime();
$date->setTimeZone( new \DateTimeZone( 'UTC' ) );
$experiment_name = sprintf(
'%s_%s_%s',
$name,
$date->format( 'Y' ),
$date->format( 'm' )
);
return $abtest->get_variation( $experiment_name ) === 'treatment';
}
/**
* Initialize default lists.
*/
public static function init_default_lists() {
$tasks = array(
'CustomizeStore',
'StoreDetails',
'Products',
'Appearance',
'WooCommercePayments',
'Payments',
'Tax',
'Shipping',
'Marketing',
);
if ( Features::is_enabled( 'core-profiler' ) ) {
$key = array_search( 'StoreDetails', $tasks, true );
if ( false !== $key ) {
unset( $tasks[ $key ] );
}
}
// Remove the old Personalize your store task if the new CustomizeStore is enabled.
$task_to_remove = Features::is_enabled( 'customize-store' ) ? 'Appearance' : 'CustomizeStore';
$store_customisation_task_index = array_search( $task_to_remove, $tasks, true );
if ( false !== $store_customisation_task_index ) {
unset( $tasks[ $store_customisation_task_index ] );
}
self::add_list(
array(
'id' => 'setup',
'title' => __( 'Get ready to start selling', 'woocommerce' ),
'tasks' => $tasks,
'display_progress_header' => true,
'event_prefix' => 'tasklist_',
'options' => array(
'use_completed_title' => true,
),
'visible' => true,
)
);
self::add_list(
array(
'id' => 'extended',
'title' => __( 'Things to do next', 'woocommerce' ),
'sort_by' => array(
array(
'key' => 'is_complete',
'order' => 'asc',
),
array(
'key' => 'level',
'order' => 'asc',
),
),
'tasks' => array(
'AdditionalPayments',
'GetMobileApp',
),
)
);
if ( Features::is_enabled( 'shipping-smart-defaults' ) ) {
self::add_task(
'extended',
new ReviewShippingOptions(
self::get_list( 'extended' )
)
);
// Tasklist that will never be shown in homescreen,
// used for having tasks that are accessed by other means.
self::add_list(
array(
'id' => 'secret_tasklist',
'hidden_id' => 'setup',
'tasks' => array(
'ExperimentalShippingRecommendation',
),
'event_prefix' => 'secret_tasklist_',
'visible' => false,
)
);
}
if ( has_filter( 'woocommerce_admin_experimental_onboarding_tasklists' ) ) {
/**
* Filter to override default task lists.
*
* @since 7.4
* @param array $lists Array of tasklists.
*/
self::$lists = apply_filters( 'woocommerce_admin_experimental_onboarding_tasklists', self::$lists );
}
}
/**
* Initialize tasks.
*/
public static function init_tasks() {
foreach ( self::DEFAULT_TASKS as $task ) {
$class = 'Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\\' . $task;
if ( ! method_exists( $class, 'init' ) ) {
continue;
}
$class::init();
}
}
/**
* Temporarily store the active task to persist across page loads when necessary.
* Most tasks do not need this.
*/
public static function set_active_task() {
if ( ! isset( $_GET[ Task::ACTIVE_TASK_TRANSIENT ] ) || ! current_user_can( 'manage_woocommerce' ) ) { // phpcs:ignore csrf ok.
return;
}
$referer = wp_get_referer();
if ( ! $referer || 0 !== strpos( $referer, wc_admin_url() ) ) {
return;
}
$task_id = sanitize_title_with_dashes( wp_unslash( $_GET[ Task::ACTIVE_TASK_TRANSIENT ] ) ); // phpcs:ignore csrf ok.
$task = self::get_task( $task_id );
if ( ! $task ) {
return;
}
$task->set_active();
}
/**
* Add a task list.
*
* @param array $args Task list properties.
* @return \WP_Error|TaskList
*/
public static function add_list( $args ) {
if ( isset( self::$lists[ $args['id'] ] ) ) {
return new \WP_Error(
'woocommerce_task_list_exists',
__( 'Task list ID already exists', 'woocommerce' )
);
}
self::$lists[ $args['id'] ] = new TaskList( $args );
return self::$lists[ $args['id'] ];
}
/**
* Add task to a given task list.
*
* @param string $list_id List ID to add the task to.
* @param Task $task Task object.
*
* @return \WP_Error|Task
*/
public static function add_task( $list_id, $task ) {
if ( ! isset( self::$lists[ $list_id ] ) ) {
return new \WP_Error(
'woocommerce_task_list_invalid_list',
__( 'Task list ID does not exist', 'woocommerce' )
);
}
self::$lists[ $list_id ]->add_task( $task );
}
/**
* Add default extended task lists.
*
* @param array $extended_tasks list of extended tasks.
*/
public static function maybe_add_extended_tasks( $extended_tasks ) {
$tasks = $extended_tasks ?? array();
foreach ( self::$lists as $task_list ) {
if ( 'extended' !== substr( $task_list->id, 0, 8 ) ) {
continue;
}
foreach ( $tasks as $args ) {
$task = new DeprecatedExtendedTask( $task_list, $args );
$task_list->add_task( $task );
}
}
}
/**
* Get all task lists.
*
* @return array
*/
public static function get_lists() {
return self::$lists;
}
/**
* Get all task lists.
*
* @param array $ids list of task list ids.
* @return array
*/
public static function get_lists_by_ids( $ids ) {
return array_filter(
self::$lists,
function( $list ) use ( $ids ) {
return in_array( $list->get_list_id(), $ids, true );
}
);
}
/**
* Get all task list ids.
*
* @return array
*/
public static function get_list_ids() {
return array_keys( self::$lists );
}
/**
* Clear all task lists.
*/
public static function clear_lists() {
self::$lists = array();
return self::$lists;
}
/**
* Get visible task lists.
*/
public static function get_visible() {
return array_filter(
self::get_lists(),
function ( $task_list ) {
return $task_list->is_visible();
}
);
}
/**
* Retrieve a task list by ID.
*
* @param String $id Task list ID.
*
* @return TaskList|null
*/
public static function get_list( $id ) {
if ( isset( self::$lists[ $id ] ) ) {
return self::$lists[ $id ];
}
return null;
}
/**
* Retrieve single task.
*
* @param String $id Task ID.
* @param String $task_list_id Task list ID.
*
* @return Object
*/
public static function get_task( $id, $task_list_id = null ) {
$task_list = $task_list_id ? self::get_list( $task_list_id ) : null;
if ( $task_list_id && ! $task_list ) {
return null;
}
$tasks_to_search = $task_list ? $task_list->tasks : array_reduce(
self::get_lists(),
function ( $all, $curr ) {
return array_merge( $all, $curr->tasks );
},
array()
);
foreach ( $tasks_to_search as $task ) {
if ( $id === $task->get_id() ) {
return $task;
}
}
return null;
}
/**
* Return number of setup tasks remaining
*
* @return number
*/
public static function setup_tasks_remaining() {
$setup_list = self::get_list( 'setup' );
if ( ! $setup_list || $setup_list->is_hidden() || $setup_list->is_complete() ) {
return;
}
$remaining_tasks = array_values(
array_filter(
$setup_list->get_viewable_tasks(),
function( $task ) {
return ! $task->is_complete();
}
)
);
return count( $remaining_tasks );
}
/**
* Add badge to homescreen menu item for remaining tasks
*/
public static function menu_task_count() {
global $submenu;
$tasks_count = self::setup_tasks_remaining();
if ( ! $tasks_count || ! isset( $submenu['woocommerce'] ) ) {
return;
}
foreach ( $submenu['woocommerce'] as $key => $menu_item ) {
if ( 0 === strpos( $menu_item[0], _x( 'Home', 'Admin menu name', 'woocommerce' ) ) ) {
$submenu['woocommerce'][ $key ][0] .= ' <span class="awaiting-mod update-plugins remaining-tasks-badge woocommerce-task-list-remaining-tasks-badge"><span class="count-' . esc_attr( $tasks_count ) . '">' . absint( $tasks_count ) . '</span></span>'; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
break;
}
}
}
/**
* Add visible list ids to component settings.
*
* @param array $settings Component settings.
*
* @return array
*/
public static function task_list_preloaded_settings( $settings ) {
$settings['visibleTaskListIds'] = array_keys( self::get_visible() );
return $settings;
}
}

View File

@@ -1,47 +0,0 @@
<?php
/**
* Task and TaskList Traits
*/
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
defined( 'ABSPATH' ) || exit;
/**
* TaskTraits class.
*/
trait TaskTraits {
/**
* Record a tracks event with the prefixed event name.
*
* @param string $event_name Event name.
* @param array $args Array of tracks arguments.
* @return string Prefixed event name.
*/
public function record_tracks_event( $event_name, $args = array() ) {
if ( ! $this->get_list_id() ) {
return;
}
$prefixed_event_name = $this->prefix_event( $event_name );
wc_admin_record_tracks_event(
$prefixed_event_name,
$args
);
return $prefixed_event_name;
}
/**
* Get the task list ID.
*
* @return string
*/
public function get_list_id() {
$namespaced_class = get_class( $this );
return is_subclass_of( $namespaced_class, 'Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task' )
? $this->get_parent_id()
: $this->id;
}
}

View File

@@ -1,195 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\Payments;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\WooCommercePayments;
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\Init;
/**
* Payments Task
*/
class AdditionalPayments extends Payments {
/**
* Used to cache is_complete() method result.
*
* @var null
*/
private $is_complete_result = null;
/**
* Used to cache can_view() method result.
*
* @var null
*/
private $can_view_result = null;
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'payments';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
return __(
'Set up additional payment options',
'woocommerce'
);
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return __(
'Choose payment providers and enable payment methods at checkout.',
'woocommerce'
);
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return __( '2 minutes', 'woocommerce' );
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
if ( null === $this->is_complete_result ) {
$this->is_complete_result = self::has_enabled_additional_gateways();
}
return $this->is_complete_result;
}
/**
* Task visibility.
*
* @return bool
*/
public function can_view() {
if ( ! Features::is_enabled( 'payment-gateway-suggestions' ) ) {
// Hide task if feature not enabled.
return false;
}
if ( null !== $this->can_view_result ) {
return $this->can_view_result;
}
// Show task if woocommerce-payments is connected or if there are any suggested gateways in other category enabled.
$this->can_view_result = (
WooCommercePayments::is_connected() ||
self::has_enabled_other_category_gateways()
);
// Early return if task is not visible.
if ( ! $this->can_view_result ) {
return false;
}
// Show task if there are any suggested gateways in additional category.
$this->can_view_result = ! empty( self::get_suggestion_gateways( 'category_additional' ) );
return $this->can_view_result;
}
/**
* Check if the store has any enabled gateways in other category.
*
* @return bool
*/
private static function has_enabled_other_category_gateways() {
$other_gateways = self::get_suggestion_gateways( 'category_other' );
$other_gateways_ids = wp_list_pluck( $other_gateways, 'id' );
return self::has_enabled_gateways(
function( $gateway ) use ( $other_gateways_ids ) {
return in_array( $gateway->id, $other_gateways_ids, true );
}
);
}
/**
* Check if the store has any enabled gateways in additional category.
*
* @return bool
*/
private static function has_enabled_additional_gateways() {
$additional_gateways = self::get_suggestion_gateways( 'category_additional' );
$additional_gateways_ids = wp_list_pluck( $additional_gateways, 'id' );
return self::has_enabled_gateways(
function( $gateway ) use ( $additional_gateways_ids ) {
return 'yes' === $gateway->enabled
&& in_array( $gateway->id, $additional_gateways_ids, true );
}
);
}
/**
* Check if the store has any enabled gateways based on the given criteria.
*
* @param callable|null $filter A callback function to filter the gateways.
* @return bool
*/
private static function has_enabled_gateways( $filter = null ) {
$gateways = WC()->payment_gateways->get_available_payment_gateways();
$enabled_gateways = array_filter(
$gateways,
function( $gateway ) use ( $filter ) {
if ( is_callable( $filter ) ) {
return 'yes' === $gateway->enabled && call_user_func( $filter, $gateway );
} else {
return 'yes' === $gateway->enabled;
}
}
);
return ! empty( $enabled_gateways );
}
/**
* Get the list of gateways to suggest.
*
* @param string $filter_by Filter by category. "category_additional" or "category_other".
*
* @return array
*/
private static function get_suggestion_gateways( $filter_by = 'category_additional' ) {
$country = wc_get_base_location()['country'];
$plugin_suggestions = Init::get_suggestions();
$plugin_suggestions = array_filter(
$plugin_suggestions,
function( $plugin ) use ( $country, $filter_by ) {
if ( ! isset( $plugin->{$filter_by} ) || ! isset( $plugin->plugins[0] ) ) {
return false;
}
return in_array( $country, $plugin->{$filter_by}, true );
}
);
return $plugin_suggestions;
}
}

View File

@@ -1,72 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Internal\Admin\Loader;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\Products;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
/**
* Appearance Task
*/
class Appearance extends Task {
/**
* Constructor.
*/
public function __construct() {
if ( ! $this->is_complete() ) {
add_action( 'load-theme-install.php', array( $this, 'mark_actioned' ) );
}
}
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'appearance';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
return __( 'Choose your theme', 'woocommerce' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return __(
"Choose a theme that best fits your brand's look and feel, then make it your own. Change the colors, add your logo, and create pages.",
'woocommerce'
);
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return __( '2 minutes', 'woocommerce' );
}
/**
* Action label.
*
* @return string
*/
public function get_action_label() {
return __( 'Choose theme', 'woocommerce' );
}
}

View File

@@ -1,254 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Jetpack_Gutenberg;
/**
* Customize Your Store Task
*/
class CustomizeStore extends Task {
/**
* Constructor
*
* @param TaskList $task_list Parent task list.
*/
public function __construct( $task_list ) {
parent::__construct( $task_list );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_site_editor_scripts' ) );
add_action( 'show_admin_bar', array( $this, 'possibly_hide_wp_admin_bar' ) );
// Use "switch_theme" instead of "after_switch_theme" because the latter is fired after the next WP load and we don't want to trigger action when switching theme to TT3 via onboarding theme API.
global $_GET;
$theme_switch_via_cys_ai_loader = isset( $_GET['theme_switch_via_cys_ai_loader'] ) ? 1 === absint( $_GET['theme_switch_via_cys_ai_loader'] ) : false;
if ( ! $theme_switch_via_cys_ai_loader ) {
add_action( 'switch_theme', array( $this, 'mark_task_as_complete' ) );
}
// Hook to remove unwanted UI elements when users are viewing with ?cys-hide-admin-bar=true.
add_action( 'wp_head', array( $this, 'possibly_remove_unwanted_ui_elements' ) );
}
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'customize-store';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
return __( 'Customize your store ', 'woocommerce' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return '';
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return '';
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
return get_option( 'woocommerce_admin_customize_store_completed' ) === 'yes';
}
/**
* Task visibility.
*
* @return bool
*/
public function can_view() {
return true;
}
/**
* Action URL.
*
* @return string
*/
public function get_action_url() {
return admin_url( 'wp-admin/admin.php?page=wc-admin&path=%2Fcustomize-store' );
}
/**
* Possibly add site editor scripts.
*/
public function possibly_add_site_editor_scripts() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$is_wc_admin_page = (
isset( $_GET['page'] ) &&
'wc-admin' === $_GET['page'] &&
isset( $_GET['path'] )
);
$is_assembler_hub = $is_wc_admin_page && str_starts_with( wc_clean( wp_unslash( $_GET['path'] ) ), '/customize-store/assembler-hub' );
$is_transitional_page = $is_wc_admin_page && str_starts_with( wc_clean( wp_unslash( $_GET['path'] ) ), '/customize-store/transitional' );
// phpcs:enable WordPress.Security.NonceVerification.Recommended
if ( ! ( $is_assembler_hub || $is_transitional_page ) ) {
return;
}
// See: https://github.com/WordPress/WordPress/blob/master/wp-admin/site-editor.php.
if ( ! wp_is_block_theme() ) {
wp_die( esc_html__( 'The theme you are currently using is not compatible.', 'woocommerce' ) );
}
global $editor_styles;
// Flag that we're loading the block editor.
$current_screen = get_current_screen();
$current_screen->is_block_editor( true );
// Default to is-fullscreen-mode to avoid jumps in the UI.
add_filter(
'admin_body_class',
static function( $classes ) {
return "$classes is-fullscreen-mode";
}
);
$block_editor_context = new \WP_Block_Editor_Context( array( 'name' => 'core/edit-site' ) );
$indexed_template_types = array();
foreach ( get_default_block_template_types() as $slug => $template_type ) {
$template_type['slug'] = (string) $slug;
$indexed_template_types[] = $template_type;
}
$custom_settings = array(
'siteUrl' => site_url(),
'postsPerPage' => get_option( 'posts_per_page' ),
'styles' => get_block_editor_theme_styles(),
'defaultTemplateTypes' => $indexed_template_types,
'defaultTemplatePartAreas' => get_allowed_block_template_part_areas(),
'supportsLayout' => wp_theme_has_theme_json(),
'supportsTemplatePartsMode' => ! wp_is_block_theme() && current_theme_supports( 'block-template-parts' ),
);
// Add additional back-compat patterns registered by `current_screen` et al.
$custom_settings['__experimentalAdditionalBlockPatterns'] = \WP_Block_Patterns_Registry::get_instance()->get_all_registered( true );
$custom_settings['__experimentalAdditionalBlockPatternCategories'] = \WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered( true );
$editor_settings = get_block_editor_settings( $custom_settings, $block_editor_context );
$active_global_styles_id = \WP_Theme_JSON_Resolver::get_user_global_styles_post_id();
$active_theme = get_stylesheet();
$preload_paths = array(
array( '/wp/v2/media', 'OPTIONS' ),
'/wp/v2/types?context=view',
'/wp/v2/types/wp_template?context=edit',
'/wp/v2/types/wp_template-part?context=edit',
'/wp/v2/templates?context=edit&per_page=-1',
'/wp/v2/template-parts?context=edit&per_page=-1',
'/wp/v2/themes?context=edit&status=active',
'/wp/v2/global-styles/' . $active_global_styles_id . '?context=edit',
'/wp/v2/global-styles/' . $active_global_styles_id,
'/wp/v2/global-styles/themes/' . $active_theme,
);
block_editor_rest_api_preload( $preload_paths, $block_editor_context );
wp_add_inline_script(
'wp-blocks',
sprintf(
'window.wcBlockSettings = %s;',
wp_json_encode( $editor_settings )
)
);
// Preload server-registered block schemas.
wp_add_inline_script(
'wp-blocks',
'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings() ) . ');'
);
wp_add_inline_script(
'wp-blocks',
sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( isset( $editor_settings['blockCategories'] ) ? $editor_settings['blockCategories'] : array() ) ),
'after'
);
wp_enqueue_script( 'wp-editor' );
wp_enqueue_script( 'wp-format-library' ); // Not sure if this is needed.
wp_enqueue_script( 'wp-router' );
wp_enqueue_style( 'wp-editor' );
wp_enqueue_style( 'wp-edit-site' );
wp_enqueue_style( 'wp-format-library' );
wp_enqueue_media();
if (
current_theme_supports( 'wp-block-styles' ) &&
( ! is_array( $editor_styles ) || count( $editor_styles ) === 0 )
) {
wp_enqueue_style( 'wp-block-library-theme' );
}
/** This action is documented in wp-admin/edit-form-blocks.php
*
* @since 8.0.3
*/
do_action( 'enqueue_block_editor_assets' );
// Load Jetpack's block editor assets because they are not enqueued by default.
if ( class_exists( 'Jetpack_Gutenberg' ) ) {
Jetpack_Gutenberg::enqueue_block_editor_assets();
}
}
/**
* Mark task as complete.
*/
public function mark_task_as_complete() {
update_option( 'woocommerce_admin_customize_store_completed', 'yes' );
}
/**
* Appends a small style to hide admin bar
*
* @param bool $show Whether to show the admin bar.
*/
public function possibly_hide_wp_admin_bar( $show ) {
if ( isset( $_GET['cys-hide-admin-bar'] ) ) { // @phpcs:ignore
return false;
}
return $show;
}
/**
* Runs script and add styles to remove unwanted elements and hide scrollbar
* when users are viewing with ?cys-hide-admin-bar=true.
*
* @return void
*/
public function possibly_remove_unwanted_ui_elements() {
if ( isset( $_GET['cys-hide-admin-bar'] ) ) { // @phpcs:ignore
echo '
<style type="text/css">
body { overflow: hidden; }
</style>';
}
}
}

View File

@@ -1,96 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\Jetpack\Connection\Manager;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\PluginsHelper;
/**
* Shipping Task
*/
class ExperimentalShippingRecommendation extends Task {
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'shipping-recommendation';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
return __( 'Set up shipping', 'woocommerce' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return '';
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return '';
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
return self::has_plugins_active() && self::has_jetpack_connected();
}
/**
* Task visibility.
*
* @return bool
*/
public function can_view() {
return Features::is_enabled( 'shipping-smart-defaults' );
}
/**
* Action URL.
*
* @return string
*/
public function get_action_url() {
return '';
}
/**
* Check if the store has any shipping zones.
*
* @return bool
*/
public static function has_plugins_active() {
return PluginsHelper::is_plugin_active( 'woocommerce-services' );
}
/**
* Check if the Jetpack is connected.
*
* @return bool
*/
public static function has_jetpack_connected() {
$jetpack_connection_manager = new Manager( 'woocommerce' );
return $jetpack_connection_manager->is_connected() && $jetpack_connection_manager->has_connected_owner();
}
}

View File

@@ -1,106 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\Jetpack\Connection\Manager; // https://github.com/Automattic/jetpack/blob/trunk/projects/packages/connection/src/class-manager.php .
/**
* Get Mobile App Task
*/
class GetMobileApp extends Task {
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'get-mobile-app';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
return __( 'Get the free WooCommerce mobile app', 'woocommerce' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return '';
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return '';
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
return get_option( 'woocommerce_admin_dismissed_mobile_app_modal' ) === 'yes';
}
/**
* Task visibility.
* Can view under these conditions:
* - Jetpack is installed and connected && current site user has a wordpress.com account connected to jetpack
* - Jetpack is not connected && current user is capable of installing plugins
*
* @return bool
*/
public function can_view() {
$jetpack_can_be_installed = current_user_can( 'manage_woocommerce' ) && current_user_can( 'install_plugins' ) && ! self::is_jetpack_connected();
$jetpack_is_installed_and_current_user_connected = self::is_current_user_connected();
return $jetpack_can_be_installed || $jetpack_is_installed_and_current_user_connected;
}
/**
* Determines if site has any users connected to WordPress.com via JetPack
*
* @return bool
*/
private static function is_jetpack_connected() {
if ( class_exists( '\Automattic\Jetpack\Connection\Manager' ) && method_exists( '\Automattic\Jetpack\Connection\Manager', 'is_active' ) ) {
$connection = new Manager();
return $connection->is_active();
}
return false;
}
/**
* Determines if the current user is connected to Jetpack.
*
* @return bool
*/
private static function is_current_user_connected() {
if ( class_exists( '\Automattic\Jetpack\Connection\Manager' ) && method_exists( '\Automattic\Jetpack\Connection\Manager', 'is_user_connected' ) ) {
$connection = new Manager();
return $connection->is_connection_owner();
}
return false;
}
/**
* Action URL.
*
* @return string
*/
public function get_action_url() {
return admin_url( 'admin.php?page=wc-admin&mobileAppModal=true' );
}
}

View File

@@ -1,129 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions\Init as RemoteFreeExtensions;
/**
* Marketing Task
*/
class Marketing extends Task {
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'marketing';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
if ( true === $this->get_parent_option( 'use_completed_title' ) ) {
if ( $this->is_complete() ) {
return __( 'You added sales channels', 'woocommerce' );
}
return __( 'Get more sales', 'woocommerce' );
}
return __( 'Set up marketing tools', 'woocommerce' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return __(
'Add recommended marketing tools to reach new customers and grow your business',
'woocommerce'
);
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return __( '2 minutes', 'woocommerce' );
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
return self::has_installed_extensions();
}
/**
* Task visibility.
*
* @return bool
*/
public function can_view() {
return Features::is_enabled( 'remote-free-extensions' ) && count( self::get_plugins() ) > 0;
}
/**
* Get the marketing plugins.
*
* @return array
*/
public static function get_plugins() {
$bundles = RemoteFreeExtensions::get_extensions(
array(
'task-list/reach',
'task-list/grow',
)
);
return array_reduce(
$bundles,
function( $plugins, $bundle ) {
$visible = array();
foreach ( $bundle['plugins'] as $plugin ) {
if ( $plugin->is_visible ) {
$visible[] = $plugin;
}
}
return array_merge( $plugins, $visible );
},
array()
);
}
/**
* Check if the store has installed marketing extensions.
*
* @return bool
*/
public static function has_installed_extensions() {
$plugins = self::get_plugins();
$remaining = array();
$installed = array();
foreach ( $plugins as $plugin ) {
if ( ! $plugin->is_installed ) {
$remaining[] = $plugin;
} else {
$installed[] = $plugin;
}
}
// Make sure the task has been actioned and a marketing extension has been installed.
if ( count( $installed ) > 0 && Task::is_task_actioned( 'marketing' ) ) {
return true;
}
return false;
}
}

View File

@@ -1,103 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
/**
* Payments Task
*/
class Payments extends Task {
/**
* Used to cache is_complete() method result.
* @var null
*/
private $is_complete_result = null;
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'payments';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
if ( true === $this->get_parent_option( 'use_completed_title' ) ) {
if ( $this->is_complete() ) {
return __( 'You set up payments', 'woocommerce' );
}
return __( 'Set up payments', 'woocommerce' );
}
return __( 'Set up payments', 'woocommerce' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return __(
'Choose payment providers and enable payment methods at checkout.',
'woocommerce'
);
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return __( '2 minutes', 'woocommerce' );
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
if ( $this->is_complete_result === null ) {
$this->is_complete_result = self::has_gateways();
}
return $this->is_complete_result;
}
/**
* Task visibility.
*
* @return bool
*/
public function can_view() {
$woocommerce_payments = $this->task_list->get_task( 'woocommerce-payments' );
return Features::is_enabled( 'payment-gateway-suggestions' ) && ! $woocommerce_payments->can_view();
}
/**
* Check if the store has any enabled gateways.
*
* @return bool
*/
public static function has_gateways() {
$gateways = WC()->payment_gateways->get_available_payment_gateways();
$enabled_gateways = array_filter(
$gateways,
function( $gateway ) {
return 'yes' === $gateway->enabled && 'woocommerce_payments' !== $gateway->id;
}
);
return ! empty( $enabled_gateways );
}
}

View File

@@ -1,167 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
/**
* Products Task
*/
class Products extends Task {
/**
* Constructor
*
* @param TaskList $task_list Parent task list.
*/
public function __construct( $task_list ) {
parent::__construct( $task_list );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_manual_return_notice_script' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_import_return_notice_script' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_load_sample_return_notice_script' ) );
}
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'products';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
if ( $this->get_parent_option( 'use_completed_title' ) === true ) {
if ( $this->is_complete() ) {
return __( 'You added products', 'woocommerce' );
}
return __( 'Add products', 'woocommerce' );
}
return __( 'Add my products', 'woocommerce' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return __(
'Start by adding the first product to your store. You can add your products manually, via CSV, or import them from another service.',
'woocommerce'
);
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return __( '1 minute per product', 'woocommerce' );
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
return self::has_products();
}
/**
* Addtional data.
*
* @return array
*/
public function get_additional_data() {
return array(
'has_products' => self::has_products(),
);
}
/**
* Adds a return to task list notice when completing the manual product task.
*
* @param string $hook Page hook.
*/
public function possibly_add_manual_return_notice_script( $hook ) {
global $post;
if ( $hook !== 'post.php' || $post->post_type !== 'product' ) {
return;
}
if ( ! $this->is_active() || ! $this->is_complete() ) {
return;
}
WCAdminAssets::register_script( 'wp-admin-scripts', 'onboarding-product-notice', true );
// Clear the active task transient to only show notice once per active session.
delete_transient( self::ACTIVE_TASK_TRANSIENT );
}
/**
* Adds a return to task list notice when completing the import product task.
*
* @param string $hook Page hook.
*/
public function possibly_add_import_return_notice_script( $hook ) {
$step = isset( $_GET['step'] ) ? $_GET['step'] : ''; // phpcs:ignore csrf ok, sanitization ok.
if ( $hook !== 'product_page_product_importer' || $step !== 'done' ) {
return;
}
if ( ! $this->is_active() || $this->is_complete() ) {
return;
}
WCAdminAssets::register_script( 'wp-admin-scripts', 'onboarding-product-import-notice', true );
}
/**
* Adds a return to task list notice when completing the loading sample products action.
*
* @param string $hook Page hook.
*/
public function possibly_add_load_sample_return_notice_script( $hook ) {
if ( $hook !== 'edit.php' || get_query_var( 'post_type' ) !== 'product' ) {
return;
}
$referer = wp_get_referer();
if ( ! $referer || strpos( $referer, wc_admin_url() ) !== 0 ) {
return;
}
if ( ! isset( $_GET[ Task::ACTIVE_TASK_TRANSIENT ] ) ) {
return;
}
$task_id = sanitize_title_with_dashes( wp_unslash( $_GET[ Task::ACTIVE_TASK_TRANSIENT ] ) );
if ( $task_id !== $this->get_id() || ! $this->is_complete() ) {
return;
}
WCAdminAssets::register_script( 'wp-admin-scripts', 'onboarding-load-sample-products-notice', true );
}
/**
* Check if the store has any published products.
*
* @return bool
*/
public static function has_products() {
$counts = wp_count_posts('product');
return isset( $counts->publish ) && $counts->publish > 0;
}
}

View File

@@ -1,203 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProducts;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingThemes;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
/**
* Purchase Task
*/
class Purchase extends Task {
/**
* Constructor
*
* @param TaskList $task_list Parent task list.
*/
public function __construct( $task_list ) {
parent::__construct( $task_list );
add_action( 'update_option_woocommerce_onboarding_profile', array( $this, 'clear_dismissal' ), 10, 2 );
}
/**
* Clear dismissal on onboarding product type changes.
*
* @param array $old_value Old value.
* @param array $new_value New value.
*/
public function clear_dismissal( $old_value, $new_value ) {
$product_types = isset( $new_value['product_types'] ) ? (array) $new_value['product_types'] : array();
$previous_product_types = isset( $old_value['product_types'] ) ? (array) $old_value['product_types'] : array();
if ( empty( array_diff( $product_types, $previous_product_types ) ) ) {
return;
}
$this->undo_dismiss();
}
/**
* Get the task arguments.
* ID.
*
* @return string
*/
public function get_id() {
return 'purchase';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
$products = $this->get_paid_products_and_themes();
$first_product = count( $products['purchaseable'] ) >= 1 ? $products['purchaseable'][0] : false;
if ( ! $first_product ) {
return null;
}
$product_label = isset( $first_product['label'] ) ? $first_product['label'] : $first_product['title'];
$additional_count = count( $products['purchaseable'] ) - 1;
if ( $this->get_parent_option( 'use_completed_title' ) && $this->is_complete() ) {
return count( $products['purchaseable'] ) === 1
? sprintf(
/* translators: %1$s: a purchased product name */
__(
'You added %1$s',
'woocommerce'
),
$product_label
)
: sprintf(
/* translators: %1$s: a purchased product name, %2$d the number of other products purchased */
_n(
'You added %1$s and %2$d other product',
'You added %1$s and %2$d other products',
$additional_count,
'woocommerce'
),
$product_label,
$additional_count
);
}
return count( $products['purchaseable'] ) === 1
? sprintf(
/* translators: %1$s: a purchaseable product name */
__(
'Add %s to my store',
'woocommerce'
),
$product_label
)
: sprintf(
/* translators: %1$s: a purchaseable product name, %2$d the number of other products to purchase */
_n(
'Add %1$s and %2$d more product to my store',
'Add %1$s and %2$d more products to my store',
$additional_count,
'woocommerce'
),
$product_label,
$additional_count
);
}
/**
* Content.
*
* @return string
*/
public function get_content() {
$products = $this->get_paid_products_and_themes();
if ( count( $products['remaining'] ) === 1 ) {
return isset( $products['purchaseable'][0]['description'] ) ? $products['purchaseable'][0]['description'] : $products['purchaseable'][0]['excerpt'];
}
return sprintf(
/* translators: %1$s: list of product names comma separated, %2%s the last product name */
__(
'Good choice! You chose to add %1$s and %2$s to your store.',
'woocommerce'
),
implode( ', ', array_slice( $products['remaining'], 0, -1 ) ) . ( count( $products['remaining'] ) > 2 ? ',' : '' ),
end( $products['remaining'] )
);
}
/**
* Action label.
*
* @return string
*/
public function get_action_label() {
return __( 'Purchase & install now', 'woocommerce' );
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return __( '2 minutes', 'woocommerce' );
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
$products = $this->get_paid_products_and_themes();
return count( $products['remaining'] ) === 0;
}
/**
* Dismissable.
*
* @return bool
*/
public function is_dismissable() {
return true;
}
/**
* Task visibility.
*
* @return bool
*/
public function can_view() {
$products = $this->get_paid_products_and_themes();
return count( $products['purchaseable'] ) > 0;
}
/**
* Get purchaseable and remaining products.
*
* @return array purchaseable and remaining products and themes.
*/
public static function get_paid_products_and_themes() {
$relevant_products = OnboardingProducts::get_relevant_products();
$profiler_data = get_option( OnboardingProfile::DATA_OPTION, array() );
$theme = isset( $profiler_data['theme'] ) ? $profiler_data['theme'] : null;
$paid_theme = $theme ? OnboardingThemes::get_paid_theme_by_slug( $theme ) : null;
if ( $paid_theme ) {
$relevant_products['purchaseable'][] = $paid_theme;
if ( isset( $paid_theme['is_installed'] ) && false === $paid_theme['is_installed'] ) {
$relevant_products['remaining'][] = $paid_theme['title'];
}
}
return $relevant_products;
}
}

View File

@@ -1,73 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
/**
* Review Shipping Options Task
*/
class ReviewShippingOptions extends Task {
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'review-shipping';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
return __( 'Review shipping options', 'woocommerce' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return '';
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return '';
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
return get_option( 'woocommerce_admin_reviewed_default_shipping_zones' ) === 'yes';
}
/**
* Task visibility.
*
* @return bool
*/
public function can_view() {
return get_option( 'woocommerce_admin_created_default_shipping_zones' ) === 'yes';
}
/**
* Action URL.
*
* @return string
*/
public function get_action_url() {
return admin_url( 'admin.php?page=wc-settings&tab=shipping' );
}
}

View File

@@ -1,190 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use WC_Data_Store;
/**
* Shipping Task
*/
class Shipping extends Task {
const ZONE_COUNT_TRANSIENT_NAME = 'woocommerce_shipping_task_zone_count_transient';
/**
* Constructor
*
* @param TaskList $task_list Parent task list.
*/
public function __construct( $task_list = null ) {
parent::__construct( $task_list );
// wp_ajax_woocommerce_shipping_zone_methods_save_changes
// and wp_ajax_woocommerce_shipping_zones_save_changes get fired
// when a new zone is added or an existing one has been changed.
add_action( 'wp_ajax_woocommerce_shipping_zones_save_changes', array( __CLASS__, 'delete_zone_count_transient' ), 9 );
add_action( 'wp_ajax_woocommerce_shipping_zone_methods_save_changes', array( __CLASS__, 'delete_zone_count_transient' ), 9 );
add_action( 'woocommerce_shipping_zone_method_added', array( __CLASS__, 'delete_zone_count_transient' ), 9 );
add_action( 'woocommerce_after_shipping_zone_object_save', array( __CLASS__, 'delete_zone_count_transient' ), 9 );
}
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'shipping';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
if ( true === $this->get_parent_option( 'use_completed_title' ) ) {
if ( $this->is_complete() ) {
return __( 'You added shipping costs', 'woocommerce' );
}
return __( 'Add shipping costs', 'woocommerce' );
}
return __( 'Set up shipping', 'woocommerce' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return __(
"Set your store location and where you'll ship to.",
'woocommerce'
);
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return __( '1 minute', 'woocommerce' );
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
return self::has_shipping_zones();
}
/**
* Task visibility.
*
* @return bool
*/
public function can_view() {
if ( Features::is_enabled( 'shipping-smart-defaults' ) ) {
if ( 'yes' === get_option( 'woocommerce_admin_created_default_shipping_zones' ) ) {
// If the user has already created a default shipping zone, we don't need to show the task.
return false;
}
/**
* Do not display the task when:
* - The store sells digital products only
* Display the task when:
* - We don't know where the store's located
* - The store is located in the UK, Australia or Canada
*/
if ( self::is_selling_digital_type_only() ) {
return false;
}
$default_store_country = wc_format_country_state_string( get_option( 'woocommerce_default_country', '' ) )['country'];
// Check if a store address is set so that we don't default to WooCommerce's default country US.
// Similar logic: https://github.com/woocommerce/woocommerce/blob/059d542394b48468587f252dcb6941c6425cd8d3/plugins/woocommerce-admin/client/profile-wizard/steps/store-details/index.js#L511-L516.
$store_country = '';
if ( ! empty( get_option( 'woocommerce_store_address', '' ) ) || 'US' !== $default_store_country ) {
$store_country = $default_store_country;
}
// Unknown country.
if ( empty( $store_country ) ) {
return true;
}
return in_array( $store_country, array( 'CA', 'AU', 'GB', 'ES', 'IT', 'DE', 'FR', 'MX', 'CO', 'CL', 'AR', 'PE', 'BR', 'UY', 'GT', 'NL', 'AT', 'BE' ), true );
}
return self::has_physical_products();
}
/**
* Action URL.
*
* @return string
*/
public function get_action_url() {
return self::has_shipping_zones()
? admin_url( 'admin.php?page=wc-settings&tab=shipping' )
: null;
}
/**
* Check if the store has any shipping zones.
*
* @return bool
*/
public static function has_shipping_zones() {
$zone_count = get_transient( self::ZONE_COUNT_TRANSIENT_NAME );
if ( false !== $zone_count ) {
return (int) $zone_count > 0;
}
$zone_count = count( WC_Data_Store::load( 'shipping-zone' )->get_zones() );
set_transient( self::ZONE_COUNT_TRANSIENT_NAME, $zone_count );
return $zone_count > 0;
}
/**
* Check if the store has physical products.
*
* @return bool
*/
public static function has_physical_products() {
$profiler_data = get_option( OnboardingProfile::DATA_OPTION, array() );
$product_types = isset( $profiler_data['product_types'] ) ? $profiler_data['product_types'] : array();
return in_array( 'physical', $product_types, true );
}
/**
* Delete the zone count transient used in has_shipping_zones() method
* to refresh the cache.
*/
public static function delete_zone_count_transient() {
delete_transient( self::ZONE_COUNT_TRANSIENT_NAME );
}
/**
* Check if the store sells digital products only.
*
* @return bool
*/
private static function is_selling_digital_type_only() {
$profiler_data = get_option( OnboardingProfile::DATA_OPTION, array() );
$product_types = isset( $profiler_data['product_types'] ) ? $profiler_data['product_types'] : array();
return array( 'downloads' ) === $product_types;
}
}

View File

@@ -1,77 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\Features\Onboarding;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
/**
* Store Details Task
*/
class StoreCreation extends Task {
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'store_creation';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
/* translators: Store name */
return sprintf( __( 'You created %s', 'woocommerce' ), get_bloginfo( 'name' ) );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return '';
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return '';
}
/**
* Time.
*
* @return string
*/
public function get_action_url() {
return '';
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
return true;
}
/**
* Check if task is disabled.
*
* @return bool
*/
public function is_disabled() {
return true;
}
}

View File

@@ -1,86 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
/**
* Store Details Task
*/
class StoreDetails extends Task {
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'store_details';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
if ( true === $this->get_parent_option( 'use_completed_title' ) ) {
if ( $this->is_complete() ) {
return __( 'You added store details', 'woocommerce' );
}
return __( 'Add store details', 'woocommerce' );
}
return __( 'Store details', 'woocommerce' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return __(
'Your store address is required to set the origin country for shipping, currencies, and payment options.',
'woocommerce'
);
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return __( '4 minutes', 'woocommerce' );
}
/**
* Time.
*
* @return string
*/
public function get_action_url() {
return ! $this->is_complete() ? admin_url( 'admin.php?page=wc-settings&tab=general&tutorial=true' ) : admin_url( 'admin.php?page=wc-settings&tab=general' );
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
$country = WC()->countries->get_base_country();
$country_locale = WC()->countries->get_country_locale();
$locale = $country_locale[ $country ] ?? array();
$hide_postcode = $locale['postcode']['hidden'] ?? false;
// If postcode is hidden, just check that the store address and city are set.
if ( $hide_postcode ) {
return get_option( 'woocommerce_store_address', '' ) !== '' && get_option( 'woocommerce_store_city', '' ) !== '';
}
// Mark as completed if the store address, city and postcode are set. We don't need to check the country because it's set by default.
return get_option( 'woocommerce_store_address', '' ) !== '' && get_option( 'woocommerce_store_city', '' ) !== '' &&
get_option( 'woocommerce_store_postcode', '' ) !== '';
}
}

View File

@@ -1,169 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\API\Reports\Taxes\Stats\DataStore as TaxDataStore;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
/**
* Tax Task
*/
class Tax extends Task {
/**
* Used to cache is_complete() method result.
* @var null
*/
private $is_complete_result = null;
/**
* Constructor
*
* @param TaskList $task_list Parent task list.
*/
public function __construct( $task_list ) {
parent::__construct( $task_list );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_return_notice_script' ) );
}
/**
* Adds a return to task list notice when completing the task.
*/
public function possibly_add_return_notice_script() {
$page = isset( $_GET['page'] ) ? $_GET['page'] : ''; // phpcs:ignore csrf ok, sanitization ok.
$tab = isset( $_GET['tab'] ) ? $_GET['tab'] : ''; // phpcs:ignore csrf ok, sanitization ok.
if ( $page !== 'wc-settings' || $tab !== 'tax' ) {
return;
}
if ( ! $this->is_active() || $this->is_complete() ) {
return;
}
WCAdminAssets::register_script( 'wp-admin-scripts', 'onboarding-tax-notice', true );
}
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'tax';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
if ( $this->get_parent_option( 'use_completed_title' ) === true ) {
if ( $this->is_complete() ) {
return __( 'You added tax rates', 'woocommerce' );
}
return __( 'Add tax rates', 'woocommerce' );
}
return __( 'Set up tax rates', 'woocommerce' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return self::can_use_automated_taxes()
? __(
'Good news! WooCommerce Tax can automate your sales tax calculations for you.',
'woocommerce'
)
: __(
'Set your store location and configure tax rate settings.',
'woocommerce'
);
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return __( '1 minute', 'woocommerce' );
}
/**
* Action label.
*
* @return string
*/
public function get_action_label() {
return self::can_use_automated_taxes()
? __( 'Yes please', 'woocommerce' )
: __( "Let's go", 'woocommerce' );
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
if ( $this->is_complete_result === null ) {
$wc_connect_taxes_enabled = get_option( 'wc_connect_taxes_enabled' );
$is_wc_connect_taxes_enabled = ( $wc_connect_taxes_enabled === 'yes' ) || ( $wc_connect_taxes_enabled === true ); // seems that in some places boolean is used, and other places 'yes' | 'no' is used
$this->is_complete_result = $is_wc_connect_taxes_enabled ||
count( TaxDataStore::get_taxes( array() ) ) > 0 ||
get_option( 'woocommerce_no_sales_tax' ) !== false;
}
return $this->is_complete_result;
}
/**
* Addtional data.
*
* @return array
*/
public function get_additional_data() {
return array(
'avalara_activated' => PluginsHelper::is_plugin_active( 'woocommerce-avatax' ),
'tax_jar_activated' => class_exists( 'WC_Taxjar' ),
'woocommerce_tax_countries' => self::get_automated_support_countries(),
);
}
/**
* Check if the store has any enabled gateways.
*
* @return bool
*/
public static function can_use_automated_taxes() {
if ( ! class_exists( 'WC_Taxjar' ) ) {
return false;
}
return in_array( WC()->countries->get_base_country(), self::get_automated_support_countries(), true );
}
/**
* Get an array of countries that support automated tax.
*
* @return array
*/
public static function get_automated_support_countries() {
// https://developers.taxjar.com/api/reference/#countries .
$tax_supported_countries = array_merge(
array( 'US', 'CA', 'AU', 'GB' ),
WC()->countries->get_european_union_countries()
);
return $tax_supported_countries;
}
}

View File

@@ -1,76 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
/**
* Tour In-App Marketplace task
*/
class TourInAppMarketplace extends Task {
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'tour-in-app-marketplace';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
return __(
'Discover ways of extending your store with a tour of the Woo Marketplace',
'woocommerce'
);
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return '';
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return '';
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
return get_option( 'woocommerce_admin_dismissed_in_app_marketplace_tour' ) === 'yes';
}
/**
* Action URL.
*
* @return string
*/
public function get_action_url() {
return admin_url( 'admin.php?page=wc-admin&path=%2Fextensions&tutorial=true' );
}
/**
* Check if should record event when task is viewed
*
* @return bool
*/
public function get_record_view_event(): bool {
return true;
}
}

View File

@@ -1,208 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\PluginsHelper;
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\Init as Suggestions;
use Automattic\WooCommerce\Internal\Admin\WCPayPromotion\Init as WCPayPromotionInit;
/**
* WooCommercePayments Task
*/
class WooCommercePayments extends Task {
/**
* Used to cache is_complete() method result.
*
* @var null
*/
private $is_complete_result = null;
/**
* ID.
*
* @return string
*/
public function get_id() {
return 'woocommerce-payments';
}
/**
* Title.
*
* @return string
*/
public function get_title() {
return __( 'Set up WooPayments', 'woocommerce' );
}
/**
* Badge.
*
* @return string
*/
public function get_badge() {
/**
* Filter WooPayments onboarding task badge.
*
* @param string $badge Badge content.
* @since 8.2.0
*/
return apply_filters( 'woocommerce_admin_woopayments_onboarding_task_badge', '' );
}
/**
* Content.
*
* @return string
*/
public function get_content() {
return __(
"You're only one step away from getting paid. Verify your business details to start managing transactions with WooPayments.",
'woocommerce'
);
}
/**
* Time.
*
* @return string
*/
public function get_time() {
return __( '2 minutes', 'woocommerce' );
}
/**
* Action label.
*
* @return string
*/
public function get_action_label() {
return __( 'Finish setup', 'woocommerce' );
}
/**
* Additional info.
*
* @return string
*/
public function get_additional_info() {
if ( WCPayPromotionInit::is_woopay_eligible() ) {
return __(
'By using WooPayments you agree to be bound by our <a href="https://wordpress.com/tos/" target="_blank">Terms of Service</a> (including WooPay <a href="https://wordpress.com/tos/#more-woopay-specifically" target="_blank">merchant terms</a>) and acknowledge that you have read our <a href="https://automattic.com/privacy/" target="_blank">Privacy Policy</a>',
'woocommerce'
);
}
return __(
'By using WooPayments you agree to be bound by our <a href="https://wordpress.com/tos/" target="_blank">Terms of Service</a> and acknowledge that you have read our <a href="https://automattic.com/privacy/" target="_blank">Privacy Policy</a>',
'woocommerce'
);
}
/**
* Task completion.
*
* @return bool
*/
public function is_complete() {
if ( null === $this->is_complete_result ) {
$this->is_complete_result = self::is_connected() && ! self::is_account_partially_onboarded();
}
return $this->is_complete_result;
}
/**
* Task visibility.
*
* @return bool
*/
public function can_view() {
$payments = $this->task_list->get_task( 'payments' );
return ! $payments->is_complete() && // Do not re-display the task if the "add payments" task has already been completed.
self::is_installed() &&
self::is_supported();
}
/**
* Check if the plugin was requested during onboarding.
*
* @return bool
*/
public static function is_requested() {
$profiler_data = get_option( OnboardingProfile::DATA_OPTION, array() );
$product_types = isset( $profiler_data['product_types'] ) ? $profiler_data['product_types'] : array();
$business_extensions = isset( $profiler_data['business_extensions'] ) ? $profiler_data['business_extensions'] : array();
$subscriptions_and_us = in_array( 'subscriptions', $product_types, true ) && 'US' === WC()->countries->get_base_country();
return in_array( 'woocommerce-payments', $business_extensions, true ) || $subscriptions_and_us;
}
/**
* Check if the plugin is installed.
*
* @return bool
*/
public static function is_installed() {
$installed_plugins = PluginsHelper::get_installed_plugin_slugs();
return in_array( 'woocommerce-payments', $installed_plugins, true );
}
/**
* Check if WooCommerce Payments is connected.
*
* @return bool
*/
public static function is_connected() {
if ( class_exists( '\WC_Payments' ) ) {
$wc_payments_gateway = \WC_Payments::get_gateway();
return method_exists( $wc_payments_gateway, 'is_connected' )
? $wc_payments_gateway->is_connected()
: false;
}
return false;
}
/**
* Check if WooCommerce Payments needs setup.
* Errored data or payments not enabled.
*
* @return bool
*/
public static function is_account_partially_onboarded() {
if ( class_exists( '\WC_Payments' ) ) {
$wc_payments_gateway = \WC_Payments::get_gateway();
return method_exists( $wc_payments_gateway, 'is_account_partially_onboarded' )
? $wc_payments_gateway->is_account_partially_onboarded()
: false;
}
return false;
}
/**
* Check if the store is in a supported country.
*
* @return bool
*/
public static function is_supported() {
$suggestions = Suggestions::get_suggestions();
$suggestion_plugins = array_merge(
...array_filter(
array_column( $suggestions, 'plugins' ),
function( $plugins ) {
return is_array( $plugins );
}
)
);
$woocommerce_payments_ids = array_search( 'woocommerce-payments', $suggestion_plugins, true );
if ( false !== $woocommerce_payments_ids ) {
return true;
}
return false;
}
}

View File

@@ -1,33 +0,0 @@
<?php
/**
* Evaluates the spec and returns a status.
*/
namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions;
defined( 'ABSPATH' ) || exit;
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RuleEvaluator;
/**
* Evaluates the spec and returns the evaluated suggestion.
*/
class EvaluateSuggestion {
/**
* Evaluates the spec and returns the suggestion.
*
* @param object|array $spec The suggestion to evaluate.
* @return object The evaluated suggestion.
*/
public static function evaluate( $spec ) {
$rule_evaluator = new RuleEvaluator();
$suggestion = is_array( $spec ) ? (object) $spec : clone $spec;
if ( isset( $suggestion->is_visible ) ) {
$is_visible = $rule_evaluator->evaluate( $suggestion->is_visible );
$suggestion->is_visible = $is_visible;
}
return $suggestion;
}
}

View File

@@ -1,106 +0,0 @@
<?php
/**
* Handles running payment gateway suggestion specs
*/
namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions;
defined( 'ABSPATH' ) || exit;
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\DefaultPaymentGateways;
use Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions\PaymentGatewaysController;
/**
* Remote Payment Methods engine.
* This goes through the specs and gets eligible payment gateways.
*/
class Init {
/**
* Option name for dismissed payment method suggestions.
*/
const RECOMMENDED_PAYMENT_PLUGINS_DISMISS_OPTION = 'woocommerce_setting_payments_recommendations_hidden';
/**
* Constructor.
*/
public function __construct() {
PaymentGatewaysController::init();
add_action( 'update_option_woocommerce_default_country', array( $this, 'delete_specs_transient' ) );
}
/**
* Go through the specs and run them.
*
* @param array|null $specs payment suggestion spec array.
* @return array
*/
public static function get_suggestions( array $specs = null ) {
$suggestions = array();
if ( null === $specs ) {
$specs = self::get_specs();
}
foreach ( $specs as $spec ) {
$suggestion = EvaluateSuggestion::evaluate( $spec );
$suggestions[] = $suggestion;
}
return array_values(
array_filter(
$suggestions,
function( $suggestion ) {
return ! property_exists( $suggestion, 'is_visible' ) || $suggestion->is_visible;
}
)
);
}
/**
* Delete the specs transient.
*/
public static function delete_specs_transient() {
PaymentGatewaySuggestionsDataSourcePoller::get_instance()->delete_specs_transient();
}
/**
* Get specs or fetch remotely if they don't exist.
*/
public static function get_specs() {
if ( 'no' === get_option( 'woocommerce_show_marketplace_suggestions', 'yes' ) ) {
return apply_filters( 'woocommerce_admin_payment_gateway_suggestion_specs', DefaultPaymentGateways::get_all() );
}
$specs = PaymentGatewaySuggestionsDataSourcePoller::get_instance()->get_specs_from_data_sources();
// Fetch specs if they don't yet exist.
if ( false === $specs || ! is_array( $specs ) || 0 === count( $specs ) ) {
return apply_filters( 'woocommerce_admin_payment_gateway_suggestion_specs', DefaultPaymentGateways::get_all() );
}
return apply_filters( 'woocommerce_admin_payment_gateway_suggestion_specs', $specs );
}
/**
* Check if suggestions should be shown in the settings screen.
*
* @return bool
*/
public static function should_display() {
if ( 'yes' === get_option( self::RECOMMENDED_PAYMENT_PLUGINS_DISMISS_OPTION, 'no' ) ) {
return false;
}
if ( 'no' === get_option( 'woocommerce_show_marketplace_suggestions', 'yes' ) ) {
return false;
}
return apply_filters( 'woocommerce_allow_payment_recommendations', true );
}
/**
* Dismiss the suggestions.
*/
public static function dismiss() {
return update_option( self::RECOMMENDED_PAYMENT_PLUGINS_DISMISS_OPTION, 'yes' );
}
}

View File

@@ -1,53 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions;
use Automattic\WooCommerce\Admin\DataSourcePoller;
/**
* Specs data source poller class for payment gateway suggestions.
*/
class PaymentGatewaySuggestionsDataSourcePoller extends DataSourcePoller {
/**
* Data Source Poller ID.
*/
const ID = 'payment_gateway_suggestions';
/**
* Default data sources array.
*/
const DATA_SOURCES = array(
'https://woocommerce.com/wp-json/wccom/payment-gateway-suggestions/1.0/suggestions.json',
);
/**
* Class instance.
*
* @var Analytics instance
*/
protected static $instance = null;
/**
* Get class instance.
*/
public static function get_instance() {
if ( ! self::$instance ) {
// Add country query param to data sources.
$base_location = wc_get_base_location();
$data_sources = array_map(
function( $url ) use ( $base_location ) {
return add_query_arg(
'country',
$base_location['country'],
$url
);
},
self::DATA_SOURCES
);
self::$instance = new self( self::ID, $data_sources );
}
return self::$instance;
}
}

View File

@@ -1,148 +0,0 @@
<?php
/**
* Logic for extending WC_REST_Payment_Gateways_Controller.
*/
namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions;
use Automattic\WooCommerce\Admin\Features\TransientNotices;
defined( 'ABSPATH' ) || exit;
/**
* PaymentGateway class
*/
class PaymentGatewaysController {
/**
* Initialize payment gateway changes.
*/
public static function init() {
add_filter( 'woocommerce_rest_prepare_payment_gateway', array( __CLASS__, 'extend_response' ), 10, 3 );
add_filter( 'admin_init', array( __CLASS__, 'possibly_do_connection_return_action' ) );
add_action( 'woocommerce_admin_payment_gateway_connection_return', array( __CLASS__, 'handle_successfull_connection' ) );
}
/**
* Add necessary fields to REST API response.
*
* @param WP_REST_Response $response Response data.
* @param WC_Payment_Gateway $gateway Payment gateway object.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response
*/
public static function extend_response( $response, $gateway, $request ) {
$data = $response->get_data();
$data['needs_setup'] = $gateway->needs_setup();
$data['post_install_scripts'] = self::get_post_install_scripts( $gateway );
$data['settings_url'] = method_exists( $gateway, 'get_settings_url' )
? $gateway->get_settings_url()
: admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . strtolower( $gateway->id ) );
$return_url = wc_admin_url( '&task=payments&connection-return=' . strtolower( $gateway->id ) . '&_wpnonce=' . wp_create_nonce( 'connection-return' ) );
$data['connection_url'] = method_exists( $gateway, 'get_connection_url' )
? $gateway->get_connection_url( $return_url )
: null;
$data['setup_help_text'] = method_exists( $gateway, 'get_setup_help_text' )
? $gateway->get_setup_help_text()
: null;
$data['required_settings_keys'] = method_exists( $gateway, 'get_required_settings_keys' )
? $gateway->get_required_settings_keys()
: array();
$response->set_data( $data );
return $response;
}
/**
* Get payment gateway scripts for post-install.
*
* @param WC_Payment_Gateway $gateway Payment gateway object.
* @return array Install scripts.
*/
public static function get_post_install_scripts( $gateway ) {
$scripts = array();
$wp_scripts = wp_scripts();
$handles = method_exists( $gateway, 'get_post_install_script_handles' )
? $gateway->get_post_install_script_handles()
: array();
foreach ( $handles as $handle ) {
if ( isset( $wp_scripts->registered[ $handle ] ) ) {
$scripts[] = $wp_scripts->registered[ $handle ];
}
}
return $scripts;
}
/**
* Call an action after a gating has been successfully returned.
*/
public static function possibly_do_connection_return_action() {
if (
! isset( $_GET['page'] ) ||
'wc-admin' !== $_GET['page'] ||
! isset( $_GET['task'] ) ||
'payments' !== $_GET['task'] ||
! isset( $_GET['connection-return'] ) ||
! isset( $_GET['_wpnonce'] ) ||
! wp_verify_nonce( wc_clean( wp_unslash( $_GET['_wpnonce'] ) ), 'connection-return' )
) {
return;
}
$gateway_id = sanitize_text_field( wp_unslash( $_GET['connection-return'] ) );
do_action( 'woocommerce_admin_payment_gateway_connection_return', $gateway_id );
}
/**
* Handle a successful gateway connection.
*
* @param string $gateway_id Gateway ID.
*/
public static function handle_successfull_connection( $gateway_id ) {
// phpcs:disable WordPress.Security.NonceVerification
if ( ! isset( $_GET['success'] ) || 1 !== intval( $_GET['success'] ) ) {
return;
}
// phpcs:enable WordPress.Security.NonceVerification
$payment_gateways = WC()->payment_gateways()->payment_gateways();
$payment_gateway = isset( $payment_gateways[ $gateway_id ] ) ? $payment_gateways[ $gateway_id ] : null;
if ( ! $payment_gateway ) {
return;
}
$payment_gateway->update_option( 'enabled', 'yes' );
TransientNotices::add(
array(
'user_id' => get_current_user_id(),
'id' => 'payment-gateway-connection-return-' . str_replace( ',', '-', $gateway_id ),
'status' => 'success',
'content' => sprintf(
/* translators: the title of the payment gateway */
__( '%s connected successfully', 'woocommerce' ),
$payment_gateway->method_title
),
)
);
wc_admin_record_tracks_event(
'tasklist_payment_connect_method',
array(
'payment_method' => $gateway_id,
)
);
wp_safe_redirect( wc_admin_url() );
}
}

View File

@@ -1,217 +0,0 @@
<?php
/**
* WooCommerce Product Editor Block Registration
*/
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
/**
* Product block registration and style registration functionality.
*/
class BlockRegistry {
/**
* Generic blocks directory.
*/
const GENERIC_BLOCKS_DIR = 'product-editor/blocks/generic';
/**
* Product fields blocks directory.
*/
const PRODUCT_FIELDS_BLOCKS_DIR = 'product-editor/blocks/product-fields';
/**
* Array of all available generic blocks.
*/
const GENERIC_BLOCKS = array(
'woocommerce/conditional',
'woocommerce/product-checkbox-field',
'woocommerce/product-collapsible',
'woocommerce/product-radio-field',
'woocommerce/product-pricing-field',
'woocommerce/product-section',
'woocommerce/product-tab',
'woocommerce/product-toggle-field',
'woocommerce/product-taxonomy-field',
'woocommerce/product-text-field',
'woocommerce/product-number-field',
);
/**
* Array of all available product fields blocks.
*/
const PRODUCT_FIELDS_BLOCKS = array(
'woocommerce/product-catalog-visibility-field',
'woocommerce/product-description-field',
'woocommerce/product-downloads-field',
'woocommerce/product-images-field',
'woocommerce/product-inventory-email-field',
'woocommerce/product-sku-field',
'woocommerce/product-name-field',
'woocommerce/product-regular-price-field',
'woocommerce/product-sale-price-field',
'woocommerce/product-schedule-sale-fields',
'woocommerce/product-shipping-class-field',
'woocommerce/product-shipping-dimensions-fields',
'woocommerce/product-summary-field',
'woocommerce/product-tag-field',
'woocommerce/product-inventory-quantity-field',
'woocommerce/product-variation-items-field',
'woocommerce/product-variations-fields',
'woocommerce/product-password-field',
'woocommerce/product-has-variations-notice',
'woocommerce/product-single-variation-notice',
);
/**
* Get a file path for a given block file.
*
* @param string $path File path.
* @param string $dir File directory.
*/
private function get_file_path( $path, $dir ) {
return WC_ABSPATH . WCAdminAssets::get_path( 'js' ) . trailingslashit( $dir ) . $path;
}
/**
* Initialize all blocks.
*/
public function init() {
add_filter( 'block_categories_all', array( $this, 'register_categories' ), 10, 2 );
$this->register_product_blocks();
}
/**
* Register all the product blocks.
*/
private function register_product_blocks() {
foreach ( self::PRODUCT_FIELDS_BLOCKS as $block_name ) {
$this->register_block( $block_name, self::PRODUCT_FIELDS_BLOCKS_DIR );
}
foreach ( self::GENERIC_BLOCKS as $block_name ) {
$this->register_block( $block_name, self::GENERIC_BLOCKS_DIR );
}
}
/**
* Register product related block categories.
*
* @param array[] $block_categories Array of categories for block types.
* @param WP_Block_Editor_Context $editor_context The current block editor context.
*/
public function register_categories( $block_categories, $editor_context ) {
if ( INIT::EDITOR_CONTEXT_NAME === $editor_context->name ) {
$block_categories[] = array(
'slug' => 'woocommerce',
'title' => __( 'WooCommerce', 'woocommerce' ),
'icon' => null,
);
}
return $block_categories;
}
/**
* Get the block name without the "woocommerce/" prefix.
*
* @param string $block_name Block name.
*
* @return string
*/
private function remove_block_prefix( $block_name ) {
if ( 0 === strpos( $block_name, 'woocommerce/' ) ) {
return substr_replace( $block_name, '', 0, strlen( 'woocommerce/' ) );
}
return $block_name;
}
/**
* Augment the attributes of a block by adding attributes that are used by the product editor.
*
* @param array $attributes Block attributes.
*/
private function augment_attributes( $attributes ) {
// Note: If you modify this function, also update the client-side
// registerWooBlockType function in @woocommerce/block-templates.
return array_merge(
$attributes,
array(
'_templateBlockId' => array(
'type' => 'string',
'__experimentalRole' => 'content',
),
'_templateBlockOrder' => array(
'type' => 'integer',
'__experimentalRole' => 'content',
),
'_templateBlockHideConditions' => array(
'type' => 'array',
'__experimentalRole' => 'content',
),
'_templateBlockDisableConditions' => array(
'type' => 'array',
'__experimentalRole' => 'content',
),
'disabled' => isset( $attributes['disabled'] ) ? $attributes['disabled'] : array(
'type' => 'boolean',
'__experimentalRole' => 'content',
),
)
);
}
/**
* Augment the uses_context of a block by adding attributes that are used by the product editor.
*
* @param array $uses_context Block uses_context.
*/
private function augment_uses_context( $uses_context ) {
// Note: If you modify this function, also update the client-side
// registerProductEditorBlockType function in @woocommerce/product-editor.
return array_merge(
isset( $uses_context ) ? $uses_context : array(),
array(
'postType',
)
);
}
/**
* Register a single block.
*
* @param string $block_name Block name.
* @param string $block_dir Block directory.
*
* @return WP_Block_Type|false The registered block type on success, or false on failure.
*/
private function register_block( $block_name, $block_dir ) {
$block_name = $this->remove_block_prefix( $block_name );
$block_json_file = $this->get_file_path( $block_name . '/block.json', $block_dir );
if ( ! file_exists( $block_json_file ) ) {
return false;
}
// phpcs:disable WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
$metadata = json_decode( file_get_contents( $block_json_file ), true );
if ( ! is_array( $metadata ) || ! $metadata['name'] ) {
return false;
}
$registry = \WP_Block_Type_Registry::get_instance();
if ( $registry->is_registered( $metadata['name'] ) ) {
$registry->unregister( $metadata['name'] );
}
return register_block_type_from_metadata(
$block_json_file,
array(
'attributes' => $this->augment_attributes( isset( $metadata['attributes'] ) ? $metadata['attributes'] : array() ),
'uses_context' => $this->augment_uses_context( isset( $metadata['usesContext'] ) ? $metadata['usesContext'] : array() ),
)
);
}
}

View File

@@ -1,241 +0,0 @@
<?php
/**
* WooCommerce Product Block Editor
*/
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Internal\Admin\Features\ProductBlockEditor\ProductTemplates\SimpleProductTemplate;
use Automattic\WooCommerce\Internal\Admin\Features\ProductBlockEditor\ProductTemplates\ProductVariationTemplate;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Internal\Admin\BlockTemplateRegistry\BlockTemplateRegistry;
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\Block;
use Automattic\WooCommerce\Internal\Admin\BlockTemplates\BlockTemplateLogger;
use WP_Block_Editor_Context;
/**
* Loads assets related to the product block editor.
*/
class Init {
/**
* The context name used to identify the editor.
*/
const EDITOR_CONTEXT_NAME = 'woocommerce/edit-product';
/**
* Supported post types.
*
* @var array
*/
private $supported_post_types = array( 'simple' );
/**
* Redirection controller.
*
* @var RedirectionController
*/
private $redirection_controller;
/**
* Constructor
*/
public function __construct() {
if ( Features::is_enabled( 'product-variation-management' ) ) {
array_push( $this->supported_post_types, 'variable' );
}
if ( Features::is_enabled( 'product-external-affiliate' ) ) {
array_push( $this->supported_post_types, 'external' );
}
$this->redirection_controller = new RedirectionController( $this->supported_post_types );
if ( \Automattic\WooCommerce\Utilities\FeaturesUtil::feature_is_enabled( 'product_block_editor' ) ) {
if ( ! Features::is_enabled( 'new-product-management-experience' ) ) {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'dequeue_conflicting_styles' ), 100 );
add_action( 'get_edit_post_link', array( $this, 'update_edit_product_link' ), 10, 2 );
}
add_filter( 'woocommerce_admin_get_user_data_fields', array( $this, 'add_user_data_fields' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
add_filter( 'woocommerce_register_post_type_product_variation', array( $this, 'enable_rest_api_for_product_variation' ) );
add_action( 'current_screen', array( $this, 'set_current_screen_to_block_editor_if_wc_admin' ) );
$block_registry = new BlockRegistry();
$block_registry->init();
$tracks = new Tracks();
$tracks->init();
// Make sure the block template logger is initialized before any templates are created.
BlockTemplateLogger::get_instance();
}
}
/**
* Enqueue scripts needed for the product form block editor.
*/
public function enqueue_scripts() {
if ( ! PageController::is_admin_or_embed_page() ) {
return;
}
$this->register_product_editor_templates();
$editor_settings = $this->get_product_editor_settings();
$script_handle = 'wc-admin-edit-product';
wp_register_script( $script_handle, '', array(), '0.1.0', true );
wp_enqueue_script( $script_handle );
wp_add_inline_script(
$script_handle,
'var productBlockEditorSettings = productBlockEditorSettings || ' . wp_json_encode( $editor_settings ) . ';',
'before'
);
wp_add_inline_script(
$script_handle,
sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( $editor_settings['blockCategories'] ) ),
'before'
);
wp_tinymce_inline_scripts();
wp_enqueue_media();
}
/**
* Enqueue styles needed for the rich text editor.
*/
public function enqueue_styles() {
if ( ! PageController::is_admin_or_embed_page() ) {
return;
}
wp_enqueue_style( 'wp-edit-blocks' );
wp_enqueue_style( 'wp-format-library' );
wp_enqueue_editor();
/**
* Enqueue any block editor related assets.
*
* @since 7.1.0
*/
do_action( 'enqueue_block_editor_assets' );
}
/**
* Dequeue conflicting styles.
*/
public function dequeue_conflicting_styles() {
if ( ! PageController::is_admin_or_embed_page() ) {
return;
}
// Dequeing this to avoid conflicts, until we remove the 'woocommerce-page' class.
wp_dequeue_style( 'woocommerce-blocktheme' );
}
/**
* Update the edit product links when the new experience is enabled.
*
* @param string $link The edit link.
* @param int $post_id Post ID.
* @return string
*/
public function update_edit_product_link( $link, $post_id ) {
$product = wc_get_product( $post_id );
if ( ! $product ) {
return $link;
}
if ( $product->get_type() === 'simple' ) {
return admin_url( 'admin.php?page=wc-admin&path=/product/' . $product->get_id() );
}
return $link;
}
/**
* Enables variation post type in REST API.
*
* @param array $args Array of post type arguments.
* @return array Array of post type arguments.
*/
public function enable_rest_api_for_product_variation( $args ) {
$args['show_in_rest'] = true;
return $args;
}
/**
* Adds fields so that we can store user preferences for the variations block.
*
* @param array $user_data_fields User data fields.
* @return array
*/
public function add_user_data_fields( $user_data_fields ) {
return array_merge(
$user_data_fields,
array(
'variable_product_block_tour_shown',
'product_block_variable_options_notice_dismissed',
'variable_items_without_price_notice_dismissed',
)
);
}
/**
* Sets the current screen to the block editor if a wc-admin page.
*/
public function set_current_screen_to_block_editor_if_wc_admin() {
$screen = get_current_screen();
// phpcs:ignore Squiz.PHP.CommentedOutCode.Found
// (no idea why I need that phpcs:ignore above, but I'm tired trying to re-write this comment to get it to pass)
// we can't check the 'path' query param because client-side routing is used within wc-admin,
// so this action handler is only called on the initial page load from the server, which might
// not be the product edit page (it mostly likely isn't).
if ( PageController::is_admin_page() ) {
$screen->is_block_editor( true );
wp_add_inline_script(
'wp-blocks',
'wp.blocks && wp.blocks.unstable__bootstrapServerSideBlockDefinitions && wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings() ) . ');'
);
}
}
/**
* Get the product editor settings.
*/
private function get_product_editor_settings() {
$editor_settings = array();
$template_registry = wc_get_container()->get( BlockTemplateRegistry::class );
$block_template_logger = BlockTemplateLogger::get_instance();
$block_template_logger->log_template_events_to_file( 'simple-product' );
$block_template_logger->log_template_events_to_file( 'product-variation' );
$editor_settings['templates'] = array(
'product' => $template_registry->get_registered( 'simple-product' )->get_formatted_template(),
'product_variation' => $template_registry->get_registered( 'product-variation' )->get_formatted_template(),
);
$editor_settings['templateEvents'] = array(
'product' => $block_template_logger->get_formatted_template_events( 'simple-product' ),
'product_variation' => $block_template_logger->get_formatted_template_events( 'product-variation' ),
);
$block_editor_context = new WP_Block_Editor_Context( array( 'name' => self::EDITOR_CONTEXT_NAME ) );
return get_block_editor_settings( $editor_settings, $block_editor_context );
}
/**
* Register product editor templates.
*/
private function register_product_editor_templates() {
$template_registry = wc_get_container()->get( BlockTemplateRegistry::class );
$template_registry->register( new SimpleProductTemplate() );
$template_registry->register( new ProductVariationTemplate() );
}
}

View File

@@ -1,27 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor\ProductTemplates;
use Automattic\WooCommerce\Admin\BlockTemplates\BlockContainerInterface;
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
/**
* Interface for group containers, which contain sections and blocks.
*/
interface GroupInterface extends BlockContainerInterface {
/**
* Adds a new section to the group
*
* @param array $block_config block config.
* @return SectionInterface new block section.
*/
public function add_section( array $block_config ): SectionInterface;
/**
* Adds a new block to the group.
*
* @param array $block_config block config.
*/
public function add_block( array $block_config ): BlockInterface;
}

View File

@@ -1,44 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor\ProductTemplates;
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
use Automattic\WooCommerce\Admin\BlockTemplates\BlockTemplateInterface;
/**
* Interface for block containers.
*/
interface ProductFormTemplateInterface extends BlockTemplateInterface {
/**
* Adds a new group block.
*
* @param array $block_config block config.
* @return GroupInterface new group block.
*/
public function add_group( array $block_config ): GroupInterface;
/**
* Gets Group block by id.
*
* @param string $group_id group id.
* @return GroupInterface|null
*/
public function get_group_by_id( string $group_id ): ?GroupInterface;
/**
* Gets Section block by id.
*
* @param string $section_id section id.
* @return SectionInterface|null
*/
public function get_section_by_id( string $section_id ): ?SectionInterface;
/**
* Gets Block by id.
*
* @param string $block_id block id.
* @return BlockInterface|null
*/
public function get_block_by_id( string $block_id ): ?BlockInterface;
}

View File

@@ -1,28 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor\ProductTemplates;
use Automattic\WooCommerce\Admin\BlockTemplates\BlockContainerInterface;
use Automattic\WooCommerce\Admin\BlockTemplates\BlockInterface;
/**
* Interface for section containers, which contain sub-sections and blocks.
*/
interface SectionInterface extends BlockContainerInterface {
/**
* Adds a new sub-section to the section.
*
* @param array $block_config block config.
* @return SectionInterface new block section.
*/
public function add_section( array $block_config ): SectionInterface;
/**
* Adds a new block to the section.
*
* @param array $block_config block config.
*/
public function add_block( array $block_config ): BlockInterface;
}

View File

@@ -1,150 +0,0 @@
<?php
/**
* WooCommerce Product Editor Redirection Controller
*/
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor;
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
/**
* Handle redirecting to the old or new editor based on features and support.
*/
class RedirectionController {
/**
* Supported post types.
*
* @var array
*/
private $supported_post_types;
/**
* Set up the hooks used for redirection.
*
* @param array $supported_post_types Array of supported post types.
*/
public function __construct( $supported_post_types ) {
$this->supported_post_types = $supported_post_types;
if ( \Automattic\WooCommerce\Utilities\FeaturesUtil::feature_is_enabled( 'product_block_editor' ) ) {
add_action( 'current_screen', array( $this, 'maybe_redirect_to_new_editor' ), 30, 0 );
add_action( 'current_screen', array( $this, 'redirect_non_supported_product_types' ), 30, 0 );
} else {
add_action( 'current_screen', array( $this, 'maybe_redirect_to_old_editor' ), 30, 0 );
}
}
/**
* Check if the current screen is the legacy add product screen.
*/
protected function is_legacy_add_new_screen(): bool {
$screen = get_current_screen();
return 'post' === $screen->base && 'product' === $screen->post_type && 'add' === $screen->action;
}
/**
* Check if the current screen is the legacy edit product screen.
*/
protected function is_legacy_edit_screen(): bool {
$screen = get_current_screen();
return 'post' === $screen->base
&& 'product' === $screen->post_type
&& isset( $_GET['post'] )
&& isset( $_GET['action'] )
&& 'edit' === $_GET['action'];
}
/**
* Check if a product is supported by the new experience.
*
* @param integer $product_id Product ID.
*/
protected function is_product_supported( $product_id ): bool {
$product = $product_id ? wc_get_product( $product_id ) : null;
$digital_product = $product->is_downloadable() || $product->is_virtual();
if ( $product && in_array( $product->get_type(), $this->supported_post_types, true ) ) {
if ( Features::is_enabled( 'product-virtual-downloadable' ) ) {
return true;
}
return ! $digital_product;
}
return false;
}
/**
* Redirects from old product form to the new product form if the
* feature `product_block_editor` is enabled.
*/
public function maybe_redirect_to_new_editor(): void {
if ( $this->is_legacy_add_new_screen() ) {
wp_safe_redirect( admin_url( 'admin.php?page=wc-admin&path=/add-product' ) );
exit();
}
if ( $this->is_legacy_edit_screen() ) {
$product_id = isset( $_GET['post'] ) ? absint( $_GET['post'] ) : null;
if ( ! $this->is_product_supported( $product_id ) ) {
return;
}
wp_safe_redirect( admin_url( 'admin.php?page=wc-admin&path=/product/' . $product_id ) );
exit();
}
}
/**
* Redirects from new product form to the old product form if the
* feature `product_block_editor` is enabled.
*/
public function maybe_redirect_to_old_editor(): void {
$route = $this->get_parsed_route();
if ( 'add-product' === $route['page'] ) {
wp_safe_redirect( admin_url( 'post-new.php?post_type=product' ) );
exit();
}
if ( 'product' === $route['page'] ) {
wp_safe_redirect( admin_url( 'post.php?post=' . $route['product_id'] . '&action=edit' ) );
exit();
}
}
/**
* Get the parsed WooCommerce Admin path.
*/
protected function get_parsed_route(): array {
if ( ! \Automattic\WooCommerce\Admin\PageController::is_admin_page() || ! isset( $_GET['path'] ) ) {
return array(
'page' => null,
'product_id' => null,
);
}
$path = esc_url_raw( wp_unslash( $_GET['path'] ) );
$path_pieces = explode( '/', wp_parse_url( $path, PHP_URL_PATH ) );
return array(
'page' => $path_pieces[1],
'product_id' => 'product' === $path_pieces[1] ? absint( $path_pieces[2] ) : null,
);
}
/**
* Redirect non supported product types to legacy editor.
*/
public function redirect_non_supported_product_types(): void {
$route = $this->get_parsed_route();
$product_id = $route['product_id'];
if ( 'product' === $route['page'] && ! $this->is_product_supported( $product_id ) ) {
wp_safe_redirect( admin_url( 'post.php?post=' . $route['product_id'] . '&action=edit' ) );
exit();
}
}
}

View File

@@ -1,54 +0,0 @@
<?php
/**
* WooCommerce Product Block Editor
*/
namespace Automattic\WooCommerce\Admin\Features\ProductBlockEditor;
/**
* Add tracks for the product block editor.
*/
class Tracks {
/**
* Initialize the tracks.
*/
public function init() {
add_filter( 'woocommerce_product_source', array( $this, 'add_product_source' ) );
}
/**
* Check if a URL is a product editor page.
*
* @param string $url Url to check.
* @return boolean
*/
protected function is_product_editor_page( $url ) {
$query_string = wp_parse_url( wp_get_referer(), PHP_URL_QUERY );
parse_str( $query_string, $query );
if ( ! isset( $query['page'] ) || 'wc-admin' !== $query['page'] || ! isset( $query['path'] ) ) {
return false;
}
$path_pieces = explode( '/', $query['path'] );
$route = $path_pieces[1];
return 'add-product' === $route || 'product' === $route;
}
/**
* Update the product source if we're on the product editor page.
*
* @param string $source Source of product.
* @return string
*/
public function add_product_source( $source ) {
if ( $this->is_product_editor_page( wp_get_referer() ) ) {
return 'product-block-editor-v1';
}
return $source;
}
}

View File

@@ -1,267 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\ShippingPartnerSuggestions;
/**
* Default Shipping Partners
*/
class DefaultShippingPartners {
/**
* Get default specs.
*
* @return array Default specs.
*/
public static function get_all() {
$asset_base_url = WC()->plugin_url() . '/assets/images/shipping_partners/';
$column_layout_features = array(
array(
'icon' => $asset_base_url . 'timer.svg',
'title' => __( 'Save time', 'woocommerce' ),
'description' => __(
'Automatically import order information to quickly print your labels.',
'woocommerce'
),
),
array(
'icon' => $asset_base_url . 'discount.svg',
'title' => __( 'Save money', 'woocommerce' ),
'description' => __(
'Shop for the best shipping rates, and access pre-negotiated discounted rates.',
'woocommerce'
),
),
array(
'icon' => $asset_base_url . 'star.svg',
'title' => __( 'Wow your shoppers', 'woocommerce' ),
'description' => __(
'Keep your customers informed with tracking notifications.',
'woocommerce'
),
),
);
$check_icon = $asset_base_url . 'check.svg';
return array(
array(
'name' => 'ShipStation',
'slug' => 'woocommerce-shipstation-integration',
'description' => __( 'Powerful yet easy-to-use solution:', 'woocommerce' ),
'layout_column' => array(
'image' => $asset_base_url . 'shipstation-column.svg',
'features' => $column_layout_features,
),
'layout_row' => array(
'image' => $asset_base_url . 'shipstation-row.svg',
'features' => array(
array(
'icon' => $check_icon,
'description' => __(
'Print labels from Royal Mail, Parcel Force, DPD, and many more',
'woocommerce'
),
),
array(
'icon' => $check_icon,
'description' => __(
'Shop for the best rates, in real-time',
'woocommerce'
),
),
array(
'icon' => $check_icon,
'description' => __( 'Connect selling channels easily', 'woocommerce' ),
),
array(
'icon' => $check_icon,
'description' => __( 'Advance automated workflows', 'woocommerce' ),
),
array(
'icon' => $check_icon,
'description' => __( '30-days free trial', 'woocommerce' ),
),
),
),
'learn_more_link' => 'https://wordpress.org/plugins/woocommerce-shipstation-integration/',
'is_visible' => array(
self::get_rules_for_countries( array( 'AU', 'CA', 'GB' ) ),
),
'available_layouts' => array( 'row', 'column' ),
),
array(
'name' => 'Skydropx',
'slug' => 'skydropx-cotizador-y-envios',
'layout_column' => array(
'image' => $asset_base_url . 'skydropx-column.svg',
'features' => $column_layout_features,
),
'description' => '',
'learn_more_link' => 'https://wordpress.org/plugins/skydropx-cotizador-y-envios/',
'is_visible' => array(
self::get_rules_for_countries( array( 'MX', 'CO' ) ),
),
'available_layouts' => array( 'column' ),
),
array(
'name' => 'Envia',
'slug' => '',
'description' => '',
'layout_column' => array(
'image' => $asset_base_url . 'envia-column.svg',
'features' => $column_layout_features,
),
'learn_more_link' => 'https://woo.com/products/envia-shipping-and-fulfillment/',
'is_visible' => array(
self::get_rules_for_countries( array( 'CL', 'AR', 'PE', 'BR', 'UY', 'GT' ) ),
),
'available_layouts' => array( 'column' ),
),
array(
'name' => 'Sendcloud',
'slug' => 'sendcloud-shipping',
'description' => __( 'All-in-one shipping tool:', 'woocommerce' ),
'layout_column' => array(
'image' => $asset_base_url . 'sendcloud-column.svg',
'features' => $column_layout_features,
),
'layout_row' => array(
'image' => $asset_base_url . 'sendcloud-row.svg',
'features' => array(
array(
'icon' => $check_icon,
'description' => __( 'Print labels from 80+ carriers', 'woocommerce' ),
),
array(
'icon' => $check_icon,
'description' => __(
'Process orders in just a few clicks',
'woocommerce'
),
),
array(
'icon' => $check_icon,
'description' => __( 'Customize checkout options', 'woocommerce' ),
),
array(
'icon' => $check_icon,
'description' => __( 'Self-service tracking & returns', 'woocommerce' ),
),
array(
'icon' => $check_icon,
'description' => __( 'Start with a free plan', 'woocommerce' ),
),
),
),
'learn_more_link' => 'https://wordpress.org/plugins/sendcloud-shipping/',
'is_visible' => array(
self::get_rules_for_countries( array( 'NL', 'AT', 'BE', 'FR', 'DE', 'ES', 'GB', 'IT' ) ),
),
'available_layouts' => array( 'row', 'column' ),
),
array(
'name' => 'Packlink',
'slug' => 'packlink-pro-shipping',
'description' => __( 'Optimize your full shipping process:', 'woocommerce' ),
'layout_column' => array(
'image' => $asset_base_url . 'packlink-column.svg',
'features' => $column_layout_features,
),
'layout_row' => array(
'image' => $asset_base_url . 'packlink-row.svg',
'features' => array(
array(
'icon' => $check_icon,
'description' => __(
'Automated, real-time order import',
'woocommerce'
),
),
array(
'icon' => $check_icon,
'description' => __(
'Direct access to leading carriers',
'woocommerce'
),
),
array(
'icon' => $check_icon,
'description' => __(
'Access competitive shipping prices',
'woocommerce'
),
),
array(
'icon' => $check_icon,
'description' => __( 'Quickly bulk print labels', 'woocommerce' ),
),
array(
'icon' => $check_icon,
'description' => __( 'Free shipping platform', 'woocommerce' ),
),
),
),
'learn_more_link' => 'https://wordpress.org/plugins/packlink-pro-shipping/',
'is_visible' => array(
self::get_rules_for_countries( array( 'FR', 'DE', 'ES', 'IT' ) ),
),
'available_layouts' => array( 'row', 'column' ),
),
array(
'name' => 'WooCommerce Shipping',
'slug' => 'woocommerce-services',
'description' => __( 'Save time and money by printing your shipping labels right from your computer with WooCommerce Shipping. Try WooCommerce Shipping for free.', 'woocommerce' ),
'dependencies' => array( 'jetpack' ),
'layout_column' => array(
'image' => $asset_base_url . 'wcs-column.svg',
'features' => array(
array(
'icon' => $asset_base_url . 'printer.svg',
'title' => __( 'Buy postage when you need it', 'woocommerce' ),
'description' => __( 'No need to wonder where that stampbook went.', 'woocommerce' ),
),
array(
'icon' => $asset_base_url . 'paper.svg',
'title' => __( 'Print at home', 'woocommerce' ),
'description' => __( 'Pick up an order, then just pay, print, package and post.', 'woocommerce' ),
),
array(
'icon' => $asset_base_url . 'discount.svg',
'title' => __( 'Discounted rates', 'woocommerce' ),
'description' => __( 'Access discounted shipping rates with DHL and USPS.', 'woocommerce' ),
),
),
),
'learn_more_link' => 'https://woo.com/products/shipping/',
'is_visible' => array(
self::get_rules_for_countries( array( 'US' ) ),
),
'available_layouts' => array( 'column' ),
),
);
}
/**
* Get rules that match the store base location to one of the provided countries.
*
* @param array $countries Array of countries to match.
* @return object Rules to match.
*/
public static function get_rules_for_countries( $countries ) {
$rules = array();
foreach ( $countries as $country ) {
$rules[] = (object) array(
'type' => 'base_location_country',
'value' => $country,
'operation' => '=',
);
}
return (object) array(
'type' => 'or',
'operands' => $rules,
);
}
}

View File

@@ -1,70 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\ShippingPartnerSuggestions;
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RuleEvaluator;
/**
* Class ShippingPartnerSuggestions
*/
class ShippingPartnerSuggestions {
/**
* Go through the specs and run them.
*
* @param array|null $specs shipping partner suggestion spec array.
* @return array
*/
public static function get_suggestions( $specs = null ) {
$suggestions = array();
if ( null === $specs ) {
$specs = self::get_specs_from_datasource();
}
$rule_evaluator = new RuleEvaluator();
foreach ( $specs as &$spec ) {
$spec = is_array( $spec ) ? (object) $spec : $spec;
if ( isset( $spec->is_visible ) ) {
$is_visible = $rule_evaluator->evaluate( $spec->is_visible );
if ( $is_visible ) {
$spec->is_visible = true;
$suggestions[] = $spec;
}
}
}
return $suggestions;
}
/**
* Get specs or fetch remotely if they don't exist.
*/
public static function get_specs_from_datasource() {
if ( 'no' === get_option( 'woocommerce_show_marketplace_suggestions', 'yes' ) ) {
/**
* It can be used to modify shipping partner suggestions spec.
*
* @since 7.4.1
*/
return apply_filters( 'woocommerce_admin_shipping_partner_suggestions_specs', DefaultShippingPartners::get_all() );
}
$specs = ShippingPartnerSuggestionsDataSourcePoller::get_instance()->get_specs_from_data_sources();
// Fetch specs if they don't yet exist.
if ( false === $specs || ! is_array( $specs ) || 0 === count( $specs ) ) {
/**
* It can be used to modify shipping partner suggestions spec.
*
* @since 7.4.1
*/
return apply_filters( 'woocommerce_admin_shipping_partner_suggestions_specs', DefaultShippingPartners::get_all() );
}
/**
* It can be used to modify shipping partner suggestions spec.
*
* @since 7.4.1
*/
return apply_filters( 'woocommerce_admin_shipping_partner_suggestions_specs', $specs );
}
}

View File

@@ -1,40 +0,0 @@
<?php
namespace Automattic\WooCommerce\Admin\Features\ShippingPartnerSuggestions;
use Automattic\WooCommerce\Admin\DataSourcePoller;
/**
* Specs data source poller class for shipping partner suggestions.
*/
class ShippingPartnerSuggestionsDataSourcePoller extends DataSourcePoller {
/**
* Data Source Poller ID.
*/
const ID = 'shipping_partner_suggestions';
/**
* Default data sources array.
*/
const DATA_SOURCES = array(
'https://woocommerce.com/wp-json/wccom/shipping-partner-suggestions/1.0/suggestions.json',
);
/**
* Class instance.
*
* @var ShippingPartnerSuggestionsDataSourcePoller instance
*/
protected static $instance = null;
/**
* Get class instance.
*/
public static function get_instance() {
if ( ! self::$instance ) {
self::$instance = new self( self::ID, self::DATA_SOURCES );
}
return self::$instance;
}
}

View File

@@ -1,123 +0,0 @@
<?php
/**
* WooCommerce Transient Notices
*/
namespace Automattic\WooCommerce\Admin\Features;
use Automattic\WooCommerce\Internal\Admin\Loader;
/**
* Shows print shipping label banner on edit order page.
*/
class TransientNotices {
/**
* Option name for the queue.
*/
const QUEUE_OPTION = 'woocommerce_admin_transient_notices_queue';
/**
* Constructor
*/
public function __construct() {
add_filter( 'woocommerce_admin_preload_options', array( $this, 'preload_options' ) );
}
/**
* Get all notices in the queue.
*
* @return array
*/
public static function get_queue() {
return get_option( self::QUEUE_OPTION, array() );
}
/**
* Get all notices in the queue by a given user ID.
*
* @param int $user_id User ID.
* @return array
*/
public static function get_queue_by_user( $user_id ) {
$notices = self::get_queue();
return array_filter(
$notices,
function( $notice ) use ( $user_id ) {
return ! isset( $notice['user_id'] ) ||
null === $notice['user_id'] ||
$user_id === $notice['user_id'];
}
);
}
/**
* Get a notice by ID.
*
* @param array $notice_id Notice of ID to get.
* @return array|null
*/
public static function get( $notice_id ) {
$queue = self::get_queue();
if ( isset( $queue[ $notice_id ] ) ) {
return $queue[ $notice_id ];
}
return null;
}
/**
* Add a notice to be shown.
*
* @param array $notice Notice.
* $notice = array(
* 'id' => (string) Unique ID for the notice. Required.
* 'user_id' => (int|null) User ID to show the notice to.
* 'status' => (string) info|error|success
* 'content' => (string) Content to be shown for the notice. Required.
* 'options' => (array) Array of options to be passed to the notice component.
* See https://developer.wordpress.org/block-editor/reference-guides/data/data-core-notices/#createNotice for available options.
* ).
*/
public static function add( $notice ) {
$queue = self::get_queue();
$defaults = array(
'user_id' => null,
'status' => 'info',
'options' => array(),
);
$notice_data = array_merge( $defaults, $notice );
$notice_data['options'] = (object) $notice_data['options'];
$queue[ $notice['id'] ] = $notice_data;
update_option( self::QUEUE_OPTION, $queue );
}
/**
* Remove a notice by ID.
*
* @param array $notice_id Notice of ID to remove.
*/
public static function remove( $notice_id ) {
$queue = self::get_queue();
unset( $queue[ $notice_id ] );
update_option( self::QUEUE_OPTION, $queue );
}
/**
* Preload options to prime state of the application.
*
* @param array $options Array of options to preload.
* @return array
*/
public function preload_options( $options ) {
$options[] = self::QUEUE_OPTION;
return $options;
}
}