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 <noreply@anthropic.com>
This commit is contained in:
2026-01-21 19:46:50 +01:00
parent 41e5f8d467
commit 78e43b9aea
15 changed files with 1036 additions and 133 deletions

View File

@@ -1,46 +1,63 @@
{% if not has_licenses %}
<p>{{ __('You have no licenses yet.') }}</p>
{% else %}
<table class="woocommerce-licenses-table shop_table shop_table_responsive">
<thead>
<tr>
<th>{{ __('License Key') }}</th>
<th>{{ __('Product') }}</th>
<th>{{ __('Domain') }}</th>
<th>{{ __('Status') }}</th>
<th>{{ __('Expires') }}</th>
</tr>
</thead>
<tbody>
{% for item in licenses %}
<tr>
<td data-title="{{ __('License Key') }}">
<code>{{ item.license.licenseKey }}</code>
</td>
<td data-title="{{ __('Product') }}">
<div class="woocommerce-licenses">
{% for item in licenses %}
<div class="license-card">
<div class="license-header">
<h3>
{% if item.product_url %}
<a href="{{ esc_url(item.product_url) }}">{{ esc_html(item.product_name) }}</a>
{% else %}
{{ esc_html(item.product_name) }}
{% endif %}
</td>
<td data-title="{{ __('Domain') }}">
{{ esc_html(item.license.domain) }}
</td>
<td data-title="{{ __('Status') }}">
<span class="license-status license-status-{{ item.license.status }}">
{{ item.license.status|capitalize }}
</h3>
<span class="license-status license-status-{{ item.license.status }}">
{{ item.license.status|capitalize }}
</span>
</div>
<div class="license-details">
<div class="license-key-row">
<label>{{ __('License Key:') }}</label>
<code class="license-key" data-license-key="{{ esc_attr(item.license.licenseKey) }}">
{{ esc_html(item.license.licenseKey) }}
</code>
<button type="button" class="copy-license-btn" data-license-key="{{ esc_attr(item.license.licenseKey) }}" title="{{ __('Copy to clipboard') }}">
<span class="dashicons dashicons-clipboard"></span>
</button>
</div>
<div class="license-info-row">
<span><strong>{{ __('Domain:') }}</strong> {{ esc_html(item.license.domain) }}</span>
<span><strong>{{ __('Expires:') }}</strong>
{% if item.license.expiresAt %}
{{ item.license.expiresAt|date('Y-m-d') }}
{% else %}
{{ __('Never') }}
{% endif %}
</span>
</td>
<td data-title="{{ __('Expires') }}">
{% if item.license.expiresAt %}
{{ item.license.expiresAt|date('Y-m-d') }}
{% else %}
{{ __('Never') }}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% if item.downloads is defined and item.downloads is not empty %}
<div class="license-downloads">
<h4>{{ __('Available Downloads') }}</h4>
<ul class="download-list">
{% for download in item.downloads %}
<li>
<a href="{{ esc_url(download.download_url) }}" class="download-link">
<span class="dashicons dashicons-download"></span>
{{ esc_html(download.filename ?: 'Version ' ~ download.version) }}
</a>
<span class="download-version">v{{ esc_html(download.version) }}</span>
<span class="download-date">{{ esc_html(download.released_at) }}</span>
</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}