9 Commits

Author SHA1 Message Date
2ec3f42b1f Bump version to 0.4.0
- Add CHANGELOG entry for self-licensing prevention feature
- Update plugin header and constant to 0.4.0

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 16:42:39 +01:00
4817175f99 Add self-licensing prevention to PluginLicenseChecker
- Add isSelfLicensing() method to detect when license server URL points to same installation
- Bypass license validation when self-licensing detected (prevents circular dependency)
- Add normalizeDomain() helper for domain comparison
- Update translations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 16:41:56 +01:00
a4561057fa Update CLAUDE.md with v0.3.9 session history
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 16:11:09 +01:00
d15c59b7c3 Add release package v0.3.9
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 16:10:00 +01:00
4a90e6b18b Bump version to 0.3.9
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 16:08:41 +01:00
502a8c7cd7 Update translation template with current line references
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 16:07:46 +01:00
6b83fce8b2 Fix admin order license generation bug
- Add 'Generate Licenses' button to order meta box for admin-created orders
- Add AJAX handler for manual license generation
- Show warning when domain is not set or order is not paid
- Handle partial license generation (when some products already have licenses)
- Update German translations for new strings (365 translated)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 16:06:13 +01:00
8c33eaff29 Clean up known bugs section after v0.3.8 fix
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 15:38:19 +01:00
98002ae3d7 Update CLAUDE.md with v0.3.8 session history
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 15:37:14 +01:00
11 changed files with 572 additions and 102 deletions

View File

@@ -7,6 +7,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.4.0] - 2026-01-24
### Added
- Self-licensing prevention: Plugin automatically bypasses license validation when the configured license server URL points to the same WordPress installation
- New `isSelfLicensing()` method in `PluginLicenseChecker` to detect circular licensing scenarios
- New `normalizeDomain()` helper method for domain comparison (strips www prefix, lowercases)
### Changed
- `isLicenseValid()` and `validateLicense()` now check for self-licensing before attempting validation
- Cache clearing now also clears the self-licensing check cache
### Technical Details
- Self-licensing detection compares normalized domains of license server URL and current site URL
- Prevents circular dependency where plugin would try to validate against itself
- Plugins can only be validated against the original store from which they were obtained
## [0.3.9] - 2026-01-24
### Added
- "Generate Licenses" button in order meta box for admin-created orders
- "Generate Missing Licenses" button when some products in an order are missing licenses
- AJAX handler `ajaxGenerateOrderLicenses()` for manual license generation from admin
- Warning message when order domain is not set before generating licenses
### Fixed
- **Critical:** Licenses are now generated for orders created manually in admin area
- Previously, licenses were only generated via checkout hooks, leaving admin-created orders without licenses
### Technical Details
- Added `wclp_generate_order_licenses` AJAX action to `OrderLicenseController`
- Updated `order-licenses.js` with generate button handler and page reload on success
- Added CSS styles for generate status messages
- Updated translations (365 strings)
## [0.3.8] - 2026-01-24 ## [0.3.8] - 2026-01-24
### Fixed ### Fixed

View File

@@ -36,13 +36,9 @@ This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase w
No known bugs at the moment. No known bugs at the moment.
### Version 0.3.8
No changes at the moment.
### Version 0.4.0 ### Version 0.4.0
No changes at the moment. - Self-licensing prevention: Plugin automatically bypasses license validation when the configured license server URL points to the same WordPress installation (prevents circular dependency)
## Technical Stack ## Technical Stack
@@ -1091,3 +1087,75 @@ Fixed dashboard widget bugs, improved UI consistency, and added download trackin
- Created release package: `releases/wc-licensed-product-0.3.7.zip` (827 KB) - Created release package: `releases/wc-licensed-product-0.3.7.zip` (827 KB)
- SHA256: `e93b2ab06f6d43c2179167090e07eda5db6809df6e391baece4ceba321cf33f6` - SHA256: `e93b2ab06f6d43c2179167090e07eda5db6809df6e391baece4ceba321cf33f6`
- Tagged as `v0.3.7` and pushed to `main` branch - Tagged as `v0.3.7` and pushed to `main` branch
### 2026-01-24 - Version 0.3.8 - Translation Bug Fix
**Overview:**
Fixed a critical translation bug that caused the settings page to crash with an `ArgumentCountError`.
**Bug Fix:**
- Fixed: Duplicate German translation string in `wc-licensed-product-de_CH.po` causing `ArgumentCountError` in settings page
- Root cause: The notification settings description was duplicated in the translation, resulting in two `%s` placeholders when only one argument was passed to `sprintf()`
- Location: [wc-licensed-product-de_CH.po:322-328](languages/wc-licensed-product-de_CH.po#L322-L328)
**Modified files:**
- `languages/wc-licensed-product-de_CH.po` - Removed duplicated translation string
- `languages/wc-licensed-product-de_CH.mo` - Recompiled binary translation
**Technical notes:**
- Error was logged to `tmp/fatal-errors-2026-01-24.log`
- The German `msgstr` contained the same text twice, each with a `%s` placeholder
- `sprintf()` at `SettingsController.php:221` only provided one argument for the single `%s` in the English source
- Translation strings with `%s` placeholders must have exactly matching placeholder counts between source and translation
**Dependency Updates:**
- Updated `magdev/wc-licensed-product-client` from `9f513a8` to `64d215c`
**Release v0.3.8:**
- Created release package: `releases/wc-licensed-product-0.3.8.zip` (829 KB)
- SHA256: `50ad6966c5ab8db2257572084d2d8a820448df62615678e1576696f2c0cb383d`
- Tagged as `v0.3.8` and pushed to `main` branch
### 2026-01-24 - Version 0.3.9 - Admin Order License Generation Fix
**Overview:**
Fixed a critical bug where licenses were not generated for orders created manually in the WordPress admin area.
**Bug Fix:**
- **Critical:** Licenses are now generated for orders created manually in admin area
- Previously, licenses were only generated via checkout hooks (`woocommerce_order_status_completed`, `woocommerce_order_status_processing`, `woocommerce_payment_complete`)
- Admin-created orders bypassed checkout, so the `_licensed_product_domain` meta was never set and licenses were never generated
**Implemented:**
- "Generate Licenses" button in order meta box for admin-created orders
- "Generate Missing Licenses" button when some products in an order already have licenses
- Warning message when order domain is not set before generating licenses
- AJAX handler `ajaxGenerateOrderLicenses()` for manual license generation
**Modified files:**
- `src/Admin/OrderLicenseController.php` - Added Generate button, AJAX handler, CSS styles
- `assets/js/order-licenses.js` - Added `generateLicenses()` function with page reload on success
**Technical notes:**
- Button only appears when order is paid and domain is set
- Uses existing `LicenseManager::generateLicense()` which handles duplicate prevention
- Page reloads after successful generation to show new licenses in table
- Tracks generated vs skipped licenses for accurate feedback messages
- Updated translations (365 strings)
**Release v0.3.9:**
- Created release package: `releases/wc-licensed-product-0.3.9.zip` (851 KB)
- SHA256: `fdb65200c368da380df0cabb3c6ac6419d5b4731cd528f630f9b432a3ba5c586`
- Tagged as `v0.3.9` and pushed to `main` branch

View File

@@ -16,6 +16,9 @@
// Order domain save // Order domain save
$('#wclp-save-order-domain').on('click', this.saveOrderDomain.bind(this)); $('#wclp-save-order-domain').on('click', this.saveOrderDomain.bind(this));
// Generate licenses button
$(document).on('click', '#wclp-generate-licenses', this.generateLicenses.bind(this));
// License domain edit/save/cancel // License domain edit/save/cancel
$(document).on('click', '.wclp-edit-domain-btn', this.startEditDomain); $(document).on('click', '.wclp-edit-domain-btn', this.startEditDomain);
$(document).on('click', '.wclp-save-domain-btn', this.saveLicenseDomain.bind(this)); $(document).on('click', '.wclp-save-domain-btn', this.saveLicenseDomain.bind(this));
@@ -135,6 +138,54 @@
$editBtn.show(); $editBtn.show();
}, },
/**
* Generate licenses for order
*/
generateLicenses: function(e) {
e.preventDefault();
var $btn = $(e.currentTarget);
var $spinner = $btn.siblings('.spinner');
var $status = $btn.siblings('.wclp-generate-status');
var orderId = $btn.data('order-id');
$btn.prop('disabled', true);
$spinner.addClass('is-active');
$status.text('').removeClass('success error');
$.ajax({
url: wclpOrderLicenses.ajaxUrl,
type: 'POST',
data: {
action: 'wclp_generate_order_licenses',
nonce: wclpOrderLicenses.nonce,
order_id: orderId
},
success: function(response) {
if (response.success) {
$status.text(response.data.message).addClass('success');
if (response.data.reload) {
// Reload the page after a short delay to show the new licenses
setTimeout(function() {
window.location.reload();
}, 1500);
}
} else {
$status.text(response.data.message || wclpOrderLicenses.strings.error).addClass('error');
$btn.prop('disabled', false);
}
},
error: function() {
$status.text(wclpOrderLicenses.strings.error).addClass('error');
$btn.prop('disabled', false);
},
complete: function() {
$spinner.removeClass('is-active');
}
});
},
/** /**
* Save license domain * Save license domain
*/ */

