You've already forked wc-licensed-product
Add license test action to admin overview
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>
This commit is contained in:
@@ -61,6 +61,9 @@ final class AdminController
|
|||||||
add_action('wp_ajax_wclp_update_license_expiry', [$this, 'handleAjaxExpiryUpdate']);
|
add_action('wp_ajax_wclp_update_license_expiry', [$this, 'handleAjaxExpiryUpdate']);
|
||||||
add_action('wp_ajax_wclp_update_license_domain', [$this, 'handleAjaxDomainUpdate']);
|
add_action('wp_ajax_wclp_update_license_domain', [$this, 'handleAjaxDomainUpdate']);
|
||||||
add_action('wp_ajax_wclp_revoke_license', [$this, 'handleAjaxRevoke']);
|
add_action('wp_ajax_wclp_revoke_license', [$this, 'handleAjaxRevoke']);
|
||||||
|
|
||||||
|
// AJAX handler for license testing
|
||||||
|
add_action('wp_ajax_wclp_test_license', [$this, 'handleAjaxTestLicense']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -355,6 +358,30 @@ final class AdminController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle AJAX license test - validates license against the API
|
||||||
|
*/
|
||||||
|
public function handleAjaxTestLicense(): void
|
||||||
|
{
|
||||||
|
check_ajax_referer('wclp_inline_edit', 'nonce');
|
||||||
|
|
||||||
|
if (!current_user_can('manage_woocommerce')) {
|
||||||
|
wp_send_json_error(['message' => __('Permission denied.', 'wc-licensed-product')], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$licenseKey = isset($_POST['license_key']) ? sanitize_text_field(wp_unslash($_POST['license_key'])) : '';
|
||||||
|
$domain = isset($_POST['domain']) ? sanitize_text_field(wp_unslash($_POST['domain'])) : '';
|
||||||
|
|
||||||
|
if (empty($licenseKey) || empty($domain)) {
|
||||||
|
wp_send_json_error(['message' => __('License key and domain are required.', 'wc-licensed-product')]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the license using LicenseManager
|
||||||
|
$result = $this->licenseManager->validateLicense($licenseKey, $domain);
|
||||||
|
|
||||||
|
wp_send_json_success($result);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle admin actions (update, delete licenses)
|
* Handle admin actions (update, delete licenses)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -184,6 +184,13 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="license-actions">
|
<td class="license-actions">
|
||||||
<div class="row-actions">
|
<div class="row-actions">
|
||||||
|
<span class="test">
|
||||||
|
<a href="#" class="wclp-test-license-link"
|
||||||
|
data-license-id="{{ item.license.id }}"
|
||||||
|
data-license-key="{{ esc_attr(item.license.licenseKey) }}"
|
||||||
|
data-domain="{{ esc_attr(item.license.domain) }}"
|
||||||
|
title="{{ __('Test license against API') }}">{{ __('Test') }}</a> |
|
||||||
|
</span>
|
||||||
{% if item.license.status != 'revoked' %}
|
{% if item.license.status != 'revoked' %}
|
||||||
<span class="transfer">
|
<span class="transfer">
|
||||||
<a href="#" class="wclp-transfer-link"
|
<a href="#" class="wclp-transfer-link"
|
||||||
@@ -272,6 +279,36 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Test License Modal -->
|
||||||
|
<div id="wclp-test-modal" class="wclp-modal" style="display:none;">
|
||||||
|
<div class="wclp-modal-content">
|
||||||
|
<span class="wclp-modal-close">×</span>
|
||||||
|
<h2>{{ __('License Validation Test') }}</h2>
|
||||||
|
<div class="wclp-test-info">
|
||||||
|
<table class="form-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{{ __('License Key') }}</th>
|
||||||
|
<td><code id="test-license-key"></code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{{ __('Domain') }}</th>
|
||||||
|
<td><code id="test-domain"></code></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div id="wclp-test-loading" style="display:none; text-align:center; padding:20px;">
|
||||||
|
<span class="spinner is-active" style="float:none;"></span>
|
||||||
|
<p>{{ __('Testing license...') }}</p>
|
||||||
|
</div>
|
||||||
|
<div id="wclp-test-result" style="display:none;">
|
||||||
|
<div id="wclp-test-result-content"></div>
|
||||||
|
</div>
|
||||||
|
<p class="submit">
|
||||||
|
<button type="button" class="button wclp-modal-cancel">{{ __('Close') }}</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Transfer Modal -->
|
<!-- Transfer Modal -->
|
||||||
<div id="wclp-transfer-modal" class="wclp-modal" style="display:none;">
|
<div id="wclp-transfer-modal" class="wclp-modal" style="display:none;">
|
||||||
<div class="wclp-modal-content">
|
<div class="wclp-modal-content">
|
||||||
@@ -349,5 +386,91 @@
|
|||||||
$modal.hide();
|
$modal.hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Test License modal
|
||||||
|
var $testModal = $('#wclp-test-modal');
|
||||||
|
var $testLoading = $('#wclp-test-loading');
|
||||||
|
var $testResult = $('#wclp-test-result');
|
||||||
|
var $testResultContent = $('#wclp-test-result-content');
|
||||||
|
|
||||||
|
$('.wclp-test-license-link').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var licenseKey = $(this).data('license-key');
|
||||||
|
var domain = $(this).data('domain');
|
||||||
|
|
||||||
|
// Show modal with info
|
||||||
|
$('#test-license-key').text(licenseKey);
|
||||||
|
$('#test-domain').text(domain);
|
||||||
|
$testLoading.show();
|
||||||
|
$testResult.hide();
|
||||||
|
$testModal.show();
|
||||||
|
|
||||||
|
// Call the test endpoint
|
||||||
|
$.ajax({
|
||||||
|
url: wclpAdmin.ajaxUrl,
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
action: 'wclp_test_license',
|
||||||
|
nonce: wclpAdmin.editNonce,
|
||||||
|
license_key: licenseKey,
|
||||||
|
domain: domain
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
$testLoading.hide();
|
||||||
|
if (response.success) {
|
||||||
|
var result = response.data;
|
||||||
|
var html = '';
|
||||||
|
|
||||||
|
if (result.valid) {
|
||||||
|
html = '<div class="notice notice-success inline"><p><strong>✓ {{ __('License is VALID') }}</strong></p></div>';
|
||||||
|
html += '<table class="widefat striped"><tbody>';
|
||||||
|
html += '<tr><th>{{ __('Product') }}</th><td>' + escapeHtml(result.product_name || '-') + '</td></tr>';
|
||||||
|
html += '<tr><th>{{ __('Version') }}</th><td>' + escapeHtml(result.version || '-') + '</td></tr>';
|
||||||
|
if (result.expires_at) {
|
||||||
|
html += '<tr><th>{{ __('Expires') }}</th><td>' + escapeHtml(result.expires_at) + '</td></tr>';
|
||||||
|
} else {
|
||||||
|
html += '<tr><th>{{ __('Expires') }}</th><td>{{ __('Lifetime') }}</td></tr>';
|
||||||
|
}
|
||||||
|
html += '</tbody></table>';
|
||||||
|
} else {
|
||||||
|
html = '<div class="notice notice-error inline"><p><strong>✗ {{ __('License is INVALID') }}</strong></p></div>';
|
||||||
|
html += '<table class="widefat striped"><tbody>';
|
||||||
|
html += '<tr><th>{{ __('Error Code') }}</th><td><code>' + escapeHtml(result.error || 'unknown') + '</code></td></tr>';
|
||||||
|
html += '<tr><th>{{ __('Message') }}</th><td>' + escapeHtml(result.message || '-') + '</td></tr>';
|
||||||
|
html += '</tbody></table>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$testResultContent.html(html);
|
||||||
|
$testResult.show();
|
||||||
|
} else {
|
||||||
|
$testResultContent.html('<div class="notice notice-error inline"><p>' + escapeHtml(response.data.message || 'Error') + '</p></div>');
|
||||||
|
$testResult.show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
$testLoading.hide();
|
||||||
|
$testResultContent.html('<div class="notice notice-error inline"><p>{{ __('Failed to test license. Please try again.') }}</p></div>');
|
||||||
|
$testResult.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close test modal
|
||||||
|
$testModal.find('.wclp-modal-close, .wclp-modal-cancel').on('click', function() {
|
||||||
|
$testModal.hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(window).on('click', function(e) {
|
||||||
|
if ($(e.target).is($testModal)) {
|
||||||
|
$testModal.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function escapeHtml(text) {
|
||||||
|
if (!text) return '';
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.textContent = text;
|
||||||
|
return div.innerHTML;
|
||||||
|
}
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user