# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [0.7.1] - 2026-01-28 ### Fixed - **CRITICAL:** Fixed API Verification Secret not displayed in PHP fallback template on customer account licenses page - Response signing now includes `/update-check` endpoint (was missing from signed routes) ### Changed - Updated `magdev/wc-licensed-product-client` dependency to v0.2.2 - Updated `symfony/http-client` dependency to v7.4.5 ### Technical Details - Added customer secret display to `displayLicensesFallback()` method in `AccountController` - Added `/update-check` route to `ResponseSigner::shouldSign()` method for consistent signature headers - Verified server implementation aligns with updated client library documentation ## [0.7.0] - 2026-01-28 ### Security - Fixed XSS vulnerability in checkout blocks DOM fallback injection - Unified IP detection for rate limiting across all REST API endpoints - Added rate limiting to license transfers (5 per hour) and downloads (30 per hour) - Added file size (2MB), row count (1000), and rate limiting to CSV import - Added JSON decode error handling in Store API extension - Added jQuery selector sanitization for license ID validation ### Added - New `IpDetectionTrait` for shared IP detection logic with proxy support - New `RateLimitTrait` for reusable frontend rate limiting - New `src/Common/` directory for shared traits ### Changed - RestApiController now uses IpDetectionTrait instead of inline methods - UpdateController now uses IpDetectionTrait for consistent rate limiting behind proxies - AccountController now uses RateLimitTrait for transfer rate limiting - DownloadController now uses RateLimitTrait for download rate limiting - Checkout blocks fallback uses safe DOM construction instead of innerHTML ## [0.6.1] - 2026-01-27 ### Added - Filter functionality on customer account licenses page (filter by product or domain) - Split auto-update settings into two options: "Enable Update Notifications" and "Automatically Install Updates" - New `isUpdateNotificationEnabled()`, `isAutoInstallEnabled()` static methods in SettingsController - WordPress auto-update filter integration (`auto_update_plugin`) for automatic installation ### Fixed - Fixed admin license test popup showing empty product field - `handleAjaxTestLicense()` now enriches response with product name - Removed version field from test popup (version_id is only set for version-bound licenses) ### Changed - Updated `magdev/wc-licensed-product-client` dependency to v0.2.1 - "Automatically Install Updates" is only selectable when "Enable Update Notifications" is enabled ## [0.6.0] - 2026-01-27 ### Added - WordPress-style automatic update system for licensed plugins - Server-side `/update-check` REST API endpoint for WordPress-compatible update information - Client-side `PluginUpdateChecker` singleton for WordPress update integration - New "Auto-Updates" settings subtab with enable/disable and check frequency options - Secure download authentication via `X-License-Key` header - Response signing support for tamper-proof update responses - Configurable cache TTL for update checks (1-168 hours) ### Changed - Updated OpenAPI specification to version 0.6.0 with `/update-check` endpoint documentation ## [0.5.15] - 2026-01-27 ### Fixed - Fixed tab rendering bug in WooCommerce product edit page when switching to licensed or licensed-variable product types - Simplified JavaScript to avoid conflicts with WooCommerce's native show/hide logic - Removed conflicting CSS rule for `.hide_if_licensed` that was causing layout issues - License Settings tab now uses CSS class toggle (`.wclp-active`) instead of jQuery `.show()/.hide()` for proper display - Variations tab now properly shows for licensed-variable products via `woocommerce_product_data_tabs` filter ## [0.5.14] - 2026-01-27 ### Fixed - **CRITICAL:** Fixed Product Versions meta box not appearing for licensed-variable products - Product Versions meta box now always added to product pages, visibility controlled via CSS/JavaScript - Added `Installer::registerProductTypes()` to create product type terms in the `product_type` taxonomy - Product type terms are now ensured to exist on `woocommerce_init` hook for existing installations - Fixed License Settings tab and Product Versions visibility toggling when changing product types ## [0.5.13] - 2026-01-27 ### Fixed - **CRITICAL:** Fixed licenses not showing in admin order form for licensed-variable products - `OrderLicenseController` now uses `LicenseManager::isLicensedProduct()` for consistent product type detection - Fixed expected licenses calculation for variable product orders - Fixed manual license generation from admin order page for variable products ### Changed - Removed debug logging from all source files (PHP and JavaScript) - Cleaned up checkout blocks integration, Store API extension, and checkout controller ## [0.5.12] - 2026-01-27 ### Fixed - **CRITICAL:** Fixed stock indicator ("1 in stock") appearing in cart for licensed variable product variations - Override `get_children()` with direct SQL query to bypass WooCommerce's `is_type('variable')` check - Override `get_variation_attributes()` to properly load taxonomy attribute terms - Override `get_variation_prices()` to prevent fatal error with null `$this->prices_array` - Override `get_available_variations()` with empty `availability_html` for variations - Added `is_type()` override to return true for both 'licensed-variable' and 'variable' type checks - Added multiple stock-related filters: `woocommerce_get_availability_text`, `woocommerce_product_get_stock_quantity`, `woocommerce_product_variation_get_stock_quantity` - Improved `isLicensedProductOrVariation()` check using `WC_Product_Factory::get_product_type()` for reliable parent type detection ### Changed - `LicensedProductVariation` now includes `get_availability()`, `managing_stock()`, and `is_purchasable()` overrides - Simplified `isVirtual()` to use shared `isLicensedProductOrVariation()` helper ## [0.5.11] - 2026-01-27 ### Fixed - **CRITICAL:** Fixed "sold out" message on licensed variable products by correcting `is_purchasable()` method - Variable products don't have a direct price - `is_purchasable()` now delegates to parent `WC_Product_Variable` class - Fixed variation class detection by using product ID parameter instead of unreliable global `$post` - Product class filter now properly accepts all 4 WooCommerce filter parameters for reliable variation detection ## [0.5.10] - 2026-01-27 ### Fixed - Fixed licensed variable products not showing variations even when attributes are defined - Re-load product via `wc_get_product()` to ensure correct class instance is used - Removed overly strict type check that was preventing variations from displaying - Now mirrors WooCommerce's standard `woocommerce_variable_add_to_cart()` implementation ## [0.5.9] - 2026-01-27 ### Fixed - Fixed frontend error on licensed variable products when no attributes are defined - Added null checks for `get_variation_attributes()`, `get_available_variations()`, and `get_default_attributes()` - Show informative message instead of error when product has no variations configured - Changed product type check from `instanceof` to `is_type()` for better compatibility ## [0.5.8] - 2026-01-27 ### Fixed - **CRITICAL:** Fixed critical error on frontend product pages for licensed variable products - Variable product add-to-cart template now passes required variables (`available_variations`, `attributes`, `selected_attributes`) - Variants tab no longer disappears when saving attributes on licensed variable products - Added WooCommerce AJAX event listeners to maintain tab visibility during attribute operations ### Changed - Improved JavaScript event handling for licensed-variable product type in admin - Added listeners for `woocommerce_variations_loaded`, `woocommerce_variations_added`, `woocommerce_variations_saved` events - Added AJAX complete handler for attribute save operations ## [0.5.7] - 2026-01-27 ### Changed - Removed "Default" prefix from setting labels on Default Settings page for cleaner UI - Labels now read "Max Activations", "License Validity (Days)", and "Bind to Major Version" ## [0.5.6] - 2026-01-27 ### Fixed - License Settings tab now only shows for Licensed Product and Licensed Variable Product types - Previously the tab was visible on all product types due to CSS `!important` override ### Changed - Improved JavaScript for License Settings tab visibility handling on product type change - Updated README.md with complete feature documentation for v0.5.x features: - Variable Licensed Products - Multi-Domain Licensing - Per-License Customer Secrets - Download Statistics - Configurable Rate Limiting ## [0.5.5] - 2026-01-26 ### Fixed - **CRITICAL:** Response signing key derivation now uses native `hash_hkdf()` for RFC 5869 compliance - Key derivation now matches client library (`SecureLicenseClient`) exactly - Added missing domain validation to `/activate` endpoint (1-255 characters) ### Changed - `ResponseSigner::deriveCustomerSecret()` now uses `hash_hkdf('sha256', $serverSecret, 32, $licenseKey)` - Previous custom HKDF-like implementation was incompatible with client library ### Security - Signatures generated by server now verify correctly with `magdev/wc-licensed-product-client` - All three API endpoints now have consistent parameter validation ## [0.5.4] - 2026-01-26 ### Fixed - REST API `/validate` endpoint now returns HTTP 404 for `license_not_found` error (was 403) - License key validation now enforces minimum 8 characters per API documentation ### Added - Configurable rate limiting via `WC_LICENSE_RATE_LIMIT` and `WC_LICENSE_RATE_WINDOW` constants - Rate limit now defaults to 30 requests per 60 second window (configurable) ### Changed - Improved HTTP status code mapping: 404 for not found, 500 for server errors, 403 for all other errors - Rate limiting implementation now uses configurable constants instead of hardcoded values ## [0.5.3] - 2026-01-26 ### Added - Variable licensed product type (`licensed-variable`) for selling licenses with different durations - Support for monthly, yearly, quarterly, or lifetime license variations - `LicensedVariableProduct` class extending `WC_Product_Variable` - `LicensedProductVariation` class for individual variation license settings - Variation-specific license duration settings in product edit page - Duration labels displayed in checkout domain fields (e.g., "Yearly License") - Variation ID tracking in order domain meta for proper license generation ### Changed - Updated `LicenseManager::generateLicense()` to accept optional variation ID - Checkout now handles variations with separate domain fields per product/variation - WooCommerce Blocks checkout updated to display variation duration labels - Store API extension updated to include variation_id in domain data schema ## [0.5.2] - 2026-01-26 ### Added - Per-license customer secrets for API response verification - "API Verification Secret" section in customer account licenses page (collapsible) - Copy button for customer secrets with clipboard support - Documentation for per-license secret derivation and usage ### Security - Customers no longer need the master server secret for signature verification - Each license key has a unique derived secret using HKDF-like key derivation - If one customer's secret is compromised, other customers remain unaffected ### Changed - Updated `ResponseSigner` with static methods for secret derivation - Updated `server-implementation.md` with per-license secret documentation - Added new translation strings for secret-related UI ## [0.5.1] - 2026-01-26 ### Fixed - Product versions now sort correctly by version DESC when added via AJAX in admin - License actions in admin overview are now always visible instead of only on hover ### Changed - Added `compareVersions()` JavaScript function for proper semantic version comparison - Updated CSS with `!important` to override WordPress default hover-only behavior for row actions ## [0.5.0] - 2026-01-25 ### Added - Multi-domain licensing support: Customers can now purchase multiple licenses for different domains in a single order - Each cart item quantity requires a unique domain at checkout - New "Enable Multi-Domain Licensing" setting in WooCommerce > Settings > Licensed Products - Multi-domain checkout UI for WooCommerce Blocks checkout - DOM injection fallback for checkout domain fields when React component fails to render - Grouped license display in customer account page by product/order - "Older versions" collapsible section in customer download area - Updated email templates to show licenses grouped by product ### Changed - Customer account licenses page now shows licenses grouped by product package - Order meta now stores `_licensed_product_domains` array for multi-domain orders - Updated translations with 19 new strings for multi-domain functionality (de_CH) - Refactored checkout blocks JavaScript to use ExperimentalOrderMeta slot pattern ### Technical Details - `CheckoutBlocksIntegration` now uses `registerPlugin` with `woocommerce-checkout` scope - `StoreApiExtension` handles both single-domain and multi-domain data formats - `CheckoutController` validates unique domains per product in multi-domain mode - `AccountController` groups licenses by product for package-style display - Backward compatible: existing single-domain orders continue to work ## [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 ### Fixed - Fixed duplicate German translation string causing `ArgumentCountError` in settings page - The notification settings description had duplicated text with two `%s` placeholders ### Changed - Updated `magdev/wc-licensed-product-client` to latest version (64d215c) ## [0.3.7] - 2026-01-24 ### Added - Download counter for licensed product versions (tracked per version) - Download Statistics admin dashboard widget showing total downloads, top products, and top versions - New `DownloadWidgetController` class for download statistics widget - New `incrementDownloadCount()`, `getTotalDownloadCount()`, and `getDownloadStatistics()` methods in `VersionManager` - New `download_count` column in product versions database table ### Fixed - Dashboard widget "View All Licenses" link now uses correct page slug (`wc-licenses`) - Download links in customer account page no longer result in 404 errors (added query var registration) - Added `license-download` endpoint registration during plugin activation ### Changed - Removed redundant "Status Breakdown" section from dashboard widget (info already shown in stat cards) - License Types section in dashboard widget now uses card style matching the stats row above - Improved dashboard widget visual consistency ### Technical Details - Added `addDownloadQueryVar()` method to `DownloadController` for proper endpoint registration - Updated `Installer::activate()` to register `license-download` endpoint before flushing rewrite rules - Updated translations (356 strings) ## [0.3.6] - 2026-01-23 ### Security - Added CSRF protection (nonce verification) to CSV export functionality - Fixed IP header spoofing vulnerability in rate limiting - now requires explicit trusted proxy configuration - Enabled explicit Twig autoescape for XSS protection - Fixed unescaped status values in CSS classes in Twig templates ### Fixed - Fixed response signing to use recursive key sorting for client compatibility - ResponseSigner now recursively sorts nested array keys alphabetically as required by client implementation ### Changed - Rate limiting now only trusts proxy headers when `WC_LICENSE_TRUSTED_PROXIES` constant is defined - Added Cloudflare IP range support via `WC_LICENSE_TRUSTED_PROXIES = 'CLOUDFLARE'` configuration - Improved IP detection with CIDR notation support for trusted proxy ranges ### Technical Details - Added `recursiveKeySort()` method to `ResponseSigner` for proper response signing - Added `isTrustedProxy()`, `isCloudflareIp()`, and `ipMatchesCidr()` methods to `RestApiController` - Twig environment now explicitly sets `autoescape => 'html'` - Export CSV link now includes nonce via `wp_nonce_url()` - Added `export_csv_url()` Twig function for generating export URL with nonce ## [0.3.5] - 2026-01-23 ### Added - Admin dashboard widget showing license statistics on WordPress dashboard - Automatic license expiration via daily wp-cron job - License expired email notification sent when license auto-expires - New `LicenseExpiredEmail` WooCommerce email class (configurable via WooCommerce > Settings > Emails) ### Changed - Improved download list layout in customer account licenses page - Downloads now displayed in two-row format: file link on first row, metadata on second row - Better visual separation between download link and version/date/checksum information ### Technical Details - New `DashboardWidgetController` class in `src/Admin/` for WordPress dashboard widget - Widget displays: total licenses, active, expiring soon, expired counts, status breakdown, license types - New `LicenseExpiredEmail` class in `src/Email/` for expired license notifications - Added `getExpiredActiveLicenses()` and `autoExpireLicense()` methods to `LicenseManager` - Daily cron now auto-expires licenses with past expiration date and sends notification emails - Updated `templates/frontend/licenses.html.twig` with new two-row structure - Added `.download-item`, `.download-row-file`, `.download-row-meta` CSS classes - Improved responsive behavior for download metadata ## [0.3.4] - 2026-01-23 ### Added - Current version display on single product pages for licensed products - Version number shown directly under the product title - Frontend CSS styling for version badge with monospace font ### Technical Details - Added `displayCurrentVersion()` method to `LicensedProductType` class - Hooked to `woocommerce_single_product_summary` at priority 6 (after title) - Added `enqueueFrontendStyles()` to load CSS on product pages - Uses `LicensedProduct::get_current_version()` to fetch latest version ## [0.3.3] - 2026-01-22 ### Fixed - Fixed version deactivation button not working in admin product versions table - Corrected parameter order in `updateVersion()` call - `isActive` was being passed to `attachmentId` parameter ### Technical Details - Bug in `VersionAdminController::ajaxToggleVersion()` - parameters were in wrong order - Changed from `updateVersion($versionId, null, null, !$currentlyActive)` to `updateVersion($versionId, null, !$currentlyActive, null)` ## [0.3.2] - 2026-01-22 ### Changed - Updated OpenAPI specification to version 0.3.2 - Added documentation for response signing headers (X-License-Signature, X-License-Timestamp) - Enhanced API description with response signing security information ### Technical Details - OpenAPI spec now documents optional response signature headers - Added header component definitions for X-License-Signature and X-License-Timestamp - All endpoint 200 responses now reference signature headers - Improved API documentation describing SecureLicenseClient usage ## [0.3.1] - 2026-01-22 ### Changed - Settings page reorganized with sub-tab navigation similar to WooCommerce Advanced tab - Settings split into three sections: Plugin License, Default Settings, Notifications - Improved settings UI with WooCommerce-style section navigation ### Technical Details - SettingsController refactored with `getSections()` and `outputSections()` methods - Section-specific settings methods using PHP 8 match expression - Hooks updated to use `woocommerce_sections_licensed_product` for sub-navigation ## [0.3.0] - 2026-01-22 ### Added - Self-licensing functionality: Plugin validates its own license against a remote server - Plugin license settings in WooCommerce > Settings > Licensed Products tab - License Server URL, License Key, and optional Server Secret configuration - License status display in settings with verify button - Localhost bypass: All features work without license when running on localhost - Admin notice when plugin license is not configured or invalid ### Changed - Frontend features now require a valid plugin license to function - Disabled features without license: Checkout domain field, customer licenses page, downloads, license generation ### Technical Details - New `PluginLicenseChecker` singleton class for license validation - Integration with `magdev/wc-licensed-product-client` Composer package - Caching: 1 hour for valid license, 5 minutes for errors - Localhost detection supports: localhost, 127.0.0.1, ::1, and .localhost/.local subdomains ## [0.2.2] - 2026-01-22 ### Added - SHA256 checksum column in admin product versions table - File hash display in customer account downloads section - Visual indicators for file integrity verification ### Changed - Checksum file upload field now styled consistently with package upload field - Download list items now show truncated hash with full hash on hover ### Technical Details - ProductVersion `getFileHash()` method now exposed in admin and frontend views - Frontend CSS extended with `.download-hash` styles - Admin CSS extended with `.file-hash` styles ## [0.2.1] - 2026-01-22 ### Changed - SHA256 hash input changed from text field to file upload field - Checksum files (.sha256 or .txt) can now be uploaded directly - Improved user experience for version integrity verification ### Technical Details - Added `readChecksumFile()` JavaScript function using FileReader API with Promise support - Checksum file format supports both "hash filename" and plain "hash" formats - Added localized error messages for checksum file validation ## [0.2.0] - 2026-01-22 ### Added - Response signing for REST API using HMAC-SHA256 - SHA256 hash field for product version uploads with checksum validation - File integrity verification before storing uploaded version files - New `ResponseSigner` class for automatic API response signing - Database column `file_hash` in versions table for storing checksums ### Changed - Version uploads now require file attachments (external URL option removed) - API responses now include `X-License-Signature` and `X-License-Timestamp` headers when `WC_LICENSE_SERVER_SECRET` is configured ### Removed - External download URL field from product version form - Direct URL support in version uploads (use Media Library uploads only) ### Security - API response signing prevents tampering and replay attacks - Per-license key derivation using HKDF-like approach - SHA256 checksum validation ensures file integrity ### Technical Details - New class: `ResponseSigner` for HMAC-SHA256 response signing - VersionManager extended with `$fileHash` parameter and validation - ProductVersion model extended with `fileHash` property - Signature algorithm: `HMAC-SHA256(derived_key, timestamp + ':' + canonical_json)` - Key derivation: `HMAC-SHA256(HMAC-SHA256(license_key, server_secret) + "\x01", server_secret)` - Compatible with `magdev/wc-licensed-product-client` SecureLicenseClient ### Configuration To enable response signing, add to `wp-config.php`: ```php define('WC_LICENSE_SERVER_SECRET', 'your-secure-random-string-min-32-chars'); ``` ## [0.1.0] - 2026-01-22 ### Added - First stable minor release - Comprehensive code review for WordPress/WooCommerce best practices - Security audit completed ### Changed - Improved input sanitization for admin page context checks - Fixed VersionManager null format handling for attachment updates ### Technical Details - All code reviewed for OWASP Top 10 security vulnerabilities - Verified proper nonce verification, capability checks, and input sanitization - SQL injection prevention confirmed using `$wpdb->prepare()` throughout - XSS prevention confirmed with proper output escaping - Rate limiting verified on REST API endpoints - README.md updated with full feature documentation ## [0.0.11] - 2026-01-22 ### Added - Created date column in admin license overview ### Technical Details - Added "Created" column to licenses table in admin (Twig template and PHP fallback) - Shows when each license was generated ## [0.0.10] - 2026-01-21 ### Added - License meta box on WooCommerce order edit pages - Editable order domain field with AJAX save - Editable license domains directly from order page - View licenses table showing all licenses for an order - Link to full licenses management page from order view - Support for both classic orders and HPOS (High-Performance Order Storage) - Inline editing for license fields (status, expiry date, domain) in admin - Copy license key button in admin licenses overview - Live search for licenses in admin overview - Settings link in plugin actions ### Fixed - Fixed 404 error on licenses menu item - Fixed Twig template cache issues with auto_reload ### Technical Details - New `OrderLicenseController` class for order page integration - New `getLicensesByOrder()` method in LicenseManager - New `updateLicenseExpiry()` method in LicenseManager - JavaScript file `order-licenses.js` for inline domain editing - JavaScript file `admin-licenses.js` for live search and inline editing - AJAX handlers for updating order domain and license domains - AJAX handlers for inline editing (status, expiry, domain updates) ## [0.0.9] - 2026-01-21 ### Added - API client examples for multiple programming languages - cURL command examples (`docs/client-examples/curl.sh`) - PHP client class (`docs/client-examples/php-client.php`) - Python client class (`docs/client-examples/python-client.py`) - JavaScript/Node.js client (`docs/client-examples/javascript-client.js`) - C# client class (`docs/client-examples/csharp-client.cs`) - Client examples documentation (`docs/client-examples/README.md`) ### Technical Details - All clients include rate limiting handling (HTTP 429) - Examples demonstrate validate, status, and activate endpoints - JavaScript client works in both browser and Node.js environments - Python client uses dataclasses for type-safe responses - C# client uses async/await patterns ## [0.0.8] - 2026-01-21 ### Changed - Current version now automatically derived from latest product version - Email system refactored to use WooCommerce transactional emails - License expiration warning email now configurable via WooCommerce email settings ### Removed - "Current Version" field from product license settings panel ### Technical Details - New `LicenseExpirationEmail` class extends WC_Email - LicensedProduct's `get_current_version()` queries VersionManager - Uses WooCommerce email header/footer templates - Warning days configurable in plugin settings ## [0.0.7] - 2026-01-21 ### Added - License Dashboard moved to WooCommerce Reports section (Reports > Licenses) - License search and filtering in admin (by license key, domain, status, product) - Customer-facing license transfer request with AJAX-based modal - Email notifications for license expiration warnings (7 days and 1 day before) - Bulk import licenses from CSV functionality - Import page with detailed format instructions - Scheduled cron job for daily expiration checks ### Changed - Dashboard now accessible via WooCommerce > Reports > Licenses tab - License list page includes search box and filter dropdowns - Pagination preserves filter state - Import CSV button added to licenses page header ### Technical Details - AccountController extended with customer transfer AJAX handler and domain normalization - LicenseEmailController extended with expiration warning scheduling and email templates - LicenseManager extended with `getLicensesExpiringSoon()`, `markExpirationNotified()`, `wasExpirationNotified()`, `importLicense()` methods - AdminController extended with CSV import handling and import page rendering - Installer clears cron events on plugin deactivation - Frontend JavaScript extended for transfer modal handling - Frontend CSS extended with modal and transfer button styles ## [0.0.6] - 2026-01-21 ### Added - License usage statistics/analytics dashboard (WooCommerce > License Dashboard) - License transfer functionality to change domain from admin - Export licenses to CSV functionality - OpenAPI 3.1 specification for REST API documentation (`openapi.json`) - Monthly license creation chart on dashboard - Top products and top domains statistics - Expiring soon alerts on dashboard ### Removed - API endpoint `/deactivate` removed (license deactivation is now admin-only) ### Changed - Licenses admin page header now includes Export CSV button - Actions column widened to accommodate Transfer link - Dashboard link added to licenses page ### Technical Details - New admin page: License Dashboard with statistics overview - LicenseManager extended with `transferLicense()`, `getStatistics()`, `exportLicensesForCsv()` methods - AdminController extended with dashboard rendering, CSV export, and transfer handling - Transfer modal with form for domain change - REST API now only has three endpoints: `/validate`, `/status`, `/activate` - OpenAPI 3.1 specification documents all API endpoints with examples ## [0.0.5] - 2026-01-21 ### Added - Bulk license operations in admin (activate, deactivate, revoke, extend, delete) - License renewal/extension functionality (extend by 30/90/365 days) - Set license to lifetime (remove expiration) - Quick action buttons per license row (+30d, ∞, Revoke, Delete) - Checkbox selection for bulk operations with select-all functionality - Improved admin notices for bulk operation results ### Changed - Licenses admin page redesigned with WordPress list table styling - License actions use row-actions pattern for cleaner UI - Bulk action dropdowns at top and bottom of table (synchronized) ### Technical Details - LicenseManager extended with `extendLicense()`, `setLicenseLifetime()`, `bulkUpdateStatus()`, `bulkDelete()`, `bulkExtend()` methods - AdminController extended with bulk action handling and extend/lifetime actions - Twig template functions for generating action URLs with nonces - JavaScript for checkbox sync and bulk action handling ## [0.0.4] - 2026-01-21 ### Added - WooCommerce settings tab "Licensed Products" for default license settings - Default settings for Max Activations, License Validity, and Bind to Major Version - Per-product settings now override global defaults (empty = use default) - Settings link in product edit page pointing to WooCommerce settings ### Changed - Product license settings now show placeholder with default values - LicensedProduct class now falls back to global defaults when product settings are empty ### Technical Details - New class: SettingsController for WooCommerce settings integration - LicensedProduct model extended with `has_custom_*` methods for checking overrides - Settings stored using WooCommerce options API ## [0.0.3] - 2026-01-21 ### Added - File attachment support for product versions (WordPress Media Library integration) - Version auto-detection from uploaded filenames (e.g., `plugin-v1.2.3.zip`) - Customer download page for purchased licenses with secure authenticated downloads - License key copy-to-clipboard functionality on account page and emails - New card-based UI for customer licenses page with download section - DownloadController for secure file delivery with hash-based URL verification ### Changed - Product versions meta box now hidden for non-licensed product types (dynamic show/hide) - Redesigned customer licenses page with modern card layout - Frontend JavaScript and CSS enhancements for better UX ### Technical Details - New class: DownloadController for secure file downloads - Database schema updated: `attachment_id` column added to versions table - ProductVersion model extended with `getEffectiveDownloadUrl()` and `getDownloadFilename()` - Secure download URLs use hash verification (license_id-version_id-hash format) ## [0.0.2] - 2026-01-21 ### Added - Product version management UI in admin (meta box on product edit page) - AJAX-based version CRUD operations (add, delete, toggle active status) - ProductVersion model and VersionManager for version data handling - Email notifications with license keys on order completion - License information included in WooCommerce order completed emails - Rate limiting for REST API endpoints (30 requests/minute per IP) - Cloudflare and proxy-aware IP detection for rate limiting - JavaScript for version management interactions ### Changed - Declared WooCommerce HPOS and cart/checkout blocks compatibility - Plugin name changed from "WC Licensed Product" to "WooCommerce Licensed Product" ### Technical Details - New classes: ProductVersion, VersionManager, VersionAdminController, LicenseEmailController - Rate limiting uses WordPress transients for request counting - HTTP 429 response with Retry-After header when rate limited ## [0.0.1] - 2026-01-21 ### Added - Initial plugin structure with WordPress Plugin API integration - New WooCommerce product type "Licensed Product" for selling software licenses - License key generation with format XXXX-XXXX-XXXX-XXXX on order completion - Domain-based license validation (licenses bound to specific domains) - REST API endpoints for license management: - `POST /wp-json/wc-licensed-product/v1/validate` - Validate license for domain - `POST /wp-json/wc-licensed-product/v1/status` - Check license status - `POST /wp-json/wc-licensed-product/v1/activate` - Activate license on domain - Checkout domain field for licensed products - Customer account page "Licenses" to view purchased licenses - Admin interface for license management (WooCommerce > Licenses) - License settings per product: - Maximum activations per license - License validity period (days or lifetime) - Optional binding to major software version - Current version tracking - Custom database tables for licenses and product versions - Twig template engine integration for views - Full internationalization support (i18n) - German (Switzerland, formal) translation (de_CH) - WooCommerce HPOS compatibility - Responsive frontend license table ### Technical - PHP 8.3+ required - WooCommerce 10.0+ required - PSR-4 autoloading via Composer - Twig 3.0 template engine - WordPress REST API integration - Custom WooCommerce product type extending WC_Product [Unreleased]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.3.3...HEAD [0.3.3]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.3.2...v0.3.3 [0.3.2]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.3.1...v0.3.2 [0.3.1]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.3.0...v0.3.1 [0.3.0]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.2.2...v0.3.0 [0.2.2]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.2.1...v0.2.2 [0.2.1]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.2.0...v0.2.1 [0.2.0]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.1.0...v0.2.0 [0.1.0]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.11...v0.1.0 [0.0.11]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.10...v0.0.11 [0.0.10]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.9...v0.0.10 [0.0.9]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.8...v0.0.9 [0.0.8]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.7...v0.0.8 [0.0.7]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.6...v0.0.7 [0.0.6]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.5...v0.0.6 [0.0.5]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.4...v0.0.5 [0.0.4]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.3...v0.0.4 [0.0.3]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.2...v0.0.3 [0.0.2]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.1...v0.0.2 [0.0.1]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/releases/tag/v0.0.1