woocommerce/plugins/woocommerce-admin/src/FeaturePlugin.php

307 lines
9.3 KiB
PHP

<?php
/**
* WooCommerce Admin: Feature plugin main class.
*/
namespace Automattic\WooCommerce\Admin;
defined( 'ABSPATH' ) || exit;
use \Automattic\WooCommerce\Admin\Notes\LearnMoreAboutVariableProducts;
use \Automattic\WooCommerce\Admin\Notes\Notes;
use \Automattic\WooCommerce\Admin\Notes\OrderMilestones;
use \Automattic\WooCommerce\Admin\Notes\WooSubscriptionsNotes;
use \Automattic\WooCommerce\Admin\Notes\TrackingOptIn;
use \Automattic\WooCommerce\Admin\Notes\WooCommercePayments;
use \Automattic\WooCommerce\Admin\Notes\InstallJPAndWCSPlugins;
use \Automattic\WooCommerce\Admin\Notes\DrawAttention;
use \Automattic\WooCommerce\Admin\Notes\SetUpAdditionalPaymentTypes;
use \Automattic\WooCommerce\Admin\Notes\TestCheckout;
use \Automattic\WooCommerce\Admin\Notes\SellingOnlineCourses;
use \Automattic\WooCommerce\Admin\Notes\MerchantEmailNotifications\MerchantEmailNotifications;
use \Automattic\WooCommerce\Admin\Notes\WelcomeToWooCommerceForStoreUsers;
use \Automattic\WooCommerce\Admin\Notes\ManageStoreActivityFromHomeScreen;
use \Automattic\WooCommerce\Admin\Notes\NavigationNudge;
use Automattic\WooCommerce\Admin\Features\Features;
/**
* Feature plugin main class.
*
* @internal This file will not be bundled with woo core, only the feature plugin.
* @internal Note this is not called WC_Admin due to a class already existing in core with that name.
*/
class FeaturePlugin {
/**
* The single instance of the class.
*
* @var object
*/
protected static $instance = null;
/**
* Constructor
*
* @return void
*/
protected function __construct() {}
/**
* Get class instance.
*
* @return object Instance.
*/
final public static function instance() {
if ( null === static::$instance ) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Init the feature plugin, only if we can detect both Gutenberg and WooCommerce.
*/
public function init() {
// Load the page controller functions file first to prevent fatal errors when disabling WooCommerce Admin.
$this->define_constants();
require_once WC_ADMIN_ABSPATH . '/includes/page-controller-functions.php';
require_once WC_ADMIN_ABSPATH . '/src/Notes/DeprecatedNotes.php';
require_once WC_ADMIN_ABSPATH . '/includes/core-functions.php';
require_once WC_ADMIN_ABSPATH . '/includes/feature-config.php';
require_once WC_ADMIN_ABSPATH . '/includes/wc-admin-update-functions.php';
register_activation_hook( WC_ADMIN_PLUGIN_FILE, array( $this, 'on_activation' ) );
register_deactivation_hook( WC_ADMIN_PLUGIN_FILE, array( $this, 'on_deactivation' ) );
if ( did_action( 'plugins_loaded' ) ) {
self::on_plugins_loaded();
} else {
// Make sure we hook into `plugins_loaded` before core's Automattic\WooCommerce\Package::init().
// If core is network activated but we aren't, the packaged version of WooCommerce Admin will
// attempt to use a data store that hasn't been loaded yet - because we've defined our constants here.
// See: https://github.com/woocommerce/woocommerce-admin/issues/3869.
add_action( 'plugins_loaded', array( $this, 'on_plugins_loaded' ), 9 );
}
}
/**
* Install DB and create cron events when activated.
*
* @return void
*/
public function on_activation() {
Install::create_tables();
Install::create_events();
}
/**
* Remove WooCommerce Admin scheduled actions on deactivate.
*
* @return void
*/
public function on_deactivation() {
// Don't clean up if the WooCommerce Admin package is in core.
// NOTE: Any future divergence from the core package will need to be accounted for here.
if ( defined( 'WC_ADMIN_PACKAGE_EXISTS' ) && WC_ADMIN_PACKAGE_EXISTS ) {
return;
}
// Check if we are deactivating due to dependencies not being satisfied.
// If WooCommerce is disabled we can't include files that depend upon it.
if ( ! $this->has_satisfied_dependencies() ) {
return;
}
$this->includes();
ReportsSync::clear_queued_actions();
Notes::clear_queued_actions();
wp_clear_scheduled_hook( 'wc_admin_daily' );
wp_clear_scheduled_hook( 'generate_category_lookup_table' );
}
/**
* Setup plugin once all other plugins are loaded.
*
* @return void
*/
public function on_plugins_loaded() {
$this->load_plugin_textdomain();
if ( ! $this->has_satisfied_dependencies() ) {
add_action( 'admin_init', array( $this, 'deactivate_self' ) );
add_action( 'admin_notices', array( $this, 'render_dependencies_notice' ) );
return;
}
$this->hooks();
$this->includes();
}
/**
* Define Constants.
*/
protected function define_constants() {
$this->define( 'WC_ADMIN_APP', 'wc-admin-app' );
$this->define( 'WC_ADMIN_ABSPATH', dirname( __DIR__ ) . '/' );
$this->define( 'WC_ADMIN_DIST_JS_FOLDER', 'dist/' );
$this->define( 'WC_ADMIN_DIST_CSS_FOLDER', 'dist/' );
$this->define( 'WC_ADMIN_PLUGIN_FILE', WC_ADMIN_ABSPATH . 'woocommerce-admin.php' );
// WARNING: Do not directly edit this version number constant.
// It is updated as part of the prebuild process from the package.json value.
$this->define( 'WC_ADMIN_VERSION_NUMBER', '2.5.0-dev' );
}
/**
* Load Localisation files.
*/
protected function load_plugin_textdomain() {
load_plugin_textdomain( 'woocommerce-admin', false, basename( dirname( __DIR__ ) ) . '/languages' );
}
/**
* Include WC Admin classes.
*/
public function includes() {
// Initialize Database updates, option migrations, and Notes.
Install::init();
Events::instance()->init();
Notes::init();
// Initialize Plugins Installer.
PluginsInstaller::init();
// Initialize API.
API\Init::instance();
if ( Features::is_enabled( 'analytics' ) ) {
// Initialize Reports syncing.
ReportsSync::init();
CategoryLookup::instance()->init();
// Initialize Reports exporter.
ReportExporter::init();
}
// Admin note providers.
// @todo These should be bundled in the features/ folder, but loading them from there currently has a load order issue.
new WooSubscriptionsNotes();
new OrderMilestones();
new TrackingOptIn();
new WooCommercePayments();
new InstallJPAndWCSPlugins();
new DrawAttention();
new SetUpAdditionalPaymentTypes();
new TestCheckout();
new SellingOnlineCourses();
new LearnMoreAboutVariableProducts();
new WelcomeToWooCommerceForStoreUsers();
new ManageStoreActivityFromHomeScreen();
new NavigationNudge();
// Initialize MerchantEmailNotifications.
MerchantEmailNotifications::init();
}
/**
* Set up our admin hooks and plugin loader.
*/
protected function hooks() {
add_filter( 'woocommerce_admin_features', array( $this, 'replace_supported_features' ), 0 );
Loader::get_instance();
}
/**
* Get an array of dependency error messages.
*
* @return array
*/
protected function get_dependency_errors() {
$errors = array();
$wordpress_version = get_bloginfo( 'version' );
$minimum_wordpress_version = '5.4';
$minimum_woocommerce_version = '4.8';
$wordpress_minimum_met = version_compare( $wordpress_version, $minimum_wordpress_version, '>=' );
$woocommerce_minimum_met = class_exists( 'WooCommerce' ) && version_compare( WC_VERSION, $minimum_woocommerce_version, '>=' );
if ( ! $woocommerce_minimum_met ) {
$errors[] = sprintf(
/* translators: 1: URL of WooCommerce plugin, 2: The minimum WooCommerce version number */
__( 'The WooCommerce Admin feature plugin requires <a href="%1$s">WooCommerce</a> %2$s or greater to be installed and active.', 'woocommerce-admin' ),
'https://wordpress.org/plugins/woocommerce/',
$minimum_woocommerce_version
);
}
if ( ! $wordpress_minimum_met ) {
$errors[] = sprintf(
/* translators: 1: URL of WordPress.org, 2: The minimum WordPress version number */
__( 'The WooCommerce Admin feature plugin requires <a href="%1$s">WordPress</a> %2$s or greater to be installed and active.', 'woocommerce-admin' ),
'https://wordpress.org/',
$minimum_wordpress_version
);
}
return $errors;
}
/**
* Returns true if all dependencies for the wc-admin plugin are loaded.
*
* @return bool
*/
public function has_satisfied_dependencies() {
$dependency_errors = $this->get_dependency_errors();
return 0 === count( $dependency_errors );
}
/**
* Deactivates this plugin.
*/
public function deactivate_self() {
deactivate_plugins( plugin_basename( WC_ADMIN_PLUGIN_FILE ) );
unset( $_GET['activate'] ); // phpcs:ignore CSRF ok.
}
/**
* Notify users of the plugin requirements.
*/
public function render_dependencies_notice() {
$message = $this->get_dependency_errors();
printf( '<div class="error"><p>%s</p></div>', implode( ' ', $message ) ); /* phpcs:ignore xss ok. */
}
/**
* Overwrites the allowed features array using a local `feature-config.php` file.
*
* @param array $features Array of feature slugs.
*/
public function replace_supported_features( $features ) {
$feature_config = apply_filters( 'woocommerce_admin_get_feature_config', wc_admin_get_feature_config() );
$features = array_keys( array_filter( $feature_config ) );
return $features;
}
/**
* Define constant if not already set.
*
* @param string $name Constant name.
* @param string|bool $value Constant value.
*/
protected function define( $name, $value ) {
if ( ! defined( $name ) ) {
define( $name, $value );
}
}
/**
* Prevent cloning.
*/
private function __clone() {}
/**
* Prevent unserializing.
*/
public function __wakeup() {
die();
}
}