- 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>
- New Metrics settings tab with enable/disable toggle
- PrometheusController for wp_prometheus_collect_metrics hook
- License gauges: total by status, lifetime, expiring, expiring soon
- Download gauges: total downloads, active versions
- API counters: requests, rate limits, validation errors
- Metric tracking in RestApiController and UpdateController
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ResponseSigner::getServerSecret() to check multiple sources
- Check constant, getenv(), $_ENV, and $_SERVER for server secret
- Update Plugin.php to use ResponseSigner::isSigningEnabled()
- Maintains backward compatibility with standard WordPress setups
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
## Fixed
- CRITICAL: Fixed API Verification Secret not displayed in PHP fallback template
- Response signing now includes /update-check endpoint
## Changed
- Updated magdev/wc-licensed-product-client to v0.2.2
- Updated symfony/http-client to v7.4.5
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security Fixes:
- Fixed XSS vulnerability in checkout blocks DOM injection (replaced innerHTML with safe DOM methods)
- Unified IP detection for rate limiting across all API endpoints (new IpDetectionTrait)
- Added rate limiting to license transfers (5/hour) and downloads (30/hour) (new RateLimitTrait)
- Added file size limit (2MB), row limit (1000), and rate limiting to CSV import
- Added JSON decode error handling in StoreApiExtension
- Added license ID validation in frontend.js to prevent selector injection
New Files:
- src/Api/IpDetectionTrait.php - Shared IP detection with proxy support
- src/Common/RateLimitTrait.php - Reusable rate limiting for frontend operations
Breaking Changes:
- None
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix admin license test popup showing empty product field
- Display product name in bold in test license modal
- Split auto-update settings into notification and auto-install options
- Add filter functionality to customer account licenses page
- Update translations (402 strings)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add UpdateController REST API endpoint for serving update info to licensed plugins
- Add PluginUpdateChecker singleton for client-side update checking
- Hook into WordPress native plugin update system (pre_set_site_transient_update_plugins, plugins_api)
- Add Auto-Updates settings subtab with enable/disable and check frequency options
- Add authentication headers for secure download requests
- Support configurable cache TTL for update checks (default 12 hours)
- Document /update-check endpoint in OpenAPI specification
- Update German translations
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Simplified JavaScript to avoid conflicts with WooCommerce's native show/hide logic
- Removed conflicting CSS rule for .hide_if_licensed
- License Settings tab uses CSS class toggle for proper display
- Variations tab properly shows for licensed-variable via woocommerce_product_data_tabs filter
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 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
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix OrderLicenseController to use 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
- Remove debug logging from all source files (PHP and JavaScript)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fixed stock indicator appearing in cart for licensed variable products
- Override get_children() with direct SQL query to bypass WooCommerce type check
- Override get_variation_attributes() for proper taxonomy attribute loading
- Override get_variation_prices() to prevent null array errors
- Override get_available_variations() with empty availability_html
- Added is_type() override to pass variable type checks
- Added multiple stock-related filters for comprehensive coverage
- Improved isLicensedProductOrVariation() with DB-level parent type check
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fixed is_purchasable() method in LicensedVariableProduct to delegate to
parent WC_Product_Variable instead of checking for price (variable products
don't have direct prices, only their variations do)
- Fixed getProductClass() filter to accept all 4 WooCommerce parameters
and use product_id for reliable variation parent detection
- Fallback to global $post when product_id not available for backwards compat
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Re-load product via wc_get_product() to ensure correct class instance
- Removed overly strict type check that prevented variations from displaying
- Now mirrors WooCommerce's standard woocommerce_variable_add_to_cart()
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added null checks for get_variation_attributes(), get_available_variations(), get_default_attributes()
- Show informative message when product has no variations configured
- Changed product type check from instanceof to is_type() for better compatibility
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Max Activations (was "Default Max Activations")
- License Validity (Days) (was "Default License Validity (Days)")
- Bind to Major Version (was "Default Bind to Major Version")
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
CRITICAL: Key derivation now uses native hash_hkdf() for RFC 5869
compliance. Previous custom implementation was incompatible with
the magdev/wc-licensed-product-client library.
Changes:
- ResponseSigner::deriveCustomerSecret() now uses hash_hkdf()
- Added missing domain validation to /activate endpoint
- Customer secrets will change after upgrade (breaking change)
The signature algorithm now matches the client's ResponseSignature::deriveKey():
- IKM: server_secret
- Length: 32 bytes
- Info: license_key
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixed HTTP status codes for API responses:
- /validate now returns 404 for license_not_found (was 403)
- Added status code mapping: 404 not found, 500 server errors, 403 others
Added configurable rate limiting:
- WC_LICENSE_RATE_LIMIT constant for requests per window
- WC_LICENSE_RATE_WINDOW constant for window duration in seconds
Fixed license_key validation:
- Now enforces minimum 8 characters across all endpoints
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Customers can now purchase licenses with different durations (monthly,
yearly, lifetime) through WooCommerce product variations. Each variation
can have its own license validity settings.
New features:
- LicensedVariableProduct class for variable licensed products
- LicensedProductVariation class for individual variations
- Per-variation license duration and max activations settings
- Duration labels in checkout (Monthly, Quarterly, Yearly, etc.)
- Full support for WooCommerce Blocks checkout with variations
- Updated translations for German (de_CH)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add static methods to ResponseSigner for deriving customer-specific secrets
- Display "API Verification Secret" in customer account licenses page
- Add collapsible secret section with copy button
- Update server-implementation.md with per-license secret documentation
- Update translations with new strings
Each customer now gets a unique verification secret derived from their
license key, eliminating the need to share the master server secret.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add multi-domain checkout support for WooCommerce Blocks
- Fix domain field rendering using ExperimentalOrderMeta slot
- Add DOM injection fallback for checkout field rendering
- Update translations with new multi-domain strings (de_CH)
- Update email templates for grouped license display
- Refactor account page to group licenses by product/order
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 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>
- 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>
- Add recursive key sorting for response signing compatibility
- Fix IP header spoofing in rate limiting with trusted proxy support
- Add CSRF protection to CSV export with nonce verification
- Explicit Twig autoescape for XSS prevention
- Escape status values in CSS classes
- Update README with security documentation and trusted proxy config
- Update translations for v0.3.6
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add admin dashboard widget with license statistics
- Add daily wp-cron to auto-expire licenses past expiration date
- Add LicenseExpiredEmail notification for expired licenses
- Add getExpiredActiveLicenses() and autoExpireLicense() to LicenseManager
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Display current version under product title for licensed products
- Add frontend CSS styling for version badge
- Update translations for new "Version:" string
- Bump version to 0.3.4
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The PHP fallback template (used when Twig fails) was missing the Test
license action and Transfer modal that were present in the Twig template.
- Added Test license link to row actions in PHP fallback
- Added Transfer link to row actions in PHP fallback
- Added Test License modal with AJAX validation
- Added Transfer License modal
- Added JavaScript handlers for both modals
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added a "Test" action button in the license overview that validates
licenses against the /validate REST API endpoint. Results are shown
in a modal with validation status, error codes, and license details.
- Added Test link in row actions for each license
- Created AJAX handler handleAjaxTestLicense() in AdminController
- Added test result modal with loading state and result display
- Shows valid/invalid status with detailed error information
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The toggle version button in the admin product versions table was not
deactivating versions due to incorrect parameter order in the
updateVersion() call. The isActive value was being passed to the
attachmentId parameter position instead.
- Fixed parameter order: updateVersion($id, null, !$active, null)
- Bumped version to 0.3.3
- Updated CHANGELOG.md
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Wrap filename link and media-archive icon in a flex container
with white-space: nowrap to keep them on a single line.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Features:
- Add SHA256 column to admin product versions table
- Display file hash in customer account downloads section
- Style checksum file upload field consistently with package upload
Changes:
- Admin versions table shows truncated hash with full hash on hover
- Customer downloads show hash with shield icon indicator
- Updated German translations
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Changed plain file input to styled button with filename display
- Added Select/Remove buttons for checksum file upload
- Updated JavaScript handlers for styled checksum file input
- Updated German translation for new button text
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace SHA256 text input with file upload field for checksum files
- Add readChecksumFile() JavaScript function using FileReader API
- Support .sha256 and .txt checksum file formats
- Add Promise-based async handling for file reading
- Add localized error messages for checksum file validation
- Update translations (de_CH) with new strings
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add REST API response signing using HMAC-SHA256
- Add SHA256 hash validation for version file uploads
- Add ResponseSigner class for automatic API response signing
- Add file_hash column to database schema
- Remove external URL support from version uploads
- Update translations with all fuzzy strings resolved
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Conducted comprehensive security and best practices review
- Fixed VersionManager null format handling for attachment updates
- Improved input sanitization in AdminController for page context checks
- Updated README.md with complete feature documentation
- Updated CHANGELOG.md with 0.1.0 release notes
- Updated translations (.pot, .po, .mo files) to version 0.1.0
- Bumped version to 0.1.0 in plugin header and constant
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Keep existing Reports > Licenses dashboard which works correctly.
Version 0.0.11 now only includes the Created column in license overview.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Store the AnalyticsController instance as a class property
to prevent it from being garbage collected before WordPress
can call the registered callbacks.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Catch all Twig errors (not just LoaderError) to ensure
fallback to PHP rendering works properly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed capability from manage_woocommerce to manage_options
to ensure admin users can access the page.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Created date column to admin license overview
- Add License Statistics page under WooCommerce menu
- Add REST API endpoints for analytics data with time-series support
- WooCommerce Analytics integration via submenu page
New files:
- src/Admin/AnalyticsController.php
- templates/admin/statistics.html.twig
REST API endpoints:
- GET /wc-licensed-product/v1/analytics/stats
- GET /wc-licensed-product/v1/analytics/products
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add inline editing for status, expiry date, and domain fields
- Add copy-to-clipboard button for license keys
- Add AJAX handlers for inline editing with nonce verification
- Update LicenseManager with updateLicenseExpiry method
- Add new translations for inline editing strings (de_CH)
- Compile updated German translations to .mo file
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This ensures template changes are detected even when WP_DEBUG is false,
avoiding stale cache issues.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>