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

340 lines
10 KiB
PHP
Raw Normal View History

<?php
/**
* WooCommerce Admin: Feature plugin main class.
*
* @package WooCommerce Admin
*/
namespace Automattic\WooCommerce\Admin;
defined( 'ABSPATH' ) || exit;
use \Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes;
use \Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes_Historical_Data;
use \Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes_Order_Milestones;
use \Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes_Woo_Subscriptions_Notes;
use \Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes_Tracking_Opt_In;
use \Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes_WooCommerce_Payments;
use \Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes_Install_JP_And_WCS_Plugins;
use \Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes_Draw_Attention;
Add Coupon feature (https://github.com/woocommerce/woocommerce-admin/pull/4526) * Handle new object for posts and recommendations * Set breadcrumb parent for woocommerce-coupons to be woocommerce-marketing * Add main coupon wrapping component * Render coupon wrapper element below coupon table using wp-admin-scripts * Finish off implementing category param for data store resolvers * Create a helper trait for legacy coupons * Add coupon related titles and descriptions * Add note for the coupons being moved * Allow for querying by note name in the notes Data Store * Revamp coupon moved trait * Add the new note only if we don't have an unactioned note and perform a redirect to ensure menu updates * set_icon is deprecated * Move coupon menu, adding a note for customers * Translate title and descriptions * Whitespace * Account for coupon functionality being disabled * Hide legacy menu before redirect * Don’t keep adding the note if customer dismisses it from inbox * Move behind feature flag * Add note if feature enabled * Add filter to override coupon feature * Tweak option name to refer to wc_admin To help with finding etc. * use css variables * Add the new note only if we don't have an unactioned note * Switch the filter logic so `false` turns off the feature This is a bit more intuitive when utilizing the filter * Remove extraneous string and add trailing new lines * Use correct posts object in tests * Revert accidental removal of where_types * Add coupons category to RecommendedExtensions * Use 1.1 api to get categorized recommendations * Add missing text domains * Fix menu handling to point to woocommerce-marketing * Only load coupon scripts on the coupon page * Rework marketing menu logic to register pages more properly * Use correct wc-admin path for marketing page * Remove separate feature flag WC Admin has existing feature flags to load enable/disable the feature * Only set the coupon parent to marketing when the feature is enabled * Only load coupon feature if marketing feature is enabled Co-authored-by: Dan Bitzer <danielbitzer@gmail.com> Co-authored-by: Jeremy Pry <jeremy.pry@gmail.com>
2020-06-16 02:30:41 +00:00
use \Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes_Coupon_Page_Moved;
Remote inbox notification delivery (https://github.com/woocommerce/woocommerce-admin/pull/4143) * Poll and persist specs * Process specs into admin notes * Add send at time rule processor * Fix style issues * Clear actions before recreating them to avoid dupes * Trigger the RINDS engine when a plugin is activated * Unit test SendAtTimeRuleProcessor * Implement plugins activated rule processor * Don't throw exception for unrecognised rule type. Also unit test around this. * add url_is_action_query to tell whether to wrap the URL in wc_admin_url() call or not * Add NOT rule * revert change to install.php * Drop unimplemented resend after dismissal rule * Add OR rule * Explicitly make "fail" a type of rule that can be applied to a spec * Add plugin version rule processor * Tidy up, don't need to pass $spec everywhere * Remove meta record for action state - not really needed * Move spec runner into it's own class, add some checks around re-unactioning a note * Replace if..else with switch * Just update the option * Check that the JSON coming in is an array * Change OR rule to accept an array of operands * Add Pass rule processor * Fix specs that are initially not published * Rename send at rule to publish after * Add publish before rule * Remove unused interface * Can't use PHP7's anonymous classes * New notification: How to draw attention to your online store * Add feature flag for rule-base inbox notes * rename everything to RemoteInboxNotifications from RINDS * Fix merge fail * fix test * Change preunactioned to pending * Move feature flag check into Events.php * Refactor reading a data source * Rename poll_data_sources function * Refactor EvaluateAndGetStatus::evaluate to take the rule evaluator directly * Check that the response body exists * Add validation and defensive checks * Add rule processor interface * Update note created time on status change * Move non-test dependencies into processor constructors * Update to proposed live URL * Remove setting icon as it's being deprecated Co-authored-by: Rebecca Scott <me@becdetat.com>
2020-06-05 01:51:25 +00:00
use \Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsEngine;
use \Automattic\WooCommerce\Admin\Notes\WC_Admin_Notes_Home_Screen_Feedback;
/**
* 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() {
/**
* Filter allowing WooCommerce Admin to be disabled.
*
* @param bool $disabled False.
*/
if ( apply_filters( 'woocommerce_admin_disabled', false ) ) {
return;
}
$this->define_constants();
require_once WC_ADMIN_ABSPATH . '/includes/core-functions.php';
require_once WC_ADMIN_ABSPATH . '/includes/feature-config.php';
require_once WC_ADMIN_ABSPATH . '/includes/page-controller-functions.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();
WC_Admin_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;
}
if ( ! $this->check_build() ) {
add_action( 'admin_notices', array( $this, 'render_build_notice' ) );
}
$this->includes();
$this->hooks();
}
/**
* 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', '1.3.0-beta.1' );
}
/**
* 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 the WC API extensions.
ReportsSync::init();
Install::init();
Events::instance()->init();
new API\Init();
ReportExporter::init();
// CRUD classes.
WC_Admin_Notes::init();
// Initialize category lookup.
CategoryLookup::instance()->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 WC_Admin_Notes_Woo_Subscriptions_Notes();
new WC_Admin_Notes_Historical_Data();
new WC_Admin_Notes_Order_Milestones();
new WC_Admin_Notes_Tracking_Opt_In();
new WC_Admin_Notes_WooCommerce_Payments();
new WC_Admin_Notes_Install_JP_And_WCS_Plugins();
new WC_Admin_Notes_Draw_Attention();
new WC_Admin_Notes_Home_Screen_Feedback();
Remote inbox notification delivery (https://github.com/woocommerce/woocommerce-admin/pull/4143) * Poll and persist specs * Process specs into admin notes * Add send at time rule processor * Fix style issues * Clear actions before recreating them to avoid dupes * Trigger the RINDS engine when a plugin is activated * Unit test SendAtTimeRuleProcessor * Implement plugins activated rule processor * Don't throw exception for unrecognised rule type. Also unit test around this. * add url_is_action_query to tell whether to wrap the URL in wc_admin_url() call or not * Add NOT rule * revert change to install.php * Drop unimplemented resend after dismissal rule * Add OR rule * Explicitly make "fail" a type of rule that can be applied to a spec * Add plugin version rule processor * Tidy up, don't need to pass $spec everywhere * Remove meta record for action state - not really needed * Move spec runner into it's own class, add some checks around re-unactioning a note * Replace if..else with switch * Just update the option * Check that the JSON coming in is an array * Change OR rule to accept an array of operands * Add Pass rule processor * Fix specs that are initially not published * Rename send at rule to publish after * Add publish before rule * Remove unused interface * Can't use PHP7's anonymous classes * New notification: How to draw attention to your online store * Add feature flag for rule-base inbox notes * rename everything to RemoteInboxNotifications from RINDS * Fix merge fail * fix test * Change preunactioned to pending * Move feature flag check into Events.php * Refactor reading a data source * Rename poll_data_sources function * Refactor EvaluateAndGetStatus::evaluate to take the rule evaluator directly * Check that the response body exists * Add validation and defensive checks * Add rule processor interface * Update note created time on status change * Move non-test dependencies into processor constructors * Update to proposed live URL * Remove setting icon as it's being deprecated Co-authored-by: Rebecca Scott <me@becdetat.com>
2020-06-05 01:51:25 +00:00
// Initialize RemoteInboxNotificationsEngine.
RemoteInboxNotificationsEngine::init();
}
/**
* Set up our admin hooks and plugin loader.
*/
protected function hooks() {
add_filter( 'woocommerce_admin_features', array( $this, 'replace_supported_features' ), 0 );
add_action( 'admin_menu', array( $this, 'register_devdocs_page' ) );
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.3';
$minimum_woocommerce_version = '3.6';
$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 );
}
/**
* Returns true if build file exists.
*
* @return bool
*/
protected function check_build() {
return file_exists( plugin_dir_path( __DIR__ ) . '/dist/app/index.js' );
}
/**
* 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. */
}
/**
* Notify users that the plugin needs to be built.
*/
public function render_build_notice() {
$message_one = __( 'You have installed a development version of WooCommerce Admin which requires files to be built. From the plugin directory, run <code>npm install</code> to install dependencies, <code>npm run build</code> to build the files.', 'woocommerce-admin' );
$message_two = sprintf(
/* translators: 1: URL of GitHub Repository build page */
__( 'Or you can download a pre-built version of the plugin by visiting <a href="%1$s">the releases page in the repository</a>.', 'woocommerce-admin' ),
'https://github.com/woocommerce/woocommerce-admin/releases'
);
printf( '<div class="error"><p>%s %s</p></div>', $message_one, $message_two ); /* 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;
}
/**
* Adds a menu item for the wc-admin devdocs.
*/
public function register_devdocs_page() {
if ( Loader::is_dev() ) {
wc_admin_register_page(
array(
'title' => 'DevDocs',
'parent' => 'woocommerce',
'path' => '/devdocs',
)
);
}
}
/**
* 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.
*/
private function __wakeup() {}
2019-08-14 23:35:02 +00:00
}