View File

@@ -4,8 +4,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: WC Licensed Product 0.3.1\n" "Project-Id-Version: WC Licensed Product 0.3.1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: magdev3.0@gmail.com\n"
"POT-Creation-Date: 2026-01-24 10:18+0100\n" "POT-Creation-Date: 2026-01-24 16:39+0100\n"
"PO-Revision-Date: 2026-01-22T17:15:00+00:00\n" "PO-Revision-Date: 2026-01-22T17:15:00+00:00\n"
"Last-Translator: Marco Graetsch <magdev3.0@gmail.com>\n" "Last-Translator: Marco Graetsch <magdev3.0@gmail.com>\n"
"Language-Team: German (Switzerland) <de_CH@li.org>\n" "Language-Team: German (Switzerland) <de_CH@li.org>\n"
@@ -17,8 +17,8 @@ msgstr ""
#: src/Admin/AdminController.php:76 src/Admin/AdminController.php:77 #: src/Admin/AdminController.php:76 src/Admin/AdminController.php:77
#: src/Admin/AdminController.php:90 src/Admin/AdminController.php:1200 #: src/Admin/AdminController.php:90 src/Admin/AdminController.php:1200
#: src/Admin/OrderLicenseController.php:127 #: src/Admin/OrderLicenseController.php:128
#: src/Admin/OrderLicenseController.php:222 #: src/Admin/OrderLicenseController.php:249
#: src/Frontend/AccountController.php:90 #: src/Frontend/AccountController.php:90
msgid "Licenses" msgid "Licenses"
msgstr "Lizenzen" msgstr "Lizenzen"
@@ -39,7 +39,7 @@ msgstr "Suche..."
msgid "Search failed" msgid "Search failed"
msgstr "Suche fehlgeschlagen" msgstr "Suche fehlgeschlagen"
#: src/Admin/AdminController.php:144 src/Admin/OrderLicenseController.php:285 #: src/Admin/AdminController.php:144 src/Admin/OrderLicenseController.php:338
msgid "Saving..." msgid "Saving..."
msgstr "Speichere..." msgstr "Speichere..."
@@ -65,22 +65,22 @@ msgstr "Bearbeiten"
#: src/Admin/AdminController.php:149 src/Admin/AdminController.php:1341 #: src/Admin/AdminController.php:149 src/Admin/AdminController.php:1341
#: src/Admin/AdminController.php:1361 src/Admin/AdminController.php:1382 #: src/Admin/AdminController.php:1361 src/Admin/AdminController.php:1382
#: src/Admin/AdminController.php:1537 src/Admin/OrderLicenseController.php:185 #: src/Admin/AdminController.php:1537 src/Admin/OrderLicenseController.php:212
#: src/Frontend/AccountController.php:271 #: src/Frontend/AccountController.php:271
msgid "Cancel" msgid "Cancel"
msgstr "Abbrechen" msgstr "Abbrechen"
#: src/Admin/AdminController.php:150 src/Admin/AdminController.php:1340 #: src/Admin/AdminController.php:150 src/Admin/AdminController.php:1340
#: src/Admin/AdminController.php:1360 src/Admin/AdminController.php:1381 #: src/Admin/AdminController.php:1360 src/Admin/AdminController.php:1381
#: src/Admin/OrderLicenseController.php:118 #: src/Admin/OrderLicenseController.php:119
#: src/Admin/OrderLicenseController.php:182 #: src/Admin/OrderLicenseController.php:209
msgid "Save" msgid "Save"
msgstr "Speichern" msgstr "Speichern"
#: src/Admin/AdminController.php:151 src/Admin/AdminController.php:266 #: src/Admin/AdminController.php:151 src/Admin/AdminController.php:266
#: src/Admin/AdminController.php:1373 src/Admin/AdminController.php:1613 #: src/Admin/AdminController.php:1373 src/Admin/AdminController.php:1613
#: src/Admin/DashboardWidgetController.php:136 #: src/Admin/DashboardWidgetController.php:136
#: src/Admin/OrderLicenseController.php:201 #: src/Admin/OrderLicenseController.php:228
#: src/Admin/SettingsController.php:192 src/Product/LicensedProductType.php:110 #: src/Admin/SettingsController.php:192 src/Product/LicensedProductType.php:110
#: src/Product/LicensedProductType.php:158 #: src/Product/LicensedProductType.php:158
msgid "Lifetime" msgid "Lifetime"
@@ -124,8 +124,9 @@ msgstr "Widerrufen"
#: src/Admin/AdminController.php:173 src/Admin/AdminController.php:213 #: src/Admin/AdminController.php:173 src/Admin/AdminController.php:213
#: src/Admin/AdminController.php:249 src/Admin/AdminController.php:301 #: src/Admin/AdminController.php:249 src/Admin/AdminController.php:301
#: src/Admin/AdminController.php:339 src/Admin/AdminController.php:369 #: src/Admin/AdminController.php:339 src/Admin/AdminController.php:369
#: src/Admin/OrderLicenseController.php:301 #: src/Admin/OrderLicenseController.php:355
#: src/Admin/OrderLicenseController.php:340 #: src/Admin/OrderLicenseController.php:394
#: src/Admin/OrderLicenseController.php:458
#: src/Admin/VersionAdminController.php:259 #: src/Admin/VersionAdminController.php:259
#: src/Admin/VersionAdminController.php:328 #: src/Admin/VersionAdminController.php:328
#: src/Admin/VersionAdminController.php:354 #: src/Admin/VersionAdminController.php:354
@@ -133,7 +134,7 @@ msgid "Permission denied."
msgstr "Zugriff verweigert." msgstr "Zugriff verweigert."
#: src/Admin/AdminController.php:195 src/Admin/AdminController.php:1019 #: src/Admin/AdminController.php:195 src/Admin/AdminController.php:1019
#: src/Admin/OrderLicenseController.php:168 #: src/Admin/OrderLicenseController.php:195
msgid "Unknown" msgid "Unknown"
msgstr "Unbekannt" msgstr "Unbekannt"
@@ -143,7 +144,7 @@ msgstr "Gast"
#: src/Admin/AdminController.php:220 src/Admin/AdminController.php:256 #: src/Admin/AdminController.php:220 src/Admin/AdminController.php:256
#: src/Admin/AdminController.php:308 src/Admin/AdminController.php:345 #: src/Admin/AdminController.php:308 src/Admin/AdminController.php:345
#: src/Admin/OrderLicenseController.php:347 #: src/Admin/OrderLicenseController.php:401
msgid "Invalid license ID." msgid "Invalid license ID."
msgstr "Ungültige Lizenz-ID." msgstr "Ungültige Lizenz-ID."
@@ -175,7 +176,7 @@ msgstr "Ablaufdatum erfolgreich aktualisiert."
msgid "Invalid date format." msgid "Invalid date format."
msgstr "Ungültiges Datumsformat." msgstr "Ungültiges Datumsformat."
#: src/Admin/AdminController.php:312 src/Admin/OrderLicenseController.php:351 #: src/Admin/AdminController.php:312 src/Admin/OrderLicenseController.php:405
msgid "Domain cannot be empty." msgid "Domain cannot be empty."
msgstr "Domain darf nicht leer sein." msgstr "Domain darf nicht leer sein."
@@ -470,14 +471,14 @@ msgid "Apply"
msgstr "Anwenden" msgstr "Anwenden"
#: src/Admin/AdminController.php:1291 src/Admin/AdminController.php:1442 #: src/Admin/AdminController.php:1291 src/Admin/AdminController.php:1442
#: src/Admin/AdminController.php:1491 src/Admin/OrderLicenseController.php:144 #: src/Admin/AdminController.php:1491 src/Admin/OrderLicenseController.php:171
#: src/Admin/SettingsController.php:142 #: src/Admin/SettingsController.php:142
#: src/Email/LicenseEmailController.php:269 #: src/Email/LicenseEmailController.php:269
msgid "License Key" msgid "License Key"
msgstr "Lizenzschlüssel" msgstr "Lizenzschlüssel"
#: src/Admin/AdminController.php:1292 src/Admin/AdminController.php:1443 #: src/Admin/AdminController.php:1292 src/Admin/AdminController.php:1443
#: src/Admin/AdminController.php:1608 src/Admin/OrderLicenseController.php:145 #: src/Admin/AdminController.php:1608 src/Admin/OrderLicenseController.php:172
#: src/Email/LicenseEmailController.php:268 #: src/Email/LicenseEmailController.php:268
msgid "Product" msgid "Product"
msgstr "Produkt" msgstr "Produkt"
@@ -489,12 +490,12 @@ msgid "Customer"
msgstr "Kunde" msgstr "Kunde"
#: src/Admin/AdminController.php:1294 src/Admin/AdminController.php:1445 #: src/Admin/AdminController.php:1294 src/Admin/AdminController.php:1445
#: src/Admin/AdminController.php:1495 src/Admin/OrderLicenseController.php:146 #: src/Admin/AdminController.php:1495 src/Admin/OrderLicenseController.php:173
msgid "Domain" msgid "Domain"
msgstr "Domain" msgstr "Domain"
#: src/Admin/AdminController.php:1295 src/Admin/AdminController.php:1446 #: src/Admin/AdminController.php:1295 src/Admin/AdminController.php:1446
#: src/Admin/OrderLicenseController.php:147 #: src/Admin/OrderLicenseController.php:174
#: src/Admin/VersionAdminController.php:140 #: src/Admin/VersionAdminController.php:140
msgid "Status" msgid "Status"
msgstr "Status" msgstr "Status"
@@ -505,13 +506,13 @@ msgstr "Erstellt"
#: src/Admin/AdminController.php:1297 src/Admin/AdminController.php:1448 #: src/Admin/AdminController.php:1297 src/Admin/AdminController.php:1448
#: src/Admin/AdminController.php:1611 src/Admin/AdminController.php:1613 #: src/Admin/AdminController.php:1611 src/Admin/AdminController.php:1613
#: src/Admin/OrderLicenseController.php:148 #: src/Admin/OrderLicenseController.php:175
#: src/Email/LicenseEmailController.php:270 #: src/Email/LicenseEmailController.php:270
msgid "Expires" msgid "Expires"
msgstr "Läuft ab" msgstr "Läuft ab"
#: src/Admin/AdminController.php:1298 src/Admin/AdminController.php:1449 #: src/Admin/AdminController.php:1298 src/Admin/AdminController.php:1449
#: src/Admin/OrderLicenseController.php:149 #: src/Admin/OrderLicenseController.php:176
#: src/Admin/VersionAdminController.php:142 #: src/Admin/VersionAdminController.php:142
msgid "Actions" msgid "Actions"
msgstr "Aktionen" msgstr "Aktionen"
@@ -758,24 +759,25 @@ msgstr "Noch keine Downloads"
msgid "Top Versions" msgid "Top Versions"
msgstr "Top-Versionen" msgstr "Top-Versionen"
#: src/Admin/OrderLicenseController.php:56 #: src/Admin/OrderLicenseController.php:57
msgid "Product Licenses" msgid "Product Licenses"
msgstr "Produktlizenzen" msgstr "Produktlizenzen"
#: src/Admin/OrderLicenseController.php:77 #: src/Admin/OrderLicenseController.php:78
#: src/Admin/OrderLicenseController.php:313 #: src/Admin/OrderLicenseController.php:367
#: src/Admin/OrderLicenseController.php:469
msgid "Order not found." msgid "Order not found."
msgstr "Bestellung nicht gefunden." msgstr "Bestellung nicht gefunden."
#: src/Admin/OrderLicenseController.php:92 #: src/Admin/OrderLicenseController.php:93
msgid "This order does not contain licensed products." msgid "This order does not contain licensed products."
msgstr "Diese Bestellung enthält keine lizensierten Produkte." msgstr "Diese Bestellung enthält keine lizensierten Produkte."
#: src/Admin/OrderLicenseController.php:106 #: src/Admin/OrderLicenseController.php:107
msgid "Order Domain" msgid "Order Domain"
msgstr "Bestellungs-Domain" msgstr "Bestellungs-Domain"
#: src/Admin/OrderLicenseController.php:108 #: src/Admin/OrderLicenseController.php:109
msgid "" msgid ""
"The domain specified during checkout. Changing this will not automatically " "The domain specified during checkout. Changing this will not automatically "
"update existing license domains." "update existing license domains."
@@ -783,17 +785,17 @@ msgstr ""
"Die bei der Bestellung angegebene Domain. Eine Änderung aktualisiert nicht " "Die bei der Bestellung angegebene Domain. Eine Änderung aktualisiert nicht "
"automatisch bestehende Lizenz-Domains." "automatisch bestehende Lizenz-Domains."
#: src/Admin/OrderLicenseController.php:116 #: src/Admin/OrderLicenseController.php:117
#: src/Checkout/CheckoutBlocksIntegration.php:102 #: src/Checkout/CheckoutBlocksIntegration.php:102
#: src/Checkout/CheckoutController.php:89 #: src/Checkout/CheckoutController.php:89
msgid "example.com" msgid "example.com"
msgstr "beispiel.ch" msgstr "beispiel.ch"
#: src/Admin/OrderLicenseController.php:131 #: src/Admin/OrderLicenseController.php:144
msgid "No licenses have been generated for this order yet." msgid "No licenses have been generated for this order yet."
msgstr "Für diese Bestellung wurden noch keine Lizenzen generiert." msgstr "Für diese Bestellung wurden noch keine Lizenzen generiert."
#: src/Admin/OrderLicenseController.php:134 #: src/Admin/OrderLicenseController.php:147
msgid "" msgid ""
"Licenses should be generated automatically when an order is paid. If " "Licenses should be generated automatically when an order is paid. If "
"missing, check that a domain was specified during checkout." "missing, check that a domain was specified during checkout."
@@ -802,68 +804,115 @@ msgstr ""
"wird. Falls fehlend, prüfen Sie, ob bei der Bestellung eine Domain angegeben " "wird. Falls fehlend, prüfen Sie, ob bei der Bestellung eine Domain angegeben "
"wurde." "wurde."
#: src/Admin/OrderLicenseController.php:137 #: src/Admin/OrderLicenseController.php:150
msgid "Licenses will be generated when the order is marked as paid/completed." msgid "Licenses will be generated when the order is marked as paid/completed."
msgstr "" msgstr ""
"Lizenzen werden generiert, sobald die Bestellung als bezahlt/abgeschlossen " "Lizenzen werden generiert, sobald die Bestellung als bezahlt/abgeschlossen "
"markiert wird." "markiert wird."
#: src/Admin/OrderLicenseController.php:178 #: src/Admin/OrderLicenseController.php:156
msgid "Generate Licenses"
msgstr "Lizenzen generieren"
#: src/Admin/OrderLicenseController.php:164
msgid "Please set the order domain above before generating licenses."
msgstr ""
"Bitte legen Sie zuerst die Bestellungs-Domain oben fest, bevor Sie Lizenzen "
"generieren."
#: src/Admin/OrderLicenseController.php:205
msgid "Edit domain" msgid "Edit domain"
msgstr "Domain bearbeiten" msgstr "Domain bearbeiten"
#: src/Admin/OrderLicenseController.php:208 #: src/Admin/OrderLicenseController.php:235
msgid "View in Licenses" msgid "View in Licenses"
msgstr "In Lizenzen anzeigen" msgstr "In Lizenzen anzeigen"
#: src/Admin/OrderLicenseController.php:221 #: src/Admin/OrderLicenseController.php:248
#, php-format #, php-format
msgid "For more actions (revoke, extend, delete), go to the %s page." msgid "For more actions (revoke, extend, delete), go to the %s page."
msgstr "" msgstr ""
"Für weitere Aktionen (widerrufen, verlängern, löschen), gehen Sie zur Seite " "Für weitere Aktionen (widerrufen, verlängern, löschen), gehen Sie zur Seite "
"%s." "%s."
#: src/Admin/OrderLicenseController.php:286 #: src/Admin/OrderLicenseController.php:261
#, php-format
msgid "%d licensed product is missing a license."
msgid_plural "%d licensed products are missing licenses."
msgstr[0] "%d lizenziertes Produkt hat keine Lizenz."
msgstr[1] "%d lizenzierte Produkte haben keine Lizenzen."
#: src/Admin/OrderLicenseController.php:270
msgid "Generate Missing Licenses"
msgstr "Fehlende Lizenzen generieren"
#: src/Admin/OrderLicenseController.php:339
msgid "Saved!" msgid "Saved!"
msgstr "Gespeichert!" msgstr "Gespeichert!"
#: src/Admin/OrderLicenseController.php:287 #: src/Admin/OrderLicenseController.php:340
msgid "Error saving. Please try again." msgid "Error. Please try again."
msgstr "Fehler beim Speichern. Bitte versuchen Sie es erneut." msgstr "Fehler. Bitte versuchen Sie es erneut."
#: src/Admin/OrderLicenseController.php:288 #: src/Admin/OrderLicenseController.php:341
#: src/Frontend/AccountController.php:314 #: src/Frontend/AccountController.php:314
#: src/Frontend/AccountController.php:346 #: src/Frontend/AccountController.php:346
msgid "Please enter a valid domain." msgid "Please enter a valid domain."
msgstr "Bitte geben Sie eine gültige Domain ein." msgstr "Bitte geben Sie eine gültige Domain ein."
#: src/Admin/OrderLicenseController.php:308 #: src/Admin/OrderLicenseController.php:342
msgid "Generating..."
msgstr "Generiere..."
#: src/Admin/OrderLicenseController.php:362
#: src/Admin/OrderLicenseController.php:464
msgid "Invalid order ID." msgid "Invalid order ID."
msgstr "Ungültige Bestellungs-ID." msgstr "Ungültige Bestellungs-ID."
#: src/Admin/OrderLicenseController.php:319 #: src/Admin/OrderLicenseController.php:373
#: src/Admin/OrderLicenseController.php:357 #: src/Admin/OrderLicenseController.php:411
msgid "Invalid domain format." msgid "Invalid domain format."
msgstr "Ungültiges Domain-Format." msgstr "Ungültiges Domain-Format."
#: src/Admin/OrderLicenseController.php:327 #: src/Admin/OrderLicenseController.php:381
msgid "Order domain updated." msgid "Order domain updated."
msgstr "Bestellungs-Domain aktualisiert." msgstr "Bestellungs-Domain aktualisiert."
#: src/Admin/OrderLicenseController.php:363 #: src/Admin/OrderLicenseController.php:417
#: src/Frontend/AccountController.php:352 #: src/Frontend/AccountController.php:352
#: src/Frontend/DownloadController.php:117 #: src/Frontend/DownloadController.php:117
msgid "License not found." msgid "License not found."
msgstr "Lizenz nicht gefunden." msgstr "Lizenz nicht gefunden."
#: src/Admin/OrderLicenseController.php:371 #: src/Admin/OrderLicenseController.php:425
msgid "License domain updated." msgid "License domain updated."
msgstr "Lizenz-Domain aktualisiert." msgstr "Lizenz-Domain aktualisiert."
#: src/Admin/OrderLicenseController.php:375 #: src/Admin/OrderLicenseController.php:429
msgid "Failed to update license domain." msgid "Failed to update license domain."
msgstr "Lizenz-Domain konnte nicht aktualisiert werden." msgstr "Lizenz-Domain konnte nicht aktualisiert werden."
#: src/Admin/OrderLicenseController.php:474
msgid "Order must be paid before licenses can be generated."
msgstr ""
"Die Bestellung muss bezahlt sein, bevor Lizenzen generiert werden können."
#: src/Admin/OrderLicenseController.php:480
msgid "Please set the order domain before generating licenses."
msgstr ""
"Bitte legen Sie die Bestellungs-Domain fest, bevor Sie Lizenzen generieren."
#: src/Admin/OrderLicenseController.php:521
#, php-format
msgid "%d license generated successfully."
msgid_plural "%d licenses generated successfully."
msgstr[0] "%d Lizenz erfolgreich generiert."
msgstr[1] "%d Lizenzen erfolgreich generiert."
#: src/Admin/OrderLicenseController.php:534
msgid "All licenses already exist for this order."
msgstr "Alle Lizenzen für diese Bestellung existieren bereits."
#: src/Admin/SettingsController.php:54 #: src/Admin/SettingsController.php:54
msgid "Licensed Products" msgid "Licensed Products"
msgstr "Lizensierte Produkte" msgstr "Lizensierte Produkte"
@@ -1617,11 +1666,11 @@ msgstr "Diese Lizenz ist inaktiv."
msgid "This license is not valid for this domain." msgid "This license is not valid for this domain."
msgstr "Diese Lizenz ist für diese Domain nicht gültig." msgstr "Diese Lizenz ist für diese Domain nicht gültig."
#: src/License/PluginLicenseChecker.php:117 #: src/License/PluginLicenseChecker.php:132
msgid "License settings not configured." msgid "License settings not configured."
msgstr "Lizenzeinstellungen nicht konfiguriert." msgstr "Lizenzeinstellungen nicht konfiguriert."
#: src/License/PluginLicenseChecker.php:153 #: src/License/PluginLicenseChecker.php:168
msgid "Could not connect to license server." msgid "Could not connect to license server."
msgstr "Verbindung zum Lizenzserver konnte nicht hergestellt werden." msgstr "Verbindung zum Lizenzserver konnte nicht hergestellt werden."

