updater = new WC_EDM_Updater(); } // Also deliberately before the WooCommerce check, and for the same // reason as the updater above: the shared parent menu is registered by // whichever of the five plugins boots first, and its label must not // depend on whether THIS plugin got past a gate. // // Registered here rather than by editing includes/shared-menu.php: // that file is byte-identical in all five, and which copy a site loads // is decided by activation order. Changing it there would make a site // with three of five updated show "Manager" or "Nolimit" depending on // who booted first, and change its mind when a plugin is deactivated. // The filter is idempotent, so a plugin still on the old build changes // nothing. add_filter( 'wpmgr_menu_title', array( $this, 'shared_menu_title' ) ); if ( ! class_exists( 'WooCommerce' ) ) { add_action( 'admin_notices', array( $this, 'woocommerce_missing_notice' ) ); return; } load_plugin_textdomain( 'wc-email-discount', false, dirname( plugin_basename( WC_EDM_PLUGIN_FILE ) ) . '/languages' ); $this->includes(); if ( ! empty( $this->missing_files ) ) { add_action( 'admin_notices', array( $this, 'incomplete_install_notice' ) ); } // Everything else builds on these two, so without them the plugin // stays dormant and shows the notice instead of erroring out. if ( ! class_exists( 'WC_EDM_DB' ) || ! class_exists( 'WC_EDM_Helpers' ) ) { return; } // Upgrade the DB schema after plugin updates that skip re-activation. add_action( 'init', array( 'WC_EDM_DB', 'maybe_upgrade' ), 5 ); if ( is_admin() && class_exists( 'WC_EDM_Admin' ) ) { $this->admin = new WC_EDM_Admin(); } if ( class_exists( 'WC_EDM_Frontend' ) ) { $this->frontend = new WC_EDM_Frontend(); } if ( class_exists( 'WC_EDM_Audit_Log' ) ) { $this->audit_log = new WC_EDM_Audit_Log(); } if ( class_exists( 'WC_EDM_REST_API' ) ) { $this->rest_api = new WC_EDM_REST_API(); } } /** * Warn that the plugin folder is incomplete. */ public function incomplete_install_notice() { if ( ! current_user_can( 'activate_plugins' ) ) { return; } echo '

'; echo esc_html__( 'WooCommerce Email Discount Manager could not load all of its files, so some features are unavailable. If you just updated the plugin, reload this page — the upload may still have been in progress. If the warning persists, upload the plugin again.', 'wc-email-discount' ); echo '

'; echo implode( ', ', array_map( 'esc_html', $this->missing_files ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo '

'; } /** * Load class files. */ /** * The files loaded only in an admin request. * * A method rather than a literal inside includes() so a test can read the * actual list. The assertion it replaces searched this file's SOURCE TEXT * for the shared menu's path, which a comment mentioning that path would * have satisfied just as well — the same hollow shape as grepping a file * for the words of the guard it is supposed to have. * * @return string[] */ public static function admin_includes() { return array( 'includes/shared-menu.php', 'includes/class-admin.php', 'includes/class-admin-groups.php', 'includes/class-admin-emails.php', 'includes/class-admin-shipping.php', 'includes/class-admin-audit.php', ); } private function includes() { $files = array( 'includes/class-db.php', 'includes/class-helpers.php', 'includes/class-frontend.php', 'includes/class-audit-log.php', 'includes/class-rate-limiter.php', 'includes/class-rest-api.php', ); if ( is_admin() ) { $files = array_merge( $files, self::admin_includes() ); } foreach ( $files as $file ) { $path = WC_EDM_PLUGIN_DIR . $file; // A missing file is recorded rather than fatal, so a half-copied // upgrade cannot take down wp-admin. if ( is_readable( $path ) ) { require_once $path; } else { $this->missing_files[] = $file; } } } /** * Declare compatibility with WooCommerce HPOS. */ public function declare_wc_compatibility() { if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) { \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', WC_EDM_PLUGIN_FILE, true ); } } /** * Admin notice shown when WooCommerce is not active. */ public function woocommerce_missing_notice() { echo '

'; esc_html_e( 'WooCommerce Email Discount Manager requires WooCommerce to be installed and active.', 'wc-email-discount' ); echo '

'; } /** * Plugin activation: verify WooCommerce and create database tables. */ public static function activate() { $active_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins', array() ) ); if ( ! class_exists( 'WooCommerce' ) && ! in_array( 'woocommerce/woocommerce.php', $active_plugins, true ) ) { deactivate_plugins( plugin_basename( WC_EDM_PLUGIN_FILE ) ); wp_die( esc_html__( 'WooCommerce Email Discount Manager requires WooCommerce to be installed and active. Please activate WooCommerce first.', 'wc-email-discount' ), esc_html__( 'Plugin activation error', 'wc-email-discount' ), array( 'back_link' => true ) ); } require_once WC_EDM_PLUGIN_DIR . 'includes/class-db.php'; WC_EDM_DB::create_tables(); } /** * Plugin deactivation: clear scheduled jobs. Data is left untouched. */ public static function deactivate() { require_once WC_EDM_PLUGIN_DIR . 'includes/class-audit-log.php'; WC_EDM_Audit_Log::unschedule_prune(); } } register_activation_hook( __FILE__, array( 'WC_Email_Discount_Manager', 'activate' ) ); register_deactivation_hook( __FILE__, array( 'WC_Email_Discount_Manager', 'deactivate' ) ); /** * Access the main plugin instance. * * @return WC_Email_Discount_Manager */ function wc_edm() { return WC_Email_Discount_Manager::instance(); } wc_edm();