You've already forked wc-licensed-product
Implement version 0.0.11 features
- 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>
This commit is contained in:
@@ -1253,6 +1253,7 @@ final class AdminController
|
||||
<th><?php esc_html_e('Customer', 'wc-licensed-product'); ?></th>
|
||||
<th><?php esc_html_e('Domain', 'wc-licensed-product'); ?></th>
|
||||
<th><?php esc_html_e('Status', 'wc-licensed-product'); ?></th>
|
||||
<th><?php esc_html_e('Created', 'wc-licensed-product'); ?></th>
|
||||
<th><?php esc_html_e('Expires', 'wc-licensed-product'); ?></th>
|
||||
<th><?php esc_html_e('Actions', 'wc-licensed-product'); ?></th>
|
||||
</tr>
|
||||
@@ -1260,7 +1261,7 @@ final class AdminController
|
||||
<tbody>
|
||||
<?php if (empty($enrichedLicenses)): ?>
|
||||
<tr>
|
||||
<td colspan="8"><?php esc_html_e('No licenses found.', 'wc-licensed-product'); ?></td>
|
||||
<td colspan="9"><?php esc_html_e('No licenses found.', 'wc-licensed-product'); ?></td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($enrichedLicenses as $item): ?>
|
||||
@@ -1320,6 +1321,9 @@ final class AdminController
|
||||
<button type="button" class="wclp-cancel-btn button button-small"><?php esc_html_e('Cancel', 'wc-licensed-product'); ?></button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="wclp-created-cell">
|
||||
<?php echo esc_html($item['license']->getCreatedAt()->format(get_option('date_format'))); ?>
|
||||
</td>
|
||||
<td class="wclp-editable-cell" data-field="expiry" data-license-id="<?php echo esc_attr($item['license']->getId()); ?>">
|
||||
<?php $expiresAt = $item['license']->getExpiresAt(); ?>
|
||||
<span class="wclp-display-value">
|
||||
@@ -1387,6 +1391,7 @@ final class AdminController
|
||||
<th><?php esc_html_e('Customer', 'wc-licensed-product'); ?></th>
|
||||
<th><?php esc_html_e('Domain', 'wc-licensed-product'); ?></th>
|
||||
<th><?php esc_html_e('Status', 'wc-licensed-product'); ?></th>
|
||||
<th><?php esc_html_e('Created', 'wc-licensed-product'); ?></th>
|
||||
<th><?php esc_html_e('Expires', 'wc-licensed-product'); ?></th>
|
||||
<th><?php esc_html_e('Actions', 'wc-licensed-product'); ?></th>
|
||||
</tr>
|
||||
|
||||
523
src/Admin/AnalyticsController.php
Normal file
523
src/Admin/AnalyticsController.php
Normal file
@@ -0,0 +1,523 @@
|
||||
<?php
|
||||
/**
|
||||
* WooCommerce Analytics Integration Controller
|
||||
*
|
||||
* @package Jeremias\WcLicensedProduct\Admin
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jeremias\WcLicensedProduct\Admin;
|
||||
|
||||
use Jeremias\WcLicensedProduct\License\LicenseManager;
|
||||
|
||||
/**
|
||||
* Integrates license statistics with WooCommerce Analytics
|
||||
*/
|
||||
class AnalyticsController
|
||||
{
|
||||
private LicenseManager $licenseManager;
|
||||
|
||||
public function __construct(LicenseManager $licenseManager)
|
||||
{
|
||||
$this->licenseManager = $licenseManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize analytics hooks
|
||||
*/
|
||||
public function init(): void
|
||||
{
|
||||
// Add submenu under WooCommerce Analytics
|
||||
add_action('admin_menu', [$this, 'addAnalyticsSubmenu'], 99);
|
||||
|
||||
// Register REST API endpoints for analytics data
|
||||
add_action('rest_api_init', [$this, 'registerRestRoutes']);
|
||||
|
||||
// Add license stats to WooCommerce Admin data registry
|
||||
add_action('admin_enqueue_scripts', [$this, 'enqueueAnalyticsData']);
|
||||
|
||||
// Add analytics navigation item (WC Admin)
|
||||
add_filter('woocommerce_navigation_menu_items', [$this, 'addNavigationItem']);
|
||||
|
||||
// Register WooCommerce Analytics report page
|
||||
add_filter('woocommerce_analytics_report_menu_items', [$this, 'addAnalyticsReportMenuItem']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add submenu page under WooCommerce menu
|
||||
*/
|
||||
public function addAnalyticsSubmenu(): void
|
||||
{
|
||||
add_submenu_page(
|
||||
'woocommerce',
|
||||
__('License Statistics', 'wc-licensed-product'),
|
||||
__('License Statistics', 'wc-licensed-product'),
|
||||
'manage_woocommerce',
|
||||
'wc-license-statistics',
|
||||
[$this, 'renderStatisticsPage']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add navigation item for WC Admin navigation
|
||||
*/
|
||||
public function addNavigationItem(array $items): array
|
||||
{
|
||||
$items[] = [
|
||||
'id' => 'wc-license-statistics',
|
||||
'title' => __('License Statistics', 'wc-licensed-product'),
|
||||
'parent' => 'woocommerce-analytics',
|
||||
'path' => '/analytics/license-statistics',
|
||||
];
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add report menu item to WooCommerce Analytics
|
||||
*/
|
||||
public function addAnalyticsReportMenuItem(array $report_pages): array
|
||||
{
|
||||
$report_pages[] = [
|
||||
'id' => 'wc-license-statistics',
|
||||
'title' => __('License Statistics', 'wc-licensed-product'),
|
||||
'parent' => 'woocommerce-analytics',
|
||||
'path' => '/analytics/license-statistics',
|
||||
];
|
||||
|
||||
return $report_pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register REST API routes for analytics data
|
||||
*/
|
||||
public function registerRestRoutes(): void
|
||||
{
|
||||
register_rest_route('wc-licensed-product/v1', '/analytics/stats', [
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'callback' => [$this, 'getAnalyticsStats'],
|
||||
'permission_callback' => function () {
|
||||
return current_user_can('manage_woocommerce');
|
||||
},
|
||||
'args' => [
|
||||
'after' => [
|
||||
'description' => __('Limit response to stats after a given date.', 'wc-licensed-product'),
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
],
|
||||
'before' => [
|
||||
'description' => __('Limit response to stats before a given date.', 'wc-licensed-product'),
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
],
|
||||
'interval' => [
|
||||
'description' => __('Time interval to aggregate stats.', 'wc-licensed-product'),
|
||||
'type' => 'string',
|
||||
'enum' => ['day', 'week', 'month', 'quarter', 'year'],
|
||||
'default' => 'month',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
register_rest_route('wc-licensed-product/v1', '/analytics/products', [
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'callback' => [$this, 'getProductStats'],
|
||||
'permission_callback' => function () {
|
||||
return current_user_can('manage_woocommerce');
|
||||
},
|
||||
'args' => [
|
||||
'per_page' => [
|
||||
'description' => __('Maximum number of items to return.', 'wc-licensed-product'),
|
||||
'type' => 'integer',
|
||||
'default' => 10,
|
||||
],
|
||||
'orderby' => [
|
||||
'description' => __('Sort by this field.', 'wc-licensed-product'),
|
||||
'type' => 'string',
|
||||
'enum' => ['licenses_count', 'product_name'],
|
||||
'default' => 'licenses_count',
|
||||
],
|
||||
'order' => [
|
||||
'description' => __('Order direction.', 'wc-licensed-product'),
|
||||
'type' => 'string',
|
||||
'enum' => ['asc', 'desc'],
|
||||
'default' => 'desc',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get analytics stats via REST API
|
||||
*/
|
||||
public function getAnalyticsStats(\WP_REST_Request $request): \WP_REST_Response
|
||||
{
|
||||
$stats = $this->licenseManager->getStatistics();
|
||||
$interval = $request->get_param('interval') ?: 'month';
|
||||
|
||||
// Get time-series data based on interval
|
||||
$timeSeriesData = $this->getTimeSeriesData($interval, $request->get_param('after'), $request->get_param('before'));
|
||||
|
||||
return new \WP_REST_Response([
|
||||
'totals' => [
|
||||
'total_licenses' => $stats['total'],
|
||||
'active_licenses' => $stats['by_status']['active'] ?? 0,
|
||||
'inactive_licenses' => $stats['by_status']['inactive'] ?? 0,
|
||||
'expired_licenses' => $stats['by_status']['expired'] ?? 0,
|
||||
'revoked_licenses' => $stats['by_status']['revoked'] ?? 0,
|
||||
'lifetime_licenses' => $stats['lifetime'] ?? 0,
|
||||
'expiring_soon' => $stats['expiring_soon'] ?? 0,
|
||||
],
|
||||
'intervals' => $timeSeriesData,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product statistics via REST API
|
||||
*/
|
||||
public function getProductStats(\WP_REST_Request $request): \WP_REST_Response
|
||||
{
|
||||
$stats = $this->licenseManager->getStatistics();
|
||||
$perPage = $request->get_param('per_page') ?: 10;
|
||||
|
||||
$productStats = array_slice($stats['by_product'] ?? [], 0, $perPage);
|
||||
|
||||
return new \WP_REST_Response([
|
||||
'products' => $productStats,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get time-series data for the specified interval
|
||||
*/
|
||||
private function getTimeSeriesData(string $interval, ?string $after = null, ?string $before = null): array
|
||||
{
|
||||
global $wpdb;
|
||||
|
||||
$tableName = $wpdb->prefix . 'wc_licensed_product_licenses';
|
||||
|
||||
// Set default date range
|
||||
$endDate = $before ? new \DateTimeImmutable($before) : new \DateTimeImmutable();
|
||||
$startDate = $after ? new \DateTimeImmutable($after) : $endDate->modify('-12 months');
|
||||
|
||||
// Build date format based on interval
|
||||
switch ($interval) {
|
||||
case 'day':
|
||||
$dateFormat = '%Y-%m-%d';
|
||||
$phpFormat = 'Y-m-d';
|
||||
break;
|
||||
case 'week':
|
||||
$dateFormat = '%Y-%u';
|
||||
$phpFormat = 'Y-W';
|
||||
break;
|
||||
case 'quarter':
|
||||
$dateFormat = "CONCAT(YEAR(created_at), '-Q', QUARTER(created_at))";
|
||||
$phpFormat = 'Y-\QQ';
|
||||
break;
|
||||
case 'year':
|
||||
$dateFormat = '%Y';
|
||||
$phpFormat = 'Y';
|
||||
break;
|
||||
case 'month':
|
||||
default:
|
||||
$dateFormat = '%Y-%m';
|
||||
$phpFormat = 'Y-m';
|
||||
break;
|
||||
}
|
||||
|
||||
// Special handling for quarter since it's not a simple DATE_FORMAT
|
||||
if ($interval === 'quarter') {
|
||||
$sql = $wpdb->prepare(
|
||||
"SELECT {$dateFormat} as period, COUNT(*) as count
|
||||
FROM {$tableName}
|
||||
WHERE created_at >= %s AND created_at <= %s
|
||||
GROUP BY period
|
||||
ORDER BY period ASC",
|
||||
$startDate->format('Y-m-d 00:00:00'),
|
||||
$endDate->format('Y-m-d 23:59:59')
|
||||
);
|
||||
} else {
|
||||
$sql = $wpdb->prepare(
|
||||
"SELECT DATE_FORMAT(created_at, %s) as period, COUNT(*) as count
|
||||
FROM {$tableName}
|
||||
WHERE created_at >= %s AND created_at <= %s
|
||||
GROUP BY period
|
||||
ORDER BY period ASC",
|
||||
$dateFormat,
|
||||
$startDate->format('Y-m-d 00:00:00'),
|
||||
$endDate->format('Y-m-d 23:59:59')
|
||||
);
|
||||
}
|
||||
|
||||
$results = $wpdb->get_results($sql, ARRAY_A);
|
||||
|
||||
$data = [];
|
||||
foreach ($results as $row) {
|
||||
$data[] = [
|
||||
'interval' => $row['period'],
|
||||
'subtotals' => [
|
||||
'licenses_count' => (int) $row['count'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue license analytics data for WC Admin
|
||||
*/
|
||||
public function enqueueAnalyticsData(): void
|
||||
{
|
||||
if (!function_exists('wc_admin_get_feature_config')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
if (!$screen || strpos($screen->id, 'woocommerce') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stats = $this->licenseManager->getStatistics();
|
||||
|
||||
wp_localize_script('wc-admin-app', 'wcLicenseStats', [
|
||||
'total' => $stats['total'],
|
||||
'active' => $stats['by_status']['active'] ?? 0,
|
||||
'inactive' => $stats['by_status']['inactive'] ?? 0,
|
||||
'expired' => $stats['by_status']['expired'] ?? 0,
|
||||
'revoked' => $stats['by_status']['revoked'] ?? 0,
|
||||
'lifetime' => $stats['lifetime'] ?? 0,
|
||||
'expiringSoon' => $stats['expiring_soon'] ?? 0,
|
||||
'endpoints' => [
|
||||
'stats' => rest_url('wc-licensed-product/v1/analytics/stats'),
|
||||
'products' => rest_url('wc-licensed-product/v1/analytics/products'),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the statistics page
|
||||
*/
|
||||
public function renderStatisticsPage(): void
|
||||
{
|
||||
$stats = $this->licenseManager->getStatistics();
|
||||
|
||||
// Render using Twig if available
|
||||
$plugin = \Jeremias\WcLicensedProduct\Plugin::getInstance();
|
||||
$twig = $plugin->getTwig();
|
||||
|
||||
if ($twig) {
|
||||
try {
|
||||
echo $twig->render('admin/statistics.html.twig', [
|
||||
'stats' => $stats,
|
||||
'admin_url' => admin_url('admin.php'),
|
||||
'rest_url' => rest_url('wc-licensed-product/v1/analytics/'),
|
||||
]);
|
||||
return;
|
||||
} catch (\Twig\Error\LoaderError $e) {
|
||||
// Template not found, use fallback
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback PHP rendering
|
||||
$this->renderStatisticsPageFallback($stats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback rendering for statistics page
|
||||
*/
|
||||
private function renderStatisticsPageFallback(array $stats): void
|
||||
{
|
||||
?>
|
||||
<div class="wrap wclp-statistics">
|
||||
<h1><?php esc_html_e('License Statistics', 'wc-licensed-product'); ?></h1>
|
||||
|
||||
<div class="wclp-stats-overview">
|
||||
<div class="wclp-stat-cards">
|
||||
<div class="wclp-stat-card">
|
||||
<h3><?php esc_html_e('Total Licenses', 'wc-licensed-product'); ?></h3>
|
||||
<span class="wclp-stat-number"><?php echo esc_html($stats['total']); ?></span>
|
||||
</div>
|
||||
<div class="wclp-stat-card wclp-stat-active">
|
||||
<h3><?php esc_html_e('Active', 'wc-licensed-product'); ?></h3>
|
||||
<span class="wclp-stat-number"><?php echo esc_html($stats['by_status']['active'] ?? 0); ?></span>
|
||||
</div>
|
||||
<div class="wclp-stat-card wclp-stat-inactive">
|
||||
<h3><?php esc_html_e('Inactive', 'wc-licensed-product'); ?></h3>
|
||||
<span class="wclp-stat-number"><?php echo esc_html($stats['by_status']['inactive'] ?? 0); ?></span>
|
||||
</div>
|
||||
<div class="wclp-stat-card wclp-stat-expired">
|
||||
<h3><?php esc_html_e('Expired', 'wc-licensed-product'); ?></h3>
|
||||
<span class="wclp-stat-number"><?php echo esc_html($stats['by_status']['expired'] ?? 0); ?></span>
|
||||
</div>
|
||||
<div class="wclp-stat-card wclp-stat-revoked">
|
||||
<h3><?php esc_html_e('Revoked', 'wc-licensed-product'); ?></h3>
|
||||
<span class="wclp-stat-number"><?php echo esc_html($stats['by_status']['revoked'] ?? 0); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($stats['expiring_soon'] > 0): ?>
|
||||
<div class="notice notice-warning">
|
||||
<p>
|
||||
<strong><?php esc_html_e('Attention:', 'wc-licensed-product'); ?></strong>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %d: number of licenses */
|
||||
_n(
|
||||
'%d license is expiring within the next 30 days.',
|
||||
'%d licenses are expiring within the next 30 days.',
|
||||
$stats['expiring_soon'],
|
||||
'wc-licensed-product'
|
||||
),
|
||||
$stats['expiring_soon']
|
||||
);
|
||||
?>
|
||||
<a href="<?php echo esc_url(admin_url('admin.php?page=wc-licenses')); ?>">
|
||||
<?php esc_html_e('View Licenses', 'wc-licensed-product'); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="wclp-stats-details">
|
||||
<div class="wclp-stat-box">
|
||||
<h3><?php esc_html_e('License Types', 'wc-licensed-product'); ?></h3>
|
||||
<table class="widefat striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><?php esc_html_e('Lifetime Licenses', 'wc-licensed-product'); ?></td>
|
||||
<td class="wclp-stat-value"><?php echo esc_html($stats['lifetime'] ?? 0); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php esc_html_e('Time-limited Licenses', 'wc-licensed-product'); ?></td>
|
||||
<td class="wclp-stat-value"><?php echo esc_html($stats['expiring'] ?? 0); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php esc_html_e('Expiring Soon (30 days)', 'wc-licensed-product'); ?></td>
|
||||
<td class="wclp-stat-value"><?php echo esc_html($stats['expiring_soon'] ?? 0); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="wclp-stat-box">
|
||||
<h3><?php esc_html_e('Top Products by Licenses', 'wc-licensed-product'); ?></h3>
|
||||
<?php if (empty($stats['by_product'])): ?>
|
||||
<p class="description"><?php esc_html_e('No license data available yet.', 'wc-licensed-product'); ?></p>
|
||||
<?php else: ?>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e('Product', 'wc-licensed-product'); ?></th>
|
||||
<th class="wclp-stat-value"><?php esc_html_e('Licenses', 'wc-licensed-product'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($stats['by_product'] as $product): ?>
|
||||
<tr>
|
||||
<td><?php echo esc_html($product['product_name']); ?></td>
|
||||
<td class="wclp-stat-value"><?php echo esc_html($product['count']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="wclp-stat-box">
|
||||
<h3><?php esc_html_e('Top Domains', 'wc-licensed-product'); ?></h3>
|
||||
<?php if (empty($stats['top_domains'])): ?>
|
||||
<p class="description"><?php esc_html_e('No license data available yet.', 'wc-licensed-product'); ?></p>
|
||||
<?php else: ?>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e('Domain', 'wc-licensed-product'); ?></th>
|
||||
<th class="wclp-stat-value"><?php esc_html_e('Licenses', 'wc-licensed-product'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($stats['top_domains'] as $domain): ?>
|
||||
<tr>
|
||||
<td><code><?php echo esc_html($domain['domain']); ?></code></td>
|
||||
<td class="wclp-stat-value"><?php echo esc_html($domain['count']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wclp-chart-section">
|
||||
<h3><?php esc_html_e('Licenses Created (Last 12 Months)', 'wc-licensed-product'); ?></h3>
|
||||
<?php if (empty($stats['monthly'])): ?>
|
||||
<p class="description"><?php esc_html_e('No license data available yet.', 'wc-licensed-product'); ?></p>
|
||||
<?php else: ?>
|
||||
<div class="wclp-chart-container">
|
||||
<div class="wclp-bar-chart">
|
||||
<?php
|
||||
$maxValue = max(1, max($stats['monthly']));
|
||||
foreach ($stats['monthly'] as $month => $count):
|
||||
$height = ($count / $maxValue * 100);
|
||||
?>
|
||||
<div class="wclp-bar-wrapper">
|
||||
<div class="wclp-bar" style="height: <?php echo esc_attr($height); ?>%;" title="<?php echo esc_attr($count); ?> <?php esc_attr_e('licenses', 'wc-licensed-product'); ?>">
|
||||
<span class="wclp-bar-value"><?php echo esc_html($count); ?></span>
|
||||
</div>
|
||||
<span class="wclp-bar-label"><?php echo esc_html(date_i18n('M Y', strtotime($month . '-01'))); ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wclp-stats-actions">
|
||||
<h2><?php esc_html_e('Quick Actions', 'wc-licensed-product'); ?></h2>
|
||||
<div class="wclp-action-buttons">
|
||||
<a href="<?php echo esc_url(admin_url('admin.php?page=wc-licenses')); ?>" class="button button-primary">
|
||||
<span class="dashicons dashicons-admin-network"></span>
|
||||
<?php esc_html_e('Manage Licenses', 'wc-licensed-product'); ?>
|
||||
</a>
|
||||
<a href="<?php echo esc_url(admin_url('admin.php?page=wc-licenses&action=export_csv')); ?>" class="button">
|
||||
<span class="dashicons dashicons-download"></span>
|
||||
<?php esc_html_e('Export to CSV', 'wc-licensed-product'); ?>
|
||||
</a>
|
||||
<a href="<?php echo esc_url(admin_url('admin.php?page=wc-settings&tab=licensed_product')); ?>" class="button">
|
||||
<span class="dashicons dashicons-admin-generic"></span>
|
||||
<?php esc_html_e('Settings', 'wc-licensed-product'); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wclp-api-info">
|
||||
<h3><?php esc_html_e('REST API Endpoints', 'wc-licensed-product'); ?></h3>
|
||||
<p class="description">
|
||||
<?php esc_html_e('The following REST API endpoints are available for retrieving license statistics:', 'wc-licensed-product'); ?>
|
||||
</p>
|
||||
<table class="widefat striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e('Endpoint', 'wc-licensed-product'); ?></th>
|
||||
<th><?php esc_html_e('Description', 'wc-licensed-product'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>GET /wc-licensed-product/v1/analytics/stats</code></td>
|
||||
<td><?php esc_html_e('Get license statistics with time-series data', 'wc-licensed-product'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GET /wc-licensed-product/v1/analytics/products</code></td>
|
||||
<td><?php esc_html_e('Get license counts by product', 'wc-licensed-product'); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ declare(strict_types=1);
|
||||
namespace Jeremias\WcLicensedProduct;
|
||||
|
||||
use Jeremias\WcLicensedProduct\Admin\AdminController;
|
||||
use Jeremias\WcLicensedProduct\Admin\AnalyticsController;
|
||||
use Jeremias\WcLicensedProduct\Admin\OrderLicenseController;
|
||||
use Jeremias\WcLicensedProduct\Admin\SettingsController;
|
||||
use Jeremias\WcLicensedProduct\Admin\VersionAdminController;
|
||||
@@ -68,6 +69,14 @@ final class Plugin
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get singleton instance (alias for instance())
|
||||
*/
|
||||
public static function getInstance(): Plugin
|
||||
{
|
||||
return self::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for singleton
|
||||
*/
|
||||
@@ -125,6 +134,7 @@ final class Plugin
|
||||
new VersionAdminController($this->versionManager);
|
||||
new OrderLicenseController($this->licenseManager);
|
||||
new SettingsController();
|
||||
(new AnalyticsController($this->licenseManager))->init();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user