View File

@@ -6,9 +6,9 @@
#, fuzzy #, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: WC Licensed Product 0.3.7\n" "Project-Id-Version: WC Licensed Product 0.4.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: magdev3.0@gmail.com\n"
"POT-Creation-Date: 2026-01-24 10:18+0100\n" "POT-Creation-Date: 2026-01-24 16:39+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -20,8 +20,8 @@ msgstr ""
#: src/Admin/AdminController.php:76 src/Admin/AdminController.php:77 #: src/Admin/AdminController.php:76 src/Admin/AdminController.php:77
#: src/Admin/AdminController.php:90 src/Admin/AdminController.php:1200 #: src/Admin/AdminController.php:90 src/Admin/AdminController.php:1200
#: src/Admin/OrderLicenseController.php:127 #: src/Admin/OrderLicenseController.php:128
#: src/Admin/OrderLicenseController.php:222 #: src/Admin/OrderLicenseController.php:249
#: src/Frontend/AccountController.php:90 #: src/Frontend/AccountController.php:90
msgid "Licenses" msgid "Licenses"
msgstr "" msgstr ""
@@ -42,7 +42,7 @@ msgstr ""
msgid "Search failed" msgid "Search failed"
msgstr "" msgstr ""
#: src/Admin/AdminController.php:144 src/Admin/OrderLicenseController.php:285 #: src/Admin/AdminController.php:144 src/Admin/OrderLicenseController.php:338
msgid "Saving..." msgid "Saving..."
msgstr "" msgstr ""
@@ -66,22 +66,22 @@ msgstr ""
#: src/Admin/AdminController.php:149 src/Admin/AdminController.php:1341 #: src/Admin/AdminController.php:149 src/Admin/AdminController.php:1341
#: src/Admin/AdminController.php:1361 src/Admin/AdminController.php:1382 #: src/Admin/AdminController.php:1361 src/Admin/AdminController.php:1382
#: src/Admin/AdminController.php:1537 src/Admin/OrderLicenseController.php:185 #: src/Admin/AdminController.php:1537 src/Admin/OrderLicenseController.php:212
#: src/Frontend/AccountController.php:271 #: src/Frontend/AccountController.php:271
msgid "Cancel" msgid "Cancel"
msgstr "" msgstr ""
#: src/Admin/AdminController.php:150 src/Admin/AdminController.php:1340 #: src/Admin/AdminController.php:150 src/Admin/AdminController.php:1340
#: src/Admin/AdminController.php:1360 src/Admin/AdminController.php:1381 #: src/Admin/AdminController.php:1360 src/Admin/AdminController.php:1381
#: src/Admin/OrderLicenseController.php:118 #: src/Admin/OrderLicenseController.php:119
#: src/Admin/OrderLicenseController.php:182 #: src/Admin/OrderLicenseController.php:209
msgid "Save" msgid "Save"
msgstr "" msgstr ""
#: src/Admin/AdminController.php:151 src/Admin/AdminController.php:266 #: src/Admin/AdminController.php:151 src/Admin/AdminController.php:266
#: src/Admin/AdminController.php:1373 src/Admin/AdminController.php:1613 #: src/Admin/AdminController.php:1373 src/Admin/AdminController.php:1613
#: src/Admin/DashboardWidgetController.php:136 #: src/Admin/DashboardWidgetController.php:136
#: src/Admin/OrderLicenseController.php:201 #: src/Admin/OrderLicenseController.php:228
#: src/Admin/SettingsController.php:192 src/Product/LicensedProductType.php:110 #: src/Admin/SettingsController.php:192 src/Product/LicensedProductType.php:110
#: src/Product/LicensedProductType.php:158 #: src/Product/LicensedProductType.php:158
msgid "Lifetime" msgid "Lifetime"
@@ -125,8 +125,9 @@ msgstr ""
#: src/Admin/AdminController.php:173 src/Admin/AdminController.php:213 #: src/Admin/AdminController.php:173 src/Admin/AdminController.php:213
#: src/Admin/AdminController.php:249 src/Admin/AdminController.php:301 #: src/Admin/AdminController.php:249 src/Admin/AdminController.php:301
#: src/Admin/AdminController.php:339 src/Admin/AdminController.php:369 #: src/Admin/AdminController.php:339 src/Admin/AdminController.php:369
#: src/Admin/OrderLicenseController.php:301 #: src/Admin/OrderLicenseController.php:355
#: src/Admin/OrderLicenseController.php:340 #: src/Admin/OrderLicenseController.php:394
#: src/Admin/OrderLicenseController.php:458
#: src/Admin/VersionAdminController.php:259 #: src/Admin/VersionAdminController.php:259
#: src/Admin/VersionAdminController.php:328 #: src/Admin/VersionAdminController.php:328
#: src/Admin/VersionAdminController.php:354 #: src/Admin/VersionAdminController.php:354
@@ -134,7 +135,7 @@ msgid "Permission denied."
msgstr "" msgstr ""
#: src/Admin/AdminController.php:195 src/Admin/AdminController.php:1019 #: src/Admin/AdminController.php:195 src/Admin/AdminController.php:1019
#: src/Admin/OrderLicenseController.php:168 #: src/Admin/OrderLicenseController.php:195
msgid "Unknown" msgid "Unknown"
msgstr "" msgstr ""
@@ -144,7 +145,7 @@ msgstr ""
#: src/Admin/AdminController.php:220 src/Admin/AdminController.php:256 #: src/Admin/AdminController.php:220 src/Admin/AdminController.php:256
#: src/Admin/AdminController.php:308 src/Admin/AdminController.php:345 #: src/Admin/AdminController.php:308 src/Admin/AdminController.php:345
#: src/Admin/OrderLicenseController.php:347 #: src/Admin/OrderLicenseController.php:401
msgid "Invalid license ID." msgid "Invalid license ID."
msgstr "" msgstr ""
@@ -176,7 +177,7 @@ msgstr ""
msgid "Invalid date format." msgid "Invalid date format."
msgstr "" msgstr ""
#: src/Admin/AdminController.php:312 src/Admin/OrderLicenseController.php:351 #: src/Admin/AdminController.php:312 src/Admin/OrderLicenseController.php:405
msgid "Domain cannot be empty." msgid "Domain cannot be empty."
msgstr "" msgstr ""
@@ -469,14 +470,14 @@ msgid "Apply"
msgstr "" msgstr ""
#: src/Admin/AdminController.php:1291 src/Admin/AdminController.php:1442 #: src/Admin/AdminController.php:1291 src/Admin/AdminController.php:1442
#: src/Admin/AdminController.php:1491 src/Admin/OrderLicenseController.php:144 #: src/Admin/AdminController.php:1491 src/Admin/OrderLicenseController.php:171
#: src/Admin/SettingsController.php:142 #: src/Admin/SettingsController.php:142
#: src/Email/LicenseEmailController.php:269 #: src/Email/LicenseEmailController.php:269
msgid "License Key" msgid "License Key"
msgstr "" msgstr ""
#: src/Admin/AdminController.php:1292 src/Admin/AdminController.php:1443 #: src/Admin/AdminController.php:1292 src/Admin/AdminController.php:1443
#: src/Admin/AdminController.php:1608 src/Admin/OrderLicenseController.php:145 #: src/Admin/AdminController.php:1608 src/Admin/OrderLicenseController.php:172
#: src/Email/LicenseEmailController.php:268 #: src/Email/LicenseEmailController.php:268
msgid "Product" msgid "Product"
msgstr "" msgstr ""
@@ -488,12 +489,12 @@ msgid "Customer"
msgstr "" msgstr ""
#: src/Admin/AdminController.php:1294 src/Admin/AdminController.php:1445 #: src/Admin/AdminController.php:1294 src/Admin/AdminController.php:1445
#: src/Admin/AdminController.php:1495 src/Admin/OrderLicenseController.php:146 #: src/Admin/AdminController.php:1495 src/Admin/OrderLicenseController.php:173
msgid "Domain" msgid "Domain"
msgstr "" msgstr ""
#: src/Admin/AdminController.php:1295 src/Admin/AdminController.php:1446 #: src/Admin/AdminController.php:1295 src/Admin/AdminController.php:1446
#: src/Admin/OrderLicenseController.php:147 #: src/Admin/OrderLicenseController.php:174
#: src/Admin/VersionAdminController.php:140 #: src/Admin/VersionAdminController.php:140
msgid "Status" msgid "Status"
msgstr "" msgstr ""
@@ -504,13 +505,13 @@ msgstr ""
#: src/Admin/AdminController.php:1297 src/Admin/AdminController.php:1448 #: src/Admin/AdminController.php:1297 src/Admin/AdminController.php:1448
#: src/Admin/AdminController.php:1611 src/Admin/AdminController.php:1613 #: src/Admin/AdminController.php:1611 src/Admin/AdminController.php:1613
#: src/Admin/OrderLicenseController.php:148 #: src/Admin/OrderLicenseController.php:175
#: src/Email/LicenseEmailController.php:270 #: src/Email/LicenseEmailController.php:270
msgid "Expires" msgid "Expires"
msgstr "" msgstr ""
#: src/Admin/AdminController.php:1298 src/Admin/AdminController.php:1449 #: src/Admin/AdminController.php:1298 src/Admin/AdminController.php:1449
#: src/Admin/OrderLicenseController.php:149 #: src/Admin/OrderLicenseController.php:176
#: src/Admin/VersionAdminController.php:142 #: src/Admin/VersionAdminController.php:142
msgid "Actions" msgid "Actions"
msgstr "" msgstr ""
@@ -752,103 +753,147 @@ msgstr ""
msgid "Top Versions" msgid "Top Versions"
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:56 #: src/Admin/OrderLicenseController.php:57
msgid "Product Licenses" msgid "Product Licenses"
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:77 #: src/Admin/OrderLicenseController.php:78
#: src/Admin/OrderLicenseController.php:313 #: src/Admin/OrderLicenseController.php:367
#: src/Admin/OrderLicenseController.php:469
msgid "Order not found." msgid "Order not found."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:92 #: src/Admin/OrderLicenseController.php:93
msgid "This order does not contain licensed products." msgid "This order does not contain licensed products."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:106 #: src/Admin/OrderLicenseController.php:107
msgid "Order Domain" msgid "Order Domain"
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:108 #: src/Admin/OrderLicenseController.php:109
msgid "" msgid ""
"The domain specified during checkout. Changing this will not automatically " "The domain specified during checkout. Changing this will not automatically "
"update existing license domains." "update existing license domains."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:116 #: src/Admin/OrderLicenseController.php:117
#: src/Checkout/CheckoutBlocksIntegration.php:102 #: src/Checkout/CheckoutBlocksIntegration.php:102
#: src/Checkout/CheckoutController.php:89 #: src/Checkout/CheckoutController.php:89
msgid "example.com" msgid "example.com"
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:131 #: src/Admin/OrderLicenseController.php:144
msgid "No licenses have been generated for this order yet." msgid "No licenses have been generated for this order yet."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:134 #: src/Admin/OrderLicenseController.php:147
msgid "" msgid ""
"Licenses should be generated automatically when an order is paid. If " "Licenses should be generated automatically when an order is paid. If "
"missing, check that a domain was specified during checkout." "missing, check that a domain was specified during checkout."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:137 #: src/Admin/OrderLicenseController.php:150
msgid "Licenses will be generated when the order is marked as paid/completed." msgid "Licenses will be generated when the order is marked as paid/completed."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:178 #: src/Admin/OrderLicenseController.php:156
msgid "Generate Licenses"
msgstr ""
#: src/Admin/OrderLicenseController.php:164
msgid "Please set the order domain above before generating licenses."
msgstr ""
#: src/Admin/OrderLicenseController.php:205
msgid "Edit domain" msgid "Edit domain"
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:208 #: src/Admin/OrderLicenseController.php:235
msgid "View in Licenses" msgid "View in Licenses"
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:221 #: src/Admin/OrderLicenseController.php:248
#, php-format #, php-format
msgid "For more actions (revoke, extend, delete), go to the %s page." msgid "For more actions (revoke, extend, delete), go to the %s page."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:286 #: src/Admin/OrderLicenseController.php:261
#, php-format
msgid "%d licensed product is missing a license."
msgid_plural "%d licensed products are missing licenses."
msgstr[0] ""
msgstr[1] ""
#: src/Admin/OrderLicenseController.php:270
msgid "Generate Missing Licenses"
msgstr ""
#: src/Admin/OrderLicenseController.php:339
msgid "Saved!" msgid "Saved!"
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:287 #: src/Admin/OrderLicenseController.php:340
msgid "Error saving. Please try again." msgid "Error. Please try again."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:288 #: src/Admin/OrderLicenseController.php:341
#: src/Frontend/AccountController.php:314 #: src/Frontend/AccountController.php:314
#: src/Frontend/AccountController.php:346 #: src/Frontend/AccountController.php:346
msgid "Please enter a valid domain." msgid "Please enter a valid domain."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:308 #: src/Admin/OrderLicenseController.php:342
msgid "Generating..."
msgstr ""
#: src/Admin/OrderLicenseController.php:362
#: src/Admin/OrderLicenseController.php:464
msgid "Invalid order ID." msgid "Invalid order ID."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:319 #: src/Admin/OrderLicenseController.php:373
#: src/Admin/OrderLicenseController.php:357 #: src/Admin/OrderLicenseController.php:411
msgid "Invalid domain format." msgid "Invalid domain format."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:327 #: src/Admin/OrderLicenseController.php:381
msgid "Order domain updated." msgid "Order domain updated."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:363 #: src/Admin/OrderLicenseController.php:417
#: src/Frontend/AccountController.php:352 #: src/Frontend/AccountController.php:352
#: src/Frontend/DownloadController.php:117 #: src/Frontend/DownloadController.php:117
msgid "License not found." msgid "License not found."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:371 #: src/Admin/OrderLicenseController.php:425
msgid "License domain updated." msgid "License domain updated."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:375 #: src/Admin/OrderLicenseController.php:429
msgid "Failed to update license domain." msgid "Failed to update license domain."
msgstr "" msgstr ""
#: src/Admin/OrderLicenseController.php:474
msgid "Order must be paid before licenses can be generated."
msgstr ""
#: src/Admin/OrderLicenseController.php:480
msgid "Please set the order domain before generating licenses."
msgstr ""
#: src/Admin/OrderLicenseController.php:521
#, php-format
msgid "%d license generated successfully."
msgid_plural "%d licenses generated successfully."
msgstr[0] ""
msgstr[1] ""
#: src/Admin/OrderLicenseController.php:534
msgid "All licenses already exist for this order."
msgstr ""
#: src/Admin/SettingsController.php:54 #: src/Admin/SettingsController.php:54
msgid "Licensed Products" msgid "Licensed Products"
msgstr "" msgstr ""
@@ -1563,11 +1608,11 @@ msgstr ""
msgid "This license is not valid for this domain." msgid "This license is not valid for this domain."
msgstr "" msgstr ""
#: src/License/PluginLicenseChecker.php:117 #: src/License/PluginLicenseChecker.php:132
msgid "License settings not configured." msgid "License settings not configured."
msgstr "" msgstr ""
#: src/License/PluginLicenseChecker.php:153 #: src/License/PluginLicenseChecker.php:168
msgid "Could not connect to license server." msgid "Could not connect to license server."
msgstr "" msgstr ""

