You've already forked wc-licensed-product
All checks were successful
Create Release Package / build-release (push) Successful in 1m9s
- Add example Grafana dashboard with 24 panels for license metrics - Register dashboard with wp-prometheus via hook - Add dashboard documentation with PromQL examples and alerting rules - Update README with monitoring section Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1009 lines
41 KiB
Markdown
1009 lines
41 KiB
Markdown
# 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.5] - 2026-02-03
|
|
|
|
### Added
|
|
|
|
- **Grafana Dashboard**: Example dashboard for license metrics monitoring
|
|
- 24 panels organized into 4 sections: License Overview, Downloads & Versions, API Metrics, Errors & Rate Limiting
|
|
- Template variables for data source and instance filtering
|
|
- Includes example Prometheus alerting rules
|
|
- **WP Prometheus Dashboard Integration**: Dashboard automatically registered with wp-prometheus
|
|
- Appears in Settings > WP Prometheus > Dashboards when metrics are enabled
|
|
- Uses `wp_prometheus_register_dashboards` hook for seamless integration
|
|
- Documentation for Grafana dashboard installation and PromQL query examples
|
|
|
|
### New Files
|
|
|
|
- `docs/grafana-dashboard.json` - Complete Grafana dashboard with 24 panels
|
|
- `docs/grafana-dashboard.md` - Installation and usage documentation
|
|
|
|
### Changed
|
|
|
|
- Updated README with "Monitoring with Prometheus & Grafana" section
|
|
|
|
## [0.7.4] - 2026-02-03
|
|
|
|
### Added
|
|
|
|
- **Prometheus Metrics Integration**: Expose license and API metrics for monitoring
|
|
- New "Metrics" settings tab with enable/disable toggle
|
|
- License gauges: total by status, lifetime, expiring, expiring soon
|
|
- Download gauges: total downloads, active versions count
|
|
- API counters: requests by endpoint/result, rate limit exceeded events, validation errors by type
|
|
- Requires [WP Prometheus](https://src.bundespruefstelle.ch/magdev/wp-prometheus) plugin
|
|
|
|
### New Files
|
|
|
|
- `src/Metrics/PrometheusController.php` - Prometheus metrics collection and registration
|
|
|
|
### Technical Details
|
|
|
|
- Hooks into `wp_prometheus_collect_metrics` action for metric collection
|
|
- API counters stored persistently in WordPress options (`wclp_prometheus_counters`)
|
|
- Static methods for incrementing counters from API controllers
|
|
- Metrics only collected when enabled in settings
|
|
|
|
## [0.7.3] - 2026-02-01
|
|
|
|
### Fixed
|
|
|
|
- **Docker Environment Support:** API Verification Secret now visible on customer licenses page in Docker environments
|
|
- Added `ResponseSigner::getServerSecret()` method to check multiple sources for server secret
|
|
- Checks PHP constant, `getenv()`, `$_ENV`, and `$_SERVER` in priority order
|
|
- Maintains full backward compatibility with standard WordPress installations
|
|
|
|
### Changed
|
|
|
|
- Updated `Plugin.php` to use `ResponseSigner::isSigningEnabled()` instead of direct constant check
|
|
|
|
### Technical Details
|
|
|
|
- Root cause: Docker WordPress setups using `wp-config-docker.php` with `getenv_docker()` don't always define PHP constants
|
|
- The environment variable was accessible but the constant wasn't being created
|
|
- New `getServerSecret()` method centralizes all server secret retrieval logic
|
|
|
|
## [0.7.2] - 2026-01-29
|
|
|
|
### Added
|
|
|
|
- **Gitea CI/CD Pipeline**: Automated release workflow triggered on version tags
|
|
- Automatic package creation with proper WordPress subdirectory structure
|
|
- SHA256 checksum generation for package integrity
|
|
- Changelog extraction for release notes
|
|
- Pre-release detection for hyphenated tags (e.g., `v0.7.2-rc1`)
|
|
|
|
### Changed
|
|
|
|
- **Git Submodule Migration**: `magdev/wc-licensed-product-client` is now a git submodule
|
|
- Located at `lib/wc-licensed-product-client` instead of being fetched via Composer VCS
|
|
- Composer now uses `path` type repository pointing to local submodule
|
|
- Improves version control clarity and development workflow
|
|
- Symlinked to `vendor/` during `composer install`
|
|
|
|
### Developer Notes
|
|
|
|
- New file: `.gitea/workflows/release.yml` for CI/CD automation
|
|
- Updated `composer.json`: Repository type changed from `vcs` to `path`
|
|
- Created `.gitmodules` for submodule tracking
|
|
- Release packages now exclude `lib/` directory (vendor has installed copy)
|
|
- Submodule checkout required: `git submodule update --init --recursive`
|
|
|
|
## [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
|