Files
wc-licensed-product/src/Plugin.php
magdev 1de8257527 Add dashboard widget and auto-expire license cron (v0.3.5)
- Add admin dashboard widget with license statistics
- Add daily wp-cron to auto-expire licenses past expiration date
- Add LicenseExpiredEmail notification for expired licenses
- Add getExpiredActiveLicenses() and autoExpireLicense() to LicenseManager

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 16:05:52 +01:00

273 lines
8.8 KiB
PHP

<?php
/**
* Main Plugin class
*
* @package Jeremias\WcLicensedProduct
*/
declare(strict_types=1);
namespace Jeremias\WcLicensedProduct;
use Jeremias\WcLicensedProduct\Admin\AdminController;
use Jeremias\WcLicensedProduct\Admin\DashboardWidgetController;
use Jeremias\WcLicensedProduct\Admin\OrderLicenseController;
use Jeremias\WcLicensedProduct\Admin\SettingsController;
use Jeremias\WcLicensedProduct\Admin\VersionAdminController;
use Jeremias\WcLicensedProduct\Api\ResponseSigner;
use Jeremias\WcLicensedProduct\Api\RestApiController;
use Jeremias\WcLicensedProduct\Checkout\CheckoutBlocksIntegration;
use Jeremias\WcLicensedProduct\Checkout\CheckoutController;
use Jeremias\WcLicensedProduct\Checkout\StoreApiExtension;
use Jeremias\WcLicensedProduct\Email\LicenseEmailController;
use Jeremias\WcLicensedProduct\Frontend\AccountController;
use Jeremias\WcLicensedProduct\Frontend\DownloadController;
use Jeremias\WcLicensedProduct\License\LicenseManager;
use Jeremias\WcLicensedProduct\License\PluginLicenseChecker;
use Jeremias\WcLicensedProduct\Product\LicensedProductType;
use Jeremias\WcLicensedProduct\Product\VersionManager;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
/**
* Main plugin controller
*/
final class Plugin
{
/**
* Singleton instance
*/
private static ?Plugin $instance = null;
/**
* Twig environment
*/
private Environment $twig;
/**
* License manager
*/
private LicenseManager $licenseManager;
/**
* Version manager
*/
private VersionManager $versionManager;
/**
* Download controller
*/
private DownloadController $downloadController;
/**
* Get singleton instance
*/
public static function instance(): Plugin
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Get singleton instance (alias for instance())
*/
public static function getInstance(): Plugin
{
return self::instance();
}
/**
* Private constructor for singleton
*/
private function __construct()
{
$this->initTwig();
$this->initComponents();
$this->registerHooks();
}
/**
* Initialize Twig environment
*/
private function initTwig(): void
{
$loader = new FilesystemLoader(WC_LICENSED_PRODUCT_PLUGIN_DIR . 'templates');
$this->twig = new Environment($loader, [
'cache' => WP_CONTENT_DIR . '/cache/wc-licensed-product/twig',
'auto_reload' => true, // Always check for template changes
]);
// Add WordPress functions as Twig functions
$this->twig->addFunction(new \Twig\TwigFunction('__', function (string $text, string $domain = 'wc-licensed-product'): string {
return __($text, $domain);
}));
$this->twig->addFunction(new \Twig\TwigFunction('esc_html', 'esc_html'));
$this->twig->addFunction(new \Twig\TwigFunction('esc_attr', 'esc_attr'));
$this->twig->addFunction(new \Twig\TwigFunction('esc_url', 'esc_url'));
$this->twig->addFunction(new \Twig\TwigFunction('wp_nonce_field', 'wp_nonce_field', ['is_safe' => ['html']]));
$this->twig->addFunction(new \Twig\TwigFunction('admin_url', 'admin_url'));
$this->twig->addFunction(new \Twig\TwigFunction('wc_get_endpoint_url', 'wc_get_endpoint_url'));
}
/**
* Initialize plugin components
*/
private function initComponents(): void
{
$this->licenseManager = new LicenseManager();
$this->versionManager = new VersionManager();
// Check plugin license
$licenseChecker = PluginLicenseChecker::getInstance();
$isLicensed = $licenseChecker->isLicenseValid();
// Always initialize product type (needed for existing orders)
new LicensedProductType();
// Only initialize frontend components if licensed or on localhost
if ($isLicensed) {
new CheckoutController($this->licenseManager);
new StoreApiExtension($this->licenseManager);
$this->registerCheckoutBlocksIntegration();
$this->downloadController = new DownloadController($this->licenseManager, $this->versionManager);
new AccountController($this->twig, $this->licenseManager, $this->versionManager, $this->downloadController);
}
// Always initialize REST API and email controller
new RestApiController($this->licenseManager);
new LicenseEmailController($this->licenseManager);
// Initialize response signing if server secret is configured
if (defined('WC_LICENSE_SERVER_SECRET') && WC_LICENSE_SERVER_SECRET !== '') {
(new ResponseSigner())->register();
}
// Admin always available
if (is_admin()) {
new AdminController($this->twig, $this->licenseManager);
new VersionAdminController($this->versionManager);
new OrderLicenseController($this->licenseManager);
new SettingsController();
new DashboardWidgetController($this->licenseManager);
// Show admin notice if unlicensed and not on localhost
if (!$isLicensed && !$licenseChecker->isLocalhost()) {
add_action('admin_notices', [$this, 'showUnlicensedNotice']);
}
}
}
/**
* Register WooCommerce Checkout Blocks integration
*/
private function registerCheckoutBlocksIntegration(): void
{
add_action('woocommerce_blocks_loaded', function (): void {
if (class_exists('Automattic\WooCommerce\Blocks\Integrations\IntegrationRegistry')) {
add_action(
'woocommerce_blocks_checkout_block_registration',
function ($integration_registry): void {
$integration_registry->register(new CheckoutBlocksIntegration());
}
);
}
});
}
/**
* Register plugin hooks
*/
private function registerHooks(): void
{
// Only register order hooks if licensed (license generation requires valid license)
$licenseChecker = PluginLicenseChecker::getInstance();
if ($licenseChecker->isLicenseValid()) {
// Generate license on order completion (multiple hooks for compatibility)
add_action('woocommerce_order_status_completed', [$this, 'onOrderCompleted']);
add_action('woocommerce_order_status_processing', [$this, 'onOrderCompleted']);
// Also hook into payment complete for immediate license generation
add_action('woocommerce_payment_complete', [$this, 'onOrderCompleted']);
}
}
/**
* Handle order completion - generate licenses
*/
public function onOrderCompleted(int $orderId): void
{
$order = wc_get_order($orderId);
if (!$order) {
return;
}
foreach ($order->get_items() as $item) {
$product = $item->get_product();
if ($product && $product->is_type('licensed')) {
$domain = $order->get_meta('_licensed_product_domain');
if ($domain) {
$this->licenseManager->generateLicense(
$orderId,
$product->get_id(),
$order->get_customer_id(),
$domain
);
}
}
}
}
/**
* Get Twig environment
*/
public function getTwig(): Environment
{
return $this->twig;
}
/**
* Get license manager
*/
public function getLicenseManager(): LicenseManager
{
return $this->licenseManager;
}
/**
* Render a Twig template
*/
public function render(string $template, array $context = []): string
{
return $this->twig->render($template, $context);
}
/**
* Show admin notice when plugin is unlicensed
*/
public function showUnlicensedNotice(): void
{
$settingsUrl = admin_url('admin.php?page=wc-settings&tab=licensed_product');
?>
<div class="notice notice-warning is-dismissible">
<p>
<strong><?php esc_html_e('WC Licensed Product', 'wc-licensed-product'); ?>:</strong>
<?php esc_html_e('Plugin license is not configured or invalid. Frontend features are disabled.', 'wc-licensed-product'); ?>
<a href="<?php echo esc_url($settingsUrl); ?>"><?php esc_html_e('Configure License', 'wc-licensed-product'); ?></a>
</p>
</div>
<?php
}
/**
* Get the plugin license checker instance
*/
public function getLicenseChecker(): PluginLicenseChecker
{
return PluginLicenseChecker::getInstance();
}
}