Binary file not shown.

View File

@@ -0,0 +1 @@
fdb65200c368da380df0cabb3c6ac6419d5b4731cd528f630f9b432a3ba5c586 releases/wc-licensed-product-0.3.9.zip

View File

@@ -36,6 +36,7 @@ final class OrderLicenseController
// Handle AJAX actions // Handle AJAX actions
add_action('wp_ajax_wclp_update_order_domain', [$this, 'ajaxUpdateOrderDomain']); add_action('wp_ajax_wclp_update_order_domain', [$this, 'ajaxUpdateOrderDomain']);
add_action('wp_ajax_wclp_update_license_domain', [$this, 'ajaxUpdateLicenseDomain']); add_action('wp_ajax_wclp_update_license_domain', [$this, 'ajaxUpdateLicenseDomain']);
add_action('wp_ajax_wclp_generate_order_licenses', [$this, 'ajaxGenerateOrderLicenses']);
// Enqueue admin scripts // Enqueue admin scripts
add_action('admin_enqueue_scripts', [$this, 'enqueueScripts']); add_action('admin_enqueue_scripts', [$this, 'enqueueScripts']);
@@ -126,6 +127,18 @@ final class OrderLicenseController
<h4><?php esc_html_e('Licenses', 'wc-licensed-product'); ?></h4> <h4><?php esc_html_e('Licenses', 'wc-licensed-product'); ?></h4>
<?php
// Count licensed products to check if all have licenses
$licensedProductCount = 0;
foreach ($order->get_items() as $item) {
$product = $item->get_product();
if ($product && $product->is_type('licensed')) {
$licensedProductCount++;
}
}
$missingLicenses = $licensedProductCount - count($licenses);
?>
<?php if (empty($licenses)): ?> <?php if (empty($licenses)): ?>
<p class="description"> <p class="description">
<?php esc_html_e('No licenses have been generated for this order yet.', 'wc-licensed-product'); ?> <?php esc_html_e('No licenses have been generated for this order yet.', 'wc-licensed-product'); ?>
@@ -137,6 +150,20 @@ final class OrderLicenseController
<em><?php esc_html_e('Licenses will be generated when the order is marked as paid/completed.', 'wc-licensed-product'); ?></em> <em><?php esc_html_e('Licenses will be generated when the order is marked as paid/completed.', 'wc-licensed-product'); ?></em>
<?php endif; ?> <?php endif; ?>
</p> </p>
<?php if ($orderDomain && $order->is_paid()): ?>
<p style="margin-top: 10px;">
<button type="button" class="button button-primary" id="wclp-generate-licenses" data-order-id="<?php echo esc_attr($order->get_id()); ?>">
<?php esc_html_e('Generate Licenses', 'wc-licensed-product'); ?>
</button>
<span class="spinner" style="float: none; margin-top: 4px;"></span>
<span class="wclp-generate-status"></span>
</p>
<?php elseif (!$orderDomain): ?>
<p class="description" style="margin-top: 10px; color: #d63638;">
<span class="dashicons dashicons-warning"></span>
<?php esc_html_e('Please set the order domain above before generating licenses.', 'wc-licensed-product'); ?>
</p>
<?php endif; ?>
<?php else: ?> <?php else: ?>
<table class="widefat striped wclp-licenses-table"> <table class="widefat striped wclp-licenses-table">
<thead> <thead>
@@ -223,6 +250,29 @@ final class OrderLicenseController
); );
?> ?>
</p> </p>
<?php if ($missingLicenses > 0 && $orderDomain && $order->is_paid()): ?>
<p style="margin-top: 10px;">
<span class="dashicons dashicons-warning" style="color: #dba617;"></span>
<?php
printf(
/* translators: %d: Number of missing licenses */
esc_html(_n(
'%d licensed product is missing a license.',
'%d licensed products are missing licenses.',
$missingLicenses,
'wc-licensed-product'
)),
$missingLicenses
);
?>
<button type="button" class="button" id="wclp-generate-licenses" data-order-id="<?php echo esc_attr($order->get_id()); ?>">
<?php esc_html_e('Generate Missing Licenses', 'wc-licensed-product'); ?>
</button>
<span class="spinner" style="float: none; margin-top: 4px;"></span>
<span class="wclp-generate-status"></span>
</p>
<?php endif; ?>
<?php endif; ?> <?php endif; ?>
</div> </div>
@@ -248,6 +298,9 @@ final class OrderLicenseController
.wclp-lifetime { color: #0073aa; font-weight: 500; } .wclp-lifetime { color: #0073aa; font-weight: 500; }
.wclp-edit-domain-btn { color: #0073aa; text-decoration: none; } .wclp-edit-domain-btn { color: #0073aa; text-decoration: none; }
.wclp-edit-domain-btn .dashicons { font-size: 16px; width: 16px; height: 16px; } .wclp-edit-domain-btn .dashicons { font-size: 16px; width: 16px; height: 16px; }
.wclp-generate-status { font-style: italic; margin-left: 8px; }
.wclp-generate-status.success { color: #46b450; }
.wclp-generate-status.error { color: #dc3232; }
</style> </style>
<?php <?php
} }
@@ -284,8 +337,9 @@ final class OrderLicenseController
'strings' => [ 'strings' => [
'saving' => __('Saving...', 'wc-licensed-product'), 'saving' => __('Saving...', 'wc-licensed-product'),
'saved' => __('Saved!', 'wc-licensed-product'), 'saved' => __('Saved!', 'wc-licensed-product'),
'error' => __('Error saving. Please try again.', 'wc-licensed-product'), 'error' => __('Error. Please try again.', 'wc-licensed-product'),
'invalidDomain' => __('Please enter a valid domain.', 'wc-licensed-product'), 'invalidDomain' => __('Please enter a valid domain.', 'wc-licensed-product'),
'generating' => __('Generating...', 'wc-licensed-product'),
], ],
]); ]);
} }
@@ -392,4 +446,96 @@ final class OrderLicenseController
$pattern = '/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/'; $pattern = '/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/';
return (bool) preg_match($pattern, $domain); return (bool) preg_match($pattern, $domain);
} }
/**
* AJAX handler for generating order licenses
*/
public function ajaxGenerateOrderLicenses(): void
{
check_ajax_referer('wclp_order_license_actions', 'nonce');
if (!current_user_can('manage_woocommerce')) {
wp_send_json_error(['message' => __('Permission denied.', 'wc-licensed-product')]);
}
$orderId = absint($_POST['order_id'] ?? 0);
if (!$orderId) {
wp_send_json_error(['message' => __('Invalid order ID.', 'wc-licensed-product')]);
}
$order = wc_get_order($orderId);
if (!$order) {
wp_send_json_error(['message' => __('Order not found.', 'wc-licensed-product')]);
}
// Check if order is paid
if (!$order->is_paid()) {
wp_send_json_error(['message' => __('Order must be paid before licenses can be generated.', 'wc-licensed-product')]);
}
// Get domain
$domain = $order->get_meta('_licensed_product_domain');
if (empty($domain)) {
wp_send_json_error(['message' => __('Please set the order domain before generating licenses.', 'wc-licensed-product')]);
}
// Generate licenses for each licensed product
$generated = 0;
$skipped = 0;
foreach ($order->get_items() as $item) {
$product = $item->get_product();
if ($product && $product->is_type('licensed')) {
$license = $this->licenseManager->generateLicense(
$orderId,
$product->get_id(),
$order->get_customer_id(),
$domain
);
if ($license) {
// Check if this is a new license or existing
$existingLicenses = $this->licenseManager->getLicensesByOrder($orderId);
$isNew = true;
foreach ($existingLicenses as $existing) {
if ($existing->getProductId() === $product->get_id() && $existing->getId() !== $license->getId()) {
$isNew = false;
break;
}
}
if ($isNew) {
$generated++;
} else {
$skipped++;
}
}
}
}
if ($generated > 0) {
wp_send_json_success([
'message' => sprintf(
/* translators: %d: Number of licenses generated */
_n(
'%d license generated successfully.',
'%d licenses generated successfully.',
$generated,
'wc-licensed-product'
),
$generated
),
'generated' => $generated,
'skipped' => $skipped,
'reload' => true,
]);
} else {
wp_send_json_success([
'message' => __('All licenses already exist for this order.', 'wc-licensed-product'),
'generated' => 0,
'skipped' => $skipped,
'reload' => false,
]);
}
}
} }

