From 7bbffa50b44e8ee533e8fe3106d71ee3bc8e581c Mon Sep 17 00:00:00 2001
From: magdev ✓ ';
- html += '
';
} else {
diff --git a/src/Admin/SettingsController.php b/src/Admin/SettingsController.php
index ca2b254..0d778bb 100644
--- a/src/Admin/SettingsController.php
+++ b/src/Admin/SettingsController.php
@@ -167,6 +167,8 @@ final class SettingsController
*/
private function getAutoUpdatesSettings(): array
{
+ $autoInstallDisabled = !self::isUpdateNotificationEnabled();
+
return [
'auto_update_section_title' => [
'name' => __('Auto-Updates', 'wc-licensed-product'),
@@ -174,13 +176,23 @@ final class SettingsController
'desc' => __('Configure automatic plugin updates from the license server.', 'wc-licensed-product'),
'id' => 'wc_licensed_product_section_auto_update',
],
- 'plugin_auto_update_enabled' => [
- 'name' => __('Enable Auto-Updates', 'wc-licensed-product'),
+ 'update_notification_enabled' => [
+ 'name' => __('Enable Update Notifications', 'wc-licensed-product'),
'type' => 'checkbox',
- 'desc' => __('Automatically check for and receive plugin updates from the license server.', 'wc-licensed-product'),
- 'id' => 'wc_licensed_product_plugin_auto_update_enabled',
+ 'desc' => __('Check for and display available updates from the license server in WordPress admin.', 'wc-licensed-product'),
+ 'id' => 'wc_licensed_product_update_notification_enabled',
'default' => 'yes',
],
+ 'plugin_auto_install_enabled' => [
+ 'name' => __('Automatically Install Updates', 'wc-licensed-product'),
+ 'type' => 'checkbox',
+ 'desc' => $autoInstallDisabled
+ ? __('Enable "Update Notifications" above to use this option.', 'wc-licensed-product')
+ : __('Automatically install updates when they become available (requires update notifications enabled).', 'wc-licensed-product'),
+ 'id' => 'wc_licensed_product_plugin_auto_install_enabled',
+ 'default' => 'no',
+ 'custom_attributes' => $autoInstallDisabled ? ['disabled' => 'disabled'] : [],
+ ],
'update_check_frequency' => [
'name' => __('Check Frequency (Hours)', 'wc-licensed-product'),
'type' => 'number',
@@ -501,11 +513,32 @@ final class SettingsController
}
/**
- * Check if auto-updates are enabled
+ * Check if update notifications are enabled
+ */
+ public static function isUpdateNotificationEnabled(): bool
+ {
+ return get_option('wc_licensed_product_update_notification_enabled', 'yes') === 'yes';
+ }
+
+ /**
+ * Check if auto-updates are enabled (legacy alias for isUpdateNotificationEnabled)
*/
public static function isAutoUpdateEnabled(): bool
{
- return get_option('wc_licensed_product_plugin_auto_update_enabled', 'yes') === 'yes';
+ return self::isUpdateNotificationEnabled();
+ }
+
+ /**
+ * Check if automatic installation of updates is enabled
+ */
+ public static function isAutoInstallEnabled(): bool
+ {
+ // Auto-install requires notifications to be enabled first
+ if (!self::isUpdateNotificationEnabled()) {
+ return false;
+ }
+
+ return get_option('wc_licensed_product_plugin_auto_install_enabled', 'no') === 'yes';
}
/**
diff --git a/src/Frontend/AccountController.php b/src/Frontend/AccountController.php
index 85b165b..0d4aafe 100644
--- a/src/Frontend/AccountController.php
+++ b/src/Frontend/AccountController.php
@@ -106,23 +106,104 @@ final class AccountController
return;
}
+ // Get filter parameters from URL
+ $filterProductId = isset($_GET['filter_product']) ? absint($_GET['filter_product']) : 0;
+ $filterDomain = isset($_GET['filter_domain']) ? sanitize_text_field(wp_unslash($_GET['filter_domain'])) : '';
+
$licenses = $this->licenseManager->getLicensesByCustomer($customerId);
+ // Apply filters
+ $filteredLicenses = $this->applyLicenseFilters($licenses, $filterProductId, $filterDomain);
+
// Group licenses by product+order into "packages"
- $packages = $this->groupLicensesIntoPackages($licenses);
+ $packages = $this->groupLicensesIntoPackages($filteredLicenses);
+
+ // Get unique products and domains for filter dropdowns
+ $filterOptions = $this->getFilterOptions($licenses);
try {
echo $this->twig->render('frontend/licenses.html.twig', [
'packages' => $packages,
'has_packages' => !empty($packages),
'signing_enabled' => ResponseSigner::isSigningEnabled(),
+ 'filter_products' => $filterOptions['products'],
+ 'filter_domains' => $filterOptions['domains'],
+ 'current_filter_product' => $filterProductId,
+ 'current_filter_domain' => $filterDomain,
+ 'is_filtered' => $filterProductId > 0 || !empty($filterDomain),
+ 'licenses_url' => wc_get_account_endpoint_url('licenses'),
]);
} catch (\Exception $e) {
// Fallback to PHP template if Twig fails
- $this->displayLicensesFallback($packages);
+ $this->displayLicensesFallback($packages, $filterOptions, $filterProductId, $filterDomain);
}
}
+ /**
+ * Apply filters to licenses
+ *
+ * @param array $licenses Array of License objects
+ * @param int $productId Filter by product ID (0 for all)
+ * @param string $domain Filter by domain (empty for all)
+ * @return array Filtered array of License objects
+ */
+ private function applyLicenseFilters(array $licenses, int $productId, string $domain): array
+ {
+ if ($productId === 0 && empty($domain)) {
+ return $licenses;
+ }
+
+ return array_filter($licenses, function ($license) use ($productId, $domain) {
+ // Filter by product
+ if ($productId > 0 && $license->getProductId() !== $productId) {
+ return false;
+ }
+
+ // Filter by domain (partial match)
+ if (!empty($domain) && stripos($license->getDomain(), $domain) === false) {
+ return false;
+ }
+
+ return true;
+ });
+ }
+
+ /**
+ * Get unique filter options from licenses
+ *
+ * @param array $licenses Array of License objects
+ * @return array Array with 'products' and 'domains' keys
+ */
+ private function getFilterOptions(array $licenses): array
+ {
+ $products = [];
+ $domains = [];
+
+ foreach ($licenses as $license) {
+ // Collect unique products
+ $productId = $license->getProductId();
+ if (!isset($products[$productId])) {
+ $product = wc_get_product($productId);
+ $products[$productId] = $product ? $product->get_name() : __('Unknown Product', 'wc-licensed-product');
+ }
+
+ // Collect unique domains
+ $domain = $license->getDomain();
+ if (!in_array($domain, $domains, true)) {
+ $domains[] = $domain;
+ }
+ }
+
+ // Sort products by name, domains alphabetically
+ asort($products);
+ sort($domains);
+
+ return [
+ 'products' => $products,
+ 'domains' => $domains,
+ ];
+ }
+
/**
* Group licenses into packages by product+order
*
@@ -217,10 +298,67 @@ final class AccountController
/**
* Fallback display method if Twig is unavailable
*/
- private function displayLicensesFallback(array $packages): void
- {
+ private function displayLicensesFallback(
+ array $packages,
+ array $filterOptions = [],
+ int $currentFilterProduct = 0,
+ string $currentFilterDomain = ''
+ ): void {
+ $isFiltered = $currentFilterProduct > 0 || !empty($currentFilterDomain);
+ $licensesUrl = wc_get_account_endpoint_url('licenses');
+
+ // Display filter form if we have filter options
+ if (!empty($filterOptions['products']) || !empty($filterOptions['domains'])) {
+ ?>
+ ';
- html += '' + escapeHtml(result.product_name || '-') + ' ';
+ html += '' + escapeHtml(result.version || '-') + ' ';
if (result.expires_at) {
html += '' + escapeHtml(result.product_name || '-') + ' ';
} else {
- html += '' + escapeHtml(result.expires_at) + ' ';
+ html += ' ';
}
html += '
' . esc_html__('No licenses found matching your filters.', 'wc-licensed-product') . '
'; + } else { + echo '' . esc_html__('You have no licenses yet.', 'wc-licensed-product') . '
'; + } return; } diff --git a/src/Update/PluginUpdateChecker.php b/src/Update/PluginUpdateChecker.php index fb7974c..2062897 100644 --- a/src/Update/PluginUpdateChecker.php +++ b/src/Update/PluginUpdateChecker.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Jeremias\WcLicensedProduct\Update; +use Jeremias\WcLicensedProduct\Admin\SettingsController; use Jeremias\WcLicensedProduct\License\PluginLicenseChecker; use Symfony\Component\HttpClient\HttpClient; @@ -74,8 +75,8 @@ final class PluginUpdateChecker */ public function register(): void { - // Skip if auto-updates are disabled - if ($this->isAutoUpdateDisabled()) { + // Skip if update notifications are disabled + if ($this->isUpdateNotificationDisabled()) { return; } @@ -88,15 +89,19 @@ final class PluginUpdateChecker // Add authentication headers to download requests add_filter('http_request_args', [$this, 'addAuthHeaders'], 10, 2); + // Handle auto-install setting + add_filter('auto_update_plugin', [$this, 'handleAutoInstall'], 10, 2); + // Clear cache on settings save add_action('update_option_wc_licensed_product_plugin_license_key', [$this, 'clearCache']); add_action('update_option_wc_licensed_product_plugin_license_server_url', [$this, 'clearCache']); + add_action('update_option_wc_licensed_product_update_notification_enabled', [$this, 'clearCache']); } /** - * Check if auto-updates are disabled + * Check if update notifications are disabled */ - private function isAutoUpdateDisabled(): bool + private function isUpdateNotificationDisabled(): bool { // Check constant if (defined('WC_LICENSE_DISABLE_AUTO_UPDATE') && WC_LICENSE_DISABLE_AUTO_UPDATE) { @@ -104,8 +109,25 @@ final class PluginUpdateChecker } // Check setting - $enabled = get_option('wc_licensed_product_plugin_auto_update_enabled', 'yes'); - return $enabled !== 'yes'; + return !SettingsController::isUpdateNotificationEnabled(); + } + + /** + * Handle auto-install setting for WordPress automatic updates + * + * @param bool|null $update The update decision + * @param object $item The plugin update object + * @return bool|null Whether to auto-update this plugin + */ + public function handleAutoInstall($update, $item): ?bool + { + // Only handle our plugin + if (!isset($item->plugin) || $item->plugin !== $this->pluginBasename) { + return $update; + } + + // Return true to enable auto-install, false to disable, or null to use default + return SettingsController::isAutoInstallEnabled() ? true : $update; } /** diff --git a/templates/admin/licenses.html.twig b/templates/admin/licenses.html.twig index 38af54f..d121fa7 100644 --- a/templates/admin/licenses.html.twig +++ b/templates/admin/licenses.html.twig @@ -424,12 +424,11 @@ if (result.valid) { html = '✓ {{ __('License is VALID') }}
| {{ __('Product') }} | ' + escapeHtml(result.product_name || '-') + ' |
|---|---|
| {{ __('Version') }} | ' + escapeHtml(result.version || '-') + ' |
| {{ __('Product') }} | ' + escapeHtml(result.product_name || '-') + ' |
| {{ __('Expires') }} | ' + escapeHtml(result.expires_at) + ' |
| {{ __('Expires') }} | {{ __('Lifetime') }} |
| {{ __('Expires') }} | {{ __('Lifetime') }} |
{{ __('You have no licenses yet.') }}
+ {% if is_filtered %} +{{ __('No licenses found matching your filters.') }}
+ {% else %} +{{ __('You have no licenses yet.') }}
+ {% endif %} {% else %}