You've already forked wc-licensed-product
Implement versions 0.0.4-0.0.7 features
v0.0.4: - Add WooCommerce settings tab for default license settings - Per-product settings override global defaults v0.0.5: - Add bulk license operations (activate, deactivate, revoke, extend, delete) - Add license renewal/extension and lifetime functionality - Add quick action buttons per license row v0.0.6: - Add license dashboard with statistics and analytics - Add license transfer functionality (admin) - Add CSV export for licenses - Add OpenAPI 3.1 specification - Remove /deactivate API endpoint v0.0.7: - Move license dashboard to WooCommerce Reports section - Add license search and filtering in admin - Add customer-facing license transfer with AJAX modal - Add email notifications for license expiration warnings - Add bulk import licenses from CSV - Update README with comprehensive documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
176
templates/admin/dashboard.html.twig
Normal file
176
templates/admin/dashboard.html.twig
Normal file
@@ -0,0 +1,176 @@
|
||||
<div class="wrap wclp-dashboard">
|
||||
<h1>{{ __('License Dashboard') }}</h1>
|
||||
|
||||
<div class="wclp-dashboard-stats">
|
||||
<!-- Overview Cards -->
|
||||
<div class="wclp-stat-cards">
|
||||
<div class="wclp-stat-card wclp-stat-total">
|
||||
<div class="wclp-stat-icon"><span class="dashicons dashicons-admin-network"></span></div>
|
||||
<div class="wclp-stat-content">
|
||||
<span class="wclp-stat-number">{{ stats.total }}</span>
|
||||
<span class="wclp-stat-label">{{ __('Total Licenses') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wclp-stat-card wclp-stat-active">
|
||||
<div class="wclp-stat-icon"><span class="dashicons dashicons-yes-alt"></span></div>
|
||||
<div class="wclp-stat-content">
|
||||
<span class="wclp-stat-number">{{ stats.by_status.active }}</span>
|
||||
<span class="wclp-stat-label">{{ __('Active') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wclp-stat-card wclp-stat-inactive">
|
||||
<div class="wclp-stat-icon"><span class="dashicons dashicons-marker"></span></div>
|
||||
<div class="wclp-stat-content">
|
||||
<span class="wclp-stat-number">{{ stats.by_status.inactive }}</span>
|
||||
<span class="wclp-stat-label">{{ __('Inactive') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wclp-stat-card wclp-stat-expired">
|
||||
<div class="wclp-stat-icon"><span class="dashicons dashicons-calendar-alt"></span></div>
|
||||
<div class="wclp-stat-content">
|
||||
<span class="wclp-stat-number">{{ stats.by_status.expired }}</span>
|
||||
<span class="wclp-stat-label">{{ __('Expired') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wclp-stat-card wclp-stat-revoked">
|
||||
<div class="wclp-stat-icon"><span class="dashicons dashicons-dismiss"></span></div>
|
||||
<div class="wclp-stat-content">
|
||||
<span class="wclp-stat-number">{{ stats.by_status.revoked }}</span>
|
||||
<span class="wclp-stat-label">{{ __('Revoked') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alert: Expiring Soon -->
|
||||
{% if stats.expiring_soon > 0 %}
|
||||
<div class="notice notice-warning">
|
||||
<p>
|
||||
<span class="dashicons dashicons-warning"></span>
|
||||
<strong>{{ __('Attention:') }}</strong>
|
||||
{{ stats.expiring_soon }} {{ stats.expiring_soon == 1 ? __('license is') : __('licenses are') }}
|
||||
{{ __('expiring within the next 30 days.') }}
|
||||
<a href="{{ admin_url }}?page=wc-licenses">{{ __('View Licenses') }}</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Secondary Stats -->
|
||||
<div class="wclp-stat-row">
|
||||
<div class="wclp-stat-box">
|
||||
<h3>{{ __('License Types') }}</h3>
|
||||
<table class="widefat striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ __('Lifetime Licenses') }}</td>
|
||||
<td class="wclp-stat-value">{{ stats.lifetime }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ __('Time-limited Licenses') }}</td>
|
||||
<td class="wclp-stat-value">{{ stats.expiring }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ __('Expiring Soon (30 days)') }}</td>
|
||||
<td class="wclp-stat-value {% if stats.expiring_soon > 0 %}wclp-warning{% endif %}">
|
||||
{{ stats.expiring_soon }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="wclp-stat-box">
|
||||
<h3>{{ __('Top Products by Licenses') }}</h3>
|
||||
{% if stats.by_product is empty %}
|
||||
<p class="description">{{ __('No license data available yet.') }}</p>
|
||||
{% else %}
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('Product') }}</th>
|
||||
<th class="wclp-stat-value">{{ __('Licenses') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for product in stats.by_product %}
|
||||
<tr>
|
||||
<td>{{ esc_html(product.product_name) }}</td>
|
||||
<td class="wclp-stat-value">{{ product.count }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="wclp-stat-box">
|
||||
<h3>{{ __('Top Domains') }}</h3>
|
||||
{% if stats.top_domains is empty %}
|
||||
<p class="description">{{ __('No license data available yet.') }}</p>
|
||||
{% else %}
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('Domain') }}</th>
|
||||
<th class="wclp-stat-value">{{ __('Licenses') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for domain in stats.top_domains %}
|
||||
<tr>
|
||||
<td><code>{{ esc_html(domain.domain) }}</code></td>
|
||||
<td class="wclp-stat-value">{{ domain.count }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Monthly Chart -->
|
||||
<div class="wclp-stat-box wclp-stat-full">
|
||||
<h3>{{ __('Licenses Created (Last 12 Months)') }}</h3>
|
||||
{% if stats.monthly is empty %}
|
||||
<p class="description">{{ __('No license data available yet.') }}</p>
|
||||
{% else %}
|
||||
<div class="wclp-chart-container">
|
||||
<div class="wclp-bar-chart" id="wclp-monthly-chart">
|
||||
{% set max_value = 1 %}
|
||||
{% for count in stats.monthly %}
|
||||
{% if count > max_value %}
|
||||
{% set max_value = count %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for month, count in stats.monthly %}
|
||||
<div class="wclp-bar-wrapper">
|
||||
<div class="wclp-bar" style="height: {{ (count / max_value * 100)|round }}%;" title="{{ count }} {{ __('licenses') }}">
|
||||
<span class="wclp-bar-value">{{ count }}</span>
|
||||
</div>
|
||||
<span class="wclp-bar-label">{{ month|date('M Y') }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="wclp-dashboard-actions">
|
||||
<h2>{{ __('Quick Actions') }}</h2>
|
||||
<div class="wclp-action-buttons">
|
||||
<a href="{{ admin_url }}?page=wc-licenses" class="button button-primary">
|
||||
<span class="dashicons dashicons-admin-network"></span>
|
||||
{{ __('Manage Licenses') }}
|
||||
</a>
|
||||
<a href="{{ admin_url }}?page=wc-licenses&action=export_csv" class="button">
|
||||
<span class="dashicons dashicons-download"></span>
|
||||
{{ __('Export to CSV') }}
|
||||
</a>
|
||||
<a href="{{ admin_url }}?page=wc-settings&tab=licensed_product" class="button">
|
||||
<span class="dashicons dashicons-admin-generic"></span>
|
||||
{{ __('Settings') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,5 +1,14 @@
|
||||
<div class="wrap">
|
||||
<h1>{{ __('Licenses') }}</h1>
|
||||
<h1 class="wp-heading-inline">{{ __('Licenses') }}</h1>
|
||||
<a href="{{ admin_url }}?action=export_csv" class="page-title-action">
|
||||
<span class="dashicons dashicons-download" style="vertical-align: middle;"></span>
|
||||
{{ __('Export CSV') }}
|
||||
</a>
|
||||
<a href="{{ admin_url }}?action=import_csv" class="page-title-action">
|
||||
<span class="dashicons dashicons-upload" style="vertical-align: middle;"></span>
|
||||
{{ __('Import CSV') }}
|
||||
</a>
|
||||
<hr class="wp-header-end">
|
||||
|
||||
{% for notice in notices %}
|
||||
<div class="notice notice-{{ notice.type }} is-dismissible">
|
||||
@@ -7,96 +16,292 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<p class="description">
|
||||
{{ __('Total licenses:') }} <strong>{{ total_licenses }}</strong>
|
||||
</p>
|
||||
<!-- Search and Filter Form -->
|
||||
<form method="get" action="" class="wclp-filter-form">
|
||||
<input type="hidden" name="page" value="wc-licenses">
|
||||
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('License Key') }}</th>
|
||||
<th>{{ __('Product') }}</th>
|
||||
<th>{{ __('Customer') }}</th>
|
||||
<th>{{ __('Domain') }}</th>
|
||||
<th>{{ __('Status') }}</th>
|
||||
<th>{{ __('Expires') }}</th>
|
||||
<th>{{ __('Actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if licenses is empty %}
|
||||
<tr>
|
||||
<td colspan="7">{{ __('No licenses found.') }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
{% for item in licenses %}
|
||||
<tr>
|
||||
<td><code>{{ item.license.licenseKey }}</code></td>
|
||||
<td>
|
||||
{% if item.product_edit_url %}
|
||||
<a href="{{ esc_url(item.product_edit_url) }}">{{ esc_html(item.product_name) }}</a>
|
||||
{% else %}
|
||||
{{ esc_html(item.product_name) }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ esc_html(item.customer_name) }}
|
||||
{% if item.customer_email %}
|
||||
<br><small>{{ esc_html(item.customer_email) }}</small>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ esc_html(item.license.domain) }}</td>
|
||||
<td>
|
||||
<span class="license-status license-status-{{ item.license.status }}">
|
||||
{{ item.license.status|capitalize }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{% if item.license.expiresAt %}
|
||||
{{ item.license.expiresAt|date('Y-m-d') }}
|
||||
{% else %}
|
||||
{{ __('Never') }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if item.license.status != 'revoked' %}
|
||||
<a href="{{ admin_url ~ '?page=wc-licenses&action=revoke&license_id=' ~ item.license.id ~ '&_wpnonce=' }}"
|
||||
class="button button-small"
|
||||
onclick="return confirm('{{ __('Are you sure?') }}')">
|
||||
{{ __('Revoke') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{{ admin_url ~ '?page=wc-licenses&action=delete&license_id=' ~ item.license.id ~ '&_wpnonce=' }}"
|
||||
class="button button-small button-link-delete"
|
||||
onclick="return confirm('{{ __('Are you sure you want to delete this license?') }}')">
|
||||
{{ __('Delete') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="search-box">
|
||||
<label class="screen-reader-text" for="license-search-input">{{ __('Search Licenses') }}</label>
|
||||
<input type="search" id="license-search-input" name="s" value="{{ filters.search|default('') }}"
|
||||
placeholder="{{ __('Search license key or domain...') }}">
|
||||
<input type="submit" id="search-submit" class="button" value="{{ __('Search') }}">
|
||||
</p>
|
||||
|
||||
<div class="tablenav top">
|
||||
<div class="alignleft actions">
|
||||
<select name="status">
|
||||
<option value="all">{{ __('All Statuses') }}</option>
|
||||
<option value="active" {{ filters.status|default('') == 'active' ? 'selected' : '' }}>{{ __('Active') }}</option>
|
||||
<option value="inactive" {{ filters.status|default('') == 'inactive' ? 'selected' : '' }}>{{ __('Inactive') }}</option>
|
||||
<option value="expired" {{ filters.status|default('') == 'expired' ? 'selected' : '' }}>{{ __('Expired') }}</option>
|
||||
<option value="revoked" {{ filters.status|default('') == 'revoked' ? 'selected' : '' }}>{{ __('Revoked') }}</option>
|
||||
</select>
|
||||
|
||||
<select name="product_id">
|
||||
<option value="">{{ __('All Products') }}</option>
|
||||
{% for id, name in products %}
|
||||
<option value="{{ id }}" {{ filters.product_id|default('') == id ? 'selected' : '' }}>{{ esc_html(name) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<input type="submit" class="button" value="{{ __('Filter') }}">
|
||||
|
||||
{% if filters is not empty %}
|
||||
<a href="{{ admin_url }}" class="button">{{ __('Clear') }}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if total_pages > 1 %}
|
||||
<div class="tablenav bottom">
|
||||
<div class="tablenav-pages">
|
||||
<span class="pagination-links">
|
||||
{% if current_page > 1 %}
|
||||
<a class="prev-page button" href="{{ admin_url ~ '&paged=' ~ (current_page - 1) }}">
|
||||
<span aria-hidden="true">‹</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<span class="paging-input">
|
||||
{{ current_page }} {{ __('of') }} {{ total_pages }}
|
||||
</span>
|
||||
{% if current_page < total_pages %}
|
||||
<a class="next-page button" href="{{ admin_url ~ '&paged=' ~ (current_page + 1) }}">
|
||||
<span aria-hidden="true">›</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
<span class="displaying-num">{{ total_licenses }} {{ total_licenses == 1 ? __('item') : __('items') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
<p class="description">
|
||||
{{ __('Showing') }} {{ total_licenses }} {{ total_licenses == 1 ? __('license') : __('licenses') }}
|
||||
{% if filters is not empty %}
|
||||
({{ __('filtered') }})
|
||||
{% endif %}
|
||||
| <a href="{{ constant('admin_url')('admin.php?page=wc-reports&tab=licenses') }}">{{ __('View Dashboard') }}</a>
|
||||
</p>
|
||||
|
||||
<form method="post" action="{{ admin_url }}" id="licenses-bulk-form">
|
||||
{{ wp_nonce_field('bulk_license_action', '_wpnonce', true, false)|raw }}
|
||||
|
||||
<div class="tablenav top">
|
||||
<div class="alignleft actions bulkactions">
|
||||
<select name="bulk_action" id="bulk-action-selector">
|
||||
<option value="">{{ __('Bulk Actions') }}</option>
|
||||
<option value="activate">{{ __('Activate') }}</option>
|
||||
<option value="deactivate">{{ __('Deactivate') }}</option>
|
||||
<option value="revoke">{{ __('Revoke') }}</option>
|
||||
<option value="extend_30">{{ __('Extend 30 days') }}</option>
|
||||
<option value="extend_90">{{ __('Extend 90 days') }}</option>
|
||||
<option value="extend_365">{{ __('Extend 1 year') }}</option>
|
||||
<option value="delete">{{ __('Delete') }}</option>
|
||||
</select>
|
||||
<input type="submit" class="button action" value="{{ __('Apply') }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="wp-list-table widefat fixed striped licenses-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="manage-column column-cb check-column">
|
||||
<input type="checkbox" id="cb-select-all-1">
|
||||
</td>
|
||||
<th>{{ __('License Key') }}</th>
|
||||
<th>{{ __('Product') }}</th>
|
||||
<th>{{ __('Customer') }}</th>
|
||||
<th>{{ __('Domain') }}</th>
|
||||
<th>{{ __('Status') }}</th>
|
||||
<th>{{ __('Expires') }}</th>
|
||||
<th>{{ __('Actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if licenses is empty %}
|
||||
<tr>
|
||||
<td colspan="8">{{ __('No licenses found.') }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
{% for item in licenses %}
|
||||
<tr>
|
||||
<th scope="row" class="check-column">
|
||||
<input type="checkbox" name="license_ids[]" value="{{ item.license.id }}">
|
||||
</th>
|
||||
<td><code>{{ item.license.licenseKey }}</code></td>
|
||||
<td>
|
||||
{% if item.product_edit_url %}
|
||||
<a href="{{ esc_url(item.product_edit_url) }}">{{ esc_html(item.product_name) }}</a>
|
||||
{% else %}
|
||||
{{ esc_html(item.product_name) }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ esc_html(item.customer_name) }}
|
||||
{% if item.customer_email %}
|
||||
<br><small>{{ esc_html(item.customer_email) }}</small>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ esc_html(item.license.domain) }}</td>
|
||||
<td>
|
||||
<span class="license-status license-status-{{ item.license.status }}">
|
||||
{{ item.license.status|capitalize }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{% if item.license.expiresAt %}
|
||||
{{ item.license.expiresAt|date('Y-m-d') }}
|
||||
{% else %}
|
||||
<span class="license-lifetime">{{ __('Lifetime') }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="license-actions">
|
||||
<div class="row-actions">
|
||||
{% if item.license.status != 'revoked' %}
|
||||
<span class="transfer">
|
||||
<a href="#" class="wclp-transfer-link"
|
||||
data-license-id="{{ item.license.id }}"
|
||||
data-current-domain="{{ esc_attr(item.license.domain) }}"
|
||||
title="{{ __('Transfer to new domain') }}">{{ __('Transfer') }}</a> |
|
||||
</span>
|
||||
<span class="extend">
|
||||
<a href="{{ extend_url(item.license.id, 30) }}" title="{{ __('Extend by 30 days') }}">+30d</a> |
|
||||
</span>
|
||||
<span class="lifetime">
|
||||
<a href="{{ lifetime_url(item.license.id) }}" title="{{ __('Set to lifetime') }}">∞</a> |
|
||||
</span>
|
||||
<span class="revoke">
|
||||
<a href="{{ revoke_url(item.license.id) }}"
|
||||
onclick="return confirm('{{ __('Are you sure?') }}')">{{ __('Revoke') }}</a> |
|
||||
</span>
|
||||
{% endif %}
|
||||
<span class="delete">
|
||||
<a href="{{ delete_url(item.license.id) }}"
|
||||
class="submitdelete"
|
||||
onclick="return confirm('{{ __('Are you sure you want to delete this license?') }}')">{{ __('Delete') }}</a>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td class="manage-column column-cb check-column">
|
||||
<input type="checkbox" id="cb-select-all-2">
|
||||
</td>
|
||||
<th>{{ __('License Key') }}</th>
|
||||
<th>{{ __('Product') }}</th>
|
||||
<th>{{ __('Customer') }}</th>
|
||||
<th>{{ __('Domain') }}</th>
|
||||
<th>{{ __('Status') }}</th>
|
||||
<th>{{ __('Expires') }}</th>
|
||||
<th>{{ __('Actions') }}</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
<div class="tablenav bottom">
|
||||
<div class="alignleft actions bulkactions">
|
||||
<select name="bulk_action_2" id="bulk-action-selector-bottom">
|
||||
<option value="">{{ __('Bulk Actions') }}</option>
|
||||
<option value="activate">{{ __('Activate') }}</option>
|
||||
<option value="deactivate">{{ __('Deactivate') }}</option>
|
||||
<option value="revoke">{{ __('Revoke') }}</option>
|
||||
<option value="extend_30">{{ __('Extend 30 days') }}</option>
|
||||
<option value="extend_90">{{ __('Extend 90 days') }}</option>
|
||||
<option value="extend_365">{{ __('Extend 1 year') }}</option>
|
||||
<option value="delete">{{ __('Delete') }}</option>
|
||||
</select>
|
||||
<input type="submit" class="button action" value="{{ __('Apply') }}">
|
||||
</div>
|
||||
{% if total_pages > 1 %}
|
||||
{% set filter_params = '' %}
|
||||
{% if filters.search is defined and filters.search %}{% set filter_params = filter_params ~ '&s=' ~ filters.search %}{% endif %}
|
||||
{% if filters.status is defined and filters.status %}{% set filter_params = filter_params ~ '&status=' ~ filters.status %}{% endif %}
|
||||
{% if filters.product_id is defined and filters.product_id %}{% set filter_params = filter_params ~ '&product_id=' ~ filters.product_id %}{% endif %}
|
||||
|
||||
<div class="tablenav-pages">
|
||||
<span class="pagination-links">
|
||||
{% if current_page > 1 %}
|
||||
<a class="prev-page button" href="{{ admin_url ~ '&paged=' ~ (current_page - 1) ~ filter_params }}">
|
||||
<span aria-hidden="true">‹</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<span class="paging-input">
|
||||
{{ current_page }} {{ __('of') }} {{ total_pages }}
|
||||
</span>
|
||||
{% if current_page < total_pages %}
|
||||
<a class="next-page button" href="{{ admin_url ~ '&paged=' ~ (current_page + 1) ~ filter_params }}">
|
||||
<span aria-hidden="true">›</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Transfer Modal -->
|
||||
<div id="wclp-transfer-modal" class="wclp-modal" style="display:none;">
|
||||
<div class="wclp-modal-content">
|
||||
<span class="wclp-modal-close">×</span>
|
||||
<h2>{{ __('Transfer License to New Domain') }}</h2>
|
||||
<form method="post" action="{{ admin_url }}">
|
||||
<input type="hidden" name="action" value="transfer_license">
|
||||
<input type="hidden" name="_wpnonce" value="{{ transfer_nonce() }}">
|
||||
<input type="hidden" name="license_id" id="transfer-license-id" value="">
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row"><label>{{ __('Current Domain') }}</label></th>
|
||||
<td><code id="transfer-current-domain"></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="new_domain">{{ __('New Domain') }}</label></th>
|
||||
<td>
|
||||
<input type="text" name="new_domain" id="transfer-new-domain" class="regular-text"
|
||||
placeholder="example.com" required>
|
||||
<p class="description">{{ __('Enter the new domain without http:// or www.') }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p class="submit">
|
||||
<button type="submit" class="button button-primary">{{ __('Transfer License') }}</button>
|
||||
<button type="button" class="button wclp-modal-cancel">{{ __('Cancel') }}</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function($) {
|
||||
// Select all checkboxes
|
||||
$('#cb-select-all-1, #cb-select-all-2').on('change', function() {
|
||||
$('input[name="license_ids[]"]').prop('checked', this.checked);
|
||||
$('#cb-select-all-1, #cb-select-all-2').prop('checked', this.checked);
|
||||
});
|
||||
|
||||
// Sync bulk action selects
|
||||
$('#bulk-action-selector, #bulk-action-selector-bottom').on('change', function() {
|
||||
var value = $(this).val();
|
||||
$('#bulk-action-selector, #bulk-action-selector-bottom').val(value);
|
||||
});
|
||||
|
||||
// Use bottom select value if top is empty
|
||||
$('form').on('submit', function() {
|
||||
var topAction = $('#bulk-action-selector').val();
|
||||
var bottomAction = $('#bulk-action-selector-bottom').val();
|
||||
if (!topAction && bottomAction) {
|
||||
$('#bulk-action-selector').val(bottomAction);
|
||||
}
|
||||
});
|
||||
|
||||
// Transfer modal
|
||||
var $modal = $('#wclp-transfer-modal');
|
||||
|
||||
$('.wclp-transfer-link').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var licenseId = $(this).data('license-id');
|
||||
var currentDomain = $(this).data('current-domain');
|
||||
|
||||
$('#transfer-license-id').val(licenseId);
|
||||
$('#transfer-current-domain').text(currentDomain);
|
||||
$('#transfer-new-domain').val('');
|
||||
$modal.show();
|
||||
});
|
||||
|
||||
$('.wclp-modal-close, .wclp-modal-cancel').on('click', function() {
|
||||
$modal.hide();
|
||||
});
|
||||
|
||||
$(window).on('click', function(e) {
|
||||
if ($(e.target).is($modal)) {
|
||||
$modal.hide();
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
@@ -29,7 +29,19 @@
|
||||
</div>
|
||||
|
||||
<div class="license-info-row">
|
||||
<span><strong>{{ __('Domain:') }}</strong> {{ esc_html(item.license.domain) }}</span>
|
||||
<span class="license-domain-display" data-license-id="{{ item.license.id }}">
|
||||
<strong>{{ __('Domain:') }}</strong>
|
||||
<span class="domain-value">{{ esc_html(item.license.domain) }}</span>
|
||||
{% if item.license.status == 'active' or item.license.status == 'inactive' %}
|
||||
<button type="button" class="wclp-transfer-btn"
|
||||
data-license-id="{{ item.license.id }}"
|
||||
data-current-domain="{{ esc_attr(item.license.domain) }}"
|
||||
title="{{ __('Transfer to new domain') }}">
|
||||
<span class="dashicons dashicons-randomize"></span>
|
||||
{{ __('Transfer') }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</span>
|
||||
<span><strong>{{ __('Expires:') }}</strong>
|
||||
{% if item.license.expiresAt %}
|
||||
{{ item.license.expiresAt|date('Y-m-d') }}
|
||||
@@ -60,4 +72,38 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Transfer Modal -->
|
||||
<div id="wclp-transfer-modal" class="wclp-modal" style="display:none;">
|
||||
<div class="wclp-modal-overlay"></div>
|
||||
<div class="wclp-modal-content">
|
||||
<button type="button" class="wclp-modal-close" aria-label="{{ __('Close') }}">×</button>
|
||||
<h3>{{ __('Transfer License to New Domain') }}</h3>
|
||||
<form id="wclp-transfer-form">
|
||||
<input type="hidden" name="license_id" id="transfer-license-id" value="">
|
||||
|
||||
<div class="wclp-form-row">
|
||||
<label>{{ __('Current Domain') }}</label>
|
||||
<p class="wclp-current-domain"><code id="transfer-current-domain"></code></p>
|
||||
</div>
|
||||
|
||||
<div class="wclp-form-row">
|
||||
<label for="transfer-new-domain">{{ __('New Domain') }}</label>
|
||||
<input type="text" name="new_domain" id="transfer-new-domain"
|
||||
placeholder="example.com" required
|
||||
pattern="[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)+">
|
||||
<p class="wclp-field-description">{{ __('Enter the new domain without http:// or www.') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="wclp-form-row wclp-form-actions">
|
||||
<button type="submit" class="button wclp-btn-primary" id="wclp-transfer-submit">
|
||||
{{ __('Transfer License') }}
|
||||
</button>
|
||||
<button type="button" class="button wclp-modal-cancel">{{ __('Cancel') }}</button>
|
||||
</div>
|
||||
|
||||
<div id="wclp-transfer-message" class="wclp-message" style="display:none;"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user