View File

@@ -52,6 +52,11 @@ final class PluginLicenseChecker
*/ */
private ?bool $isLocalhostCached = null; private ?bool $isLocalhostCached = null;
/**
* Cached self-licensing check result
*/
private ?bool $isSelfLicensingCached = null;
/** /**
* Get singleton instance * Get singleton instance
*/ */
@@ -84,6 +89,11 @@ final class PluginLicenseChecker
return true; return true;
} }
// Always valid when self-licensing (server URL points to this installation)
if ($this->isSelfLicensing()) {
return true;
}
// Check cache first // Check cache first
$cached = get_transient(self::CACHE_KEY); $cached = get_transient(self::CACHE_KEY);
if ($cached !== false) { if ($cached !== false) {
@@ -107,6 +117,11 @@ final class PluginLicenseChecker
return true; return true;
} }
// Always valid when self-licensing (server URL points to this installation)
if ($this->isSelfLicensing()) {
return true;
}
// Check settings are configured // Check settings are configured
$serverUrl = $this->getLicenseServerUrl(); $serverUrl = $this->getLicenseServerUrl();
$licenseKey = $this->getLicenseKey(); $licenseKey = $this->getLicenseKey();
@@ -176,6 +191,7 @@ final class PluginLicenseChecker
delete_transient(self::CACHE_KEY); delete_transient(self::CACHE_KEY);
delete_transient(self::ERROR_CACHE_KEY); delete_transient(self::ERROR_CACHE_KEY);
$this->isLocalhostCached = null; $this->isLocalhostCached = null;
$this->isSelfLicensingCached = null;
} }
/** /**
@@ -215,6 +231,60 @@ final class PluginLicenseChecker
return false; return false;
} }
/**
* Check if self-licensing (license server URL points to this installation)
*
* Prevents circular dependency where plugin tries to validate against itself.
* Plugins can only be validated against the original store from which they were obtained.
*/
public function isSelfLicensing(): bool
{
if ($this->isSelfLicensingCached !== null) {
return $this->isSelfLicensingCached;
}
$serverUrl = $this->getLicenseServerUrl();
// No server URL configured - not self-licensing
if (empty($serverUrl)) {
$this->isSelfLicensingCached = false;
return false;
}
// Parse both URLs to compare domains
$serverParsed = parse_url($serverUrl);
$siteUrl = get_site_url();
$siteParsed = parse_url($siteUrl);
// Get normalized domains (lowercase, no www prefix)
$serverDomain = $this->normalizeDomain($serverParsed['host'] ?? '');
$siteDomain = $this->normalizeDomain($siteParsed['host'] ?? '');
// If domains match, this is self-licensing
if ($serverDomain === $siteDomain) {
$this->isSelfLicensingCached = true;
return true;
}
$this->isSelfLicensingCached = false;
return false;
}
/**
* Normalize a domain for comparison (lowercase, strip www)
*/
private function normalizeDomain(string $domain): string
{
$domain = strtolower(trim($domain));
// Strip www. prefix
if (str_starts_with($domain, 'www.')) {
$domain = substr($domain, 4);
}
return $domain;
}
/** /**
* Get the current domain from the site URL * Get the current domain from the site URL
*/ */

