From 78e43b9aeae8e3df5cd858a3724b74775d53fc4c Mon Sep 17 00:00:00 2001 From: magdev Date: Wed, 21 Jan 2026 19:46:50 +0100 Subject: [PATCH] Implement version 0.0.3 features - Add file attachment support for product versions (Media Library) - Add version auto-detection from uploaded filenames - Implement secure customer downloads with hash verification - Add license key copy-to-clipboard functionality - Redesign customer licenses page with card-based UI - Fix product versions meta box visibility for non-licensed types - Add DownloadController for secure file delivery - Update CLAUDE.md roadmap and session history Co-Authored-By: Claude Opus 4.5 --- CHANGELOG.md | 27 ++- CLAUDE.md | 35 +++- assets/css/admin.css | 20 +++ assets/css/frontend.css | 248 +++++++++++++++++++++++--- assets/js/frontend.js | 90 ++++++++++ assets/js/versions.js | 116 +++++++++++- src/Admin/VersionAdminController.php | 65 +++++-- src/Frontend/AccountController.php | 151 +++++++++++----- src/Frontend/DownloadController.php | 237 ++++++++++++++++++++++++ src/Installer.php | 1 + src/Plugin.php | 9 +- src/Product/ProductVersion.php | 63 +++++++ src/Product/VersionManager.php | 14 +- templates/frontend/licenses.html.twig | 89 +++++---- wc-licensed-product.php | 4 +- 15 files changed, 1036 insertions(+), 133 deletions(-) create mode 100644 assets/js/frontend.js create mode 100644 src/Frontend/DownloadController.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 547e07f..7c8620e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [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 @@ -68,6 +92,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - WordPress REST API integration - Custom WooCommerce product type extending WC_Product -[Unreleased]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.2...HEAD +[Unreleased]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.3...HEAD +[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 diff --git a/CLAUDE.md b/CLAUDE.md index b7080fa..e18d47b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -36,12 +36,11 @@ This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase w _No known bugs at this time._ -### Version 0.0.3 (Next) +### Version 0.0.4 (Next) -- Add download file attachment support for product versions -- Implement customer download page for purchased licenses -- Add license key copy-to-clipboard functionality in emails and account page - Consider adding license usage statistics/analytics +- Consider adding bulk license operations in admin +- Consider adding license renewal/extension functionality ## Technical Stack @@ -289,3 +288,31 @@ Base: `/wp-json/wc-licensed-product/v1/` - Rate limiting uses WordPress transients - IP detection supports Cloudflare and proxies - Version management uses AJAX for smooth UX + +### 2026-01-21 - Version 0.0.3 Features + +**Implemented:** + +- 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 +- New card-based UI for customer licenses page with download section +- Product versions meta box visibility fix (now hidden for non-licensed product types) + +**New classes:** + +- `DownloadController` - Secure file delivery with hash-based URL verification + +**Technical notes:** + +- Secure download URLs use hash verification (license_id-version_id-hash format) +- Database schema updated: `attachment_id` column added to versions table +- ProductVersion model extended with `getEffectiveDownloadUrl()` and `getDownloadFilename()` +- Media uploader filters for zip files only +- Clipboard API with fallback for older browsers +- Card-based responsive UI design for licenses page + +**Bug fixes:** + +- Fixed product versions meta box visibility for non-licensed product types (targets `#wc_licensed_product_versions` container) diff --git a/assets/css/admin.css b/assets/css/admin.css index a2ae274..ce60dbf 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -145,3 +145,23 @@ font-style: italic; color: #666; } + +/* File Upload UI */ +.selected-file-name { + display: inline-block; + margin-right: 10px; + padding: 5px 10px; + background: #e7f3ff; + border-radius: 3px; + font-weight: 500; +} + +.selected-file-name:empty { + display: none; +} + +#versions-table .dashicons-media-archive { + color: #2271b1; + vertical-align: middle; + margin-left: 5px; +} diff --git a/assets/css/frontend.css b/assets/css/frontend.css index 884de01..68b9261 100644 --- a/assets/css/frontend.css +++ b/assets/css/frontend.css @@ -37,7 +37,206 @@ color: #383d41; } -/* License Table */ +/* License Cards */ +.woocommerce-licenses { + display: flex; + flex-direction: column; + gap: 1.5em; +} + +.license-card { + border: 1px solid #e5e5e5; + border-radius: 8px; + overflow: hidden; + background: #fff; +} + +.license-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1em 1.5em; + background: #f8f9fa; + border-bottom: 1px solid #e5e5e5; +} + +.license-header h3 { + margin: 0; + font-size: 1.1em; +} + +.license-header h3 a { + color: inherit; + text-decoration: none; +} + +.license-header h3 a:hover { + text-decoration: underline; +} + +.license-details { + padding: 1.5em; +} + +.license-key-row { + display: flex; + align-items: center; + gap: 0.75em; + margin-bottom: 1em; + flex-wrap: wrap; +} + +.license-key-row label { + font-weight: 600; +} + +.license-key-row code { + font-family: 'SF Mono', Monaco, Consolas, monospace; + background-color: #f5f5f5; + padding: 0.4em 0.8em; + border-radius: 4px; + font-size: 1em; + letter-spacing: 0.05em; +} + +.copy-license-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 0; + background: #f0f0f0; + border: 1px solid #ddd; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s ease; +} + +.copy-license-btn:hover { + background: #e5e5e5; + border-color: #ccc; +} + +.copy-license-btn .dashicons { + font-size: 18px; + width: 18px; + height: 18px; +} + +.copy-feedback { + display: inline-block; + margin-left: 0.5em; + padding: 0.25em 0.5em; + font-size: 0.85em; + border-radius: 3px; +} + +.copy-feedback.success { + background: #d4edda; + color: #155724; +} + +.copy-feedback.error { + background: #f8d7da; + color: #721c24; +} + +.license-info-row { + display: flex; + gap: 2em; + color: #666; + font-size: 0.95em; + flex-wrap: wrap; +} + +/* Download Section */ +.license-downloads { + padding: 1em 1.5em; + background: #f8f9fa; + border-top: 1px solid #e5e5e5; +} + +.license-downloads h4 { + margin: 0 0 0.75em 0; + font-size: 0.95em; + color: #333; +} + +.download-list { + list-style: none; + margin: 0; + padding: 0; +} + +.download-list li { + display: flex; + align-items: center; + gap: 1em; + padding: 0.5em 0; + border-bottom: 1px solid #eee; +} + +.download-list li:last-child { + border-bottom: none; +} + +.download-link { + display: inline-flex; + align-items: center; + gap: 0.5em; + color: #2271b1; + text-decoration: none; + font-weight: 500; +} + +.download-link:hover { + text-decoration: underline; +} + +.download-link .dashicons { + font-size: 16px; + width: 16px; + height: 16px; +} + +.download-version { + background: #e7f3ff; + padding: 0.2em 0.5em; + border-radius: 3px; + font-size: 0.85em; + color: #2271b1; +} + +.download-date { + color: #999; + font-size: 0.85em; + margin-left: auto; +} + +/* Domain Field */ +#licensed-product-domain-field { + margin-top: 2em; + padding: 1.5em; + background-color: #f8f9fa; + border: 1px solid #e5e5e5; + border-radius: 4px; +} + +#licensed-product-domain-field h3 { + margin-top: 0; + margin-bottom: 1em; + font-size: 1.1em; +} + +#licensed-product-domain-field .description { + display: block; + margin-top: 0.5em; + font-size: 0.9em; + color: #666; +} + +/* Legacy License Table (kept for backwards compatibility) */ .woocommerce-licenses-table { width: 100%; border-collapse: collapse; @@ -64,30 +263,33 @@ font-size: 0.9em; } -/* Domain Field */ -#licensed-product-domain-field { - margin-top: 2em; - padding: 1.5em; - background-color: #f8f9fa; - border: 1px solid #e5e5e5; - border-radius: 4px; -} - -#licensed-product-domain-field h3 { - margin-top: 0; - margin-bottom: 1em; - font-size: 1.1em; -} - -#licensed-product-domain-field .description { - display: block; - margin-top: 0.5em; - font-size: 0.9em; - color: #666; -} - /* Responsive */ @media screen and (max-width: 768px) { + .license-header { + flex-direction: column; + align-items: flex-start; + gap: 0.5em; + } + + .license-key-row { + flex-direction: column; + align-items: flex-start; + } + + .license-info-row { + flex-direction: column; + gap: 0.5em; + } + + .download-list li { + flex-wrap: wrap; + } + + .download-date { + margin-left: 0; + width: 100%; + } + .woocommerce-licenses-table, .woocommerce-licenses-table thead, .woocommerce-licenses-table tbody, diff --git a/assets/js/frontend.js b/assets/js/frontend.js new file mode 100644 index 0000000..909e3f9 --- /dev/null +++ b/assets/js/frontend.js @@ -0,0 +1,90 @@ +/** + * WC Licensed Product - Frontend Scripts + * + * @package Jeremias\WcLicensedProduct + */ + +(function($) { + 'use strict'; + + var WCLicensedProductFrontend = { + init: function() { + this.bindEvents(); + }, + + bindEvents: function() { + $(document).on('click', '.copy-license-btn', this.copyLicenseKey); + }, + + /** + * Copy license key to clipboard + */ + copyLicenseKey: function(e) { + e.preventDefault(); + + var $btn = $(this); + var licenseKey = $btn.data('license-key'); + + if (!licenseKey) { + return; + } + + // Use modern clipboard API if available + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(licenseKey) + .then(function() { + WCLicensedProductFrontend.showCopyFeedback($btn, true); + }) + .catch(function() { + WCLicensedProductFrontend.fallbackCopy(licenseKey, $btn); + }); + } else { + WCLicensedProductFrontend.fallbackCopy(licenseKey, $btn); + } + }, + + /** + * Fallback copy method for older browsers + */ + fallbackCopy: function(text, $btn) { + var $temp = $('