Files
nolimit-discounts/woocommerce-email-discount-manager.php
T

291 lines
7.9 KiB
PHP
Raw Normal View History

<?php
/**
* Plugin Name: WooCommerce Email Discount Manager
* Plugin URI: https://gitea.nolimit.dk/kw/woocommerce-email-discount-manager
* Update URI: https://gitea.nolimit.dk/kw/woocommerce-email-discount-manager
* Description: Apply discounts and show/hide shipping methods based on the customer's email address (full address, domain or partial match).
2026-09-16 10:51:57 +02:00
* Version: 1.4.1
* Author: WEDSMP
* License: GPL-2.0-or-later
* Text Domain: wc-email-discount
* Requires at least: 5.8
* Requires PHP: 7.4
* WC requires at least: 6.0
* WC tested up to: 11.1.0
* Requires Plugins: woocommerce
*/
/*
* "Update URI" is what makes updates work, and it is load-bearing in a second
* way that is easy to miss: since WordPress 5.8, a plugin that declares one is
* never asked about on wordpress.org. Remove the line and a .org plugin that
* happens to share this slug could be offered to every shop running this one.
* includes/class-updater.php reads it; nothing else configures the source.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
2026-09-16 10:51:57 +02:00
define( 'WC_EDM_VERSION', '1.4.1' );
define( 'WC_EDM_PLUGIN_FILE', __FILE__ );
define( 'WC_EDM_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'WC_EDM_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
/**
* Main plugin class (singleton).
*/
final class WC_Email_Discount_Manager {
/**
* Singleton instance.
*
* @var WC_Email_Discount_Manager|null
*/
private static $instance = null;
/**
* Admin controller.
*
* @var WC_EDM_Admin|null
*/
public $admin = null;
/**
* Frontend controller.
*
* @var WC_EDM_Frontend|null
*/
public $frontend = null;
/**
* REST API controller.
*
* @var WC_EDM_REST_API|null
*/
public $rest_api = null;
/**
* Audit log controller.
*
* @var WC_EDM_Audit_Log|null
*/
public $audit_log = null;
/**
* Update checker.
*
* @var WC_EDM_Updater|null
*/
public $updater = null;
/**
* Class files that could not be loaded.
*
* A plugin upgrade replaces files one by one, so a request landing
* mid-copy can see an incomplete plugin folder. Tracking what is missing
* lets the plugin degrade instead of taking the whole screen down.
*
* @var string[]
*/
private $missing_files = array();
/**
* Get the singleton instance.
*
* @return WC_Email_Discount_Manager
*/
public static function instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor. Private — use instance().
*/
private function __construct() {
add_action( 'plugins_loaded', array( $this, 'init' ) );
add_action( 'before_woocommerce_init', array( $this, 'declare_wc_compatibility' ) );
}
/**
* Prevent cloning.
*/
private function __clone() {}
/**
* Prevent unserializing.
*/
public function __wakeup() {
_doing_it_wrong( __FUNCTION__, 'Unserializing is not allowed.', '1.0.0' );
}
/**
* Bootstrap once all plugins are loaded.
*/
public function init() {
// Deliberately before the WooCommerce check. Everything else here
// needs WooCommerce, but updates do not — and a shop that has
// WooCommerce switched off for an afternoon must not quietly stop
// receiving fixes for this plugin.
$updater = WC_EDM_PLUGIN_DIR . 'includes/class-updater.php';
if ( is_readable( $updater ) ) {
require_once $updater;
$this->updater = new WC_EDM_Updater();
}
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 '<div class="notice notice-error"><p>';
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 '</p><p><code>';
echo implode( '</code>, <code>', array_map( 'esc_html', $this->missing_files ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '</code></p></div>';
}
/**
* Load class files.
*/
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,
array(
'includes/class-admin.php',
'includes/class-admin-groups.php',
'includes/class-admin-emails.php',
'includes/class-admin-shipping.php',
'includes/class-admin-audit.php',
)
);
}
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 '<div class="notice notice-error"><p>';
esc_html_e( 'WooCommerce Email Discount Manager requires WooCommerce to be installed and active.', 'wc-email-discount' );
echo '</p></div>';
}
/**
* 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();