View File

@@ -3,7 +3,7 @@
* Plugin Name: WooCommerce Licensed Product * Plugin Name: WooCommerce Licensed Product
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wc-licensed-product * Plugin URI: https://src.bundespruefstelle.ch/magdev/wc-licensed-product
* Description: WooCommerce plugin to sell software products using license keys with domain-based validation. * Description: WooCommerce plugin to sell software products using license keys with domain-based validation.
* Version: 0.3.8 * Version: 0.4.0
* Author: Marco Graetsch * Author: Marco Graetsch
* Author URI: https://src.bundespruefstelle.ch/magdev * Author URI: https://src.bundespruefstelle.ch/magdev
* License: GPL-2.0-or-later * License: GPL-2.0-or-later
@@ -28,7 +28,7 @@ if (!defined('ABSPATH')) {
} }
// Plugin constants // Plugin constants
define('WC_LICENSED_PRODUCT_VERSION', '0.3.8'); define('WC_LICENSED_PRODUCT_VERSION', '0.4.0');
define('WC_LICENSED_PRODUCT_PLUGIN_FILE', __FILE__); define('WC_LICENSED_PRODUCT_PLUGIN_FILE', __FILE__);
define('WC_LICENSED_PRODUCT_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('WC_LICENSED_PRODUCT_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WC_LICENSED_PRODUCT_PLUGIN_URL', plugin_dir_url(__FILE__)); define('WC_LICENSED_PRODUCT_PLUGIN_URL', plugin_dir_url(__FILE__));