diff --git a/CHANGELOG.md b/CHANGELOG.md
index c424410..0405345 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [0.0.11] - 2026-01-21
+
+### Added
+
+- Created date column in admin license overview
+- License Statistics page under WooCommerce menu
+- REST API endpoints for analytics data:
+ - `GET /wp-json/wc-licensed-product/v1/analytics/stats` - License statistics with time-series data
+ - `GET /wp-json/wc-licensed-product/v1/analytics/products` - License counts by product
+- WooCommerce Analytics integration via submenu page
+
+### Technical Details
+
+- New `AnalyticsController` class for WooCommerce Analytics integration
+- Statistics page accessible via WooCommerce > License Statistics
+- Time-series data supports day, week, month, quarter, year intervals
+- REST API endpoints for external analytics integrations
+- Statistics template `templates/admin/statistics.html.twig`
+
## [0.0.10] - 2026-01-21
### Added
@@ -264,7 +283,11 @@ 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.7...HEAD
+[Unreleased]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.11...HEAD
+[0.0.11]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.10...v0.0.11
+[0.0.10]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.9...v0.0.10
+[0.0.9]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.8...v0.0.9
+[0.0.8]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.7...v0.0.8
[0.0.7]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.6...v0.0.7
[0.0.6]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.5...v0.0.6
[0.0.5]: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/compare/v0.0.4...v0.0.5
diff --git a/CLAUDE.md b/CLAUDE.md
index d7150bf..d83a938 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -36,10 +36,6 @@ This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase w
- Version uploads not appearing in list (under investigation - may require plugin reactivation to ensure database tables exist)
-### Version 0.0.11 (planned)
-
-- TBD - no specific features planned yet
-
## Technical Stack
- **Language:** PHP 8.3.x
@@ -597,3 +593,36 @@ Full API documentation available in `openapi.json` (OpenAPI 3.1 specification).
- Created release package: `releases/wc-licensed-product-0.0.10.zip` (472 KB)
- SHA256: `3f4a093f6d4d02389082c3a88c00542f477ab3ad4d4a0c65079e524ef0739620`
- Tagged as `v0.0.10` and pushed to `main` branch
+
+### 2026-01-21 - Version 0.0.11 Features
+
+**Implemented:**
+
+- Created date column added to admin license overview
+- License Statistics page under WooCommerce menu (WooCommerce > License Statistics)
+- REST API endpoints for analytics data with time-series support
+- WooCommerce Analytics integration via submenu page
+
+**New files:**
+
+- `src/Admin/AnalyticsController.php` - WooCommerce Analytics integration
+- `templates/admin/statistics.html.twig` - Statistics page template
+
+**New REST API endpoints:**
+
+- `GET /wp-json/wc-licensed-product/v1/analytics/stats` - License statistics with time-series data (supports day/week/month/quarter/year intervals)
+- `GET /wp-json/wc-licensed-product/v1/analytics/products` - License counts by product
+
+**Modified files:**
+
+- `templates/admin/licenses.html.twig` - Added "Created" column
+- `src/Admin/AdminController.php` - Added "Created" column to fallback rendering
+- `src/Plugin.php` - Added AnalyticsController initialization and `getInstance()` alias
+
+**Technical notes:**
+
+- Statistics page accessible via WooCommerce > License Statistics submenu
+- REST API endpoints support date range filtering (`after`, `before` parameters)
+- Time-series data aggregation supports multiple intervals (day, week, month, quarter, year)
+- AnalyticsController registers REST routes and renders statistics page
+- Page uses existing dashboard CSS styles for consistent appearance
diff --git a/languages/wc-licensed-product-de_CH.mo b/languages/wc-licensed-product-de_CH.mo
index 3d6cb54..e111388 100644
Binary files a/languages/wc-licensed-product-de_CH.mo and b/languages/wc-licensed-product-de_CH.mo differ
diff --git a/languages/wc-licensed-product-de_CH.po b/languages/wc-licensed-product-de_CH.po
index a4f203e..0a6cdda 100644
--- a/languages/wc-licensed-product-de_CH.po
+++ b/languages/wc-licensed-product-de_CH.po
@@ -3,7 +3,7 @@
# This file is distributed under the GPL-2.0-or-later.
msgid ""
msgstr ""
-"Project-Id-Version: WC Licensed Product 0.0.10\n"
+"Project-Id-Version: WC Licensed Product 0.0.11\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/issues\n"
"POT-Creation-Date: 2026-01-21T00:00:00+00:00\n"
"PO-Revision-Date: 2026-01-21T00:00:00+00:00\n"
@@ -939,3 +939,34 @@ msgstr "Fehler beim Speichern. Bitte versuchen Sie es erneut."
msgid "Failed to update license domain."
msgstr "Lizenz-Domain konnte nicht aktualisiert werden."
+
+#. Admin - License Overview (Created column)
+msgid "Created"
+msgstr "Erstellt"
+
+#. Admin - License Statistics
+msgid "License Statistics"
+msgstr "Lizenz-Statistiken"
+
+msgid "%d license is expiring within the next 30 days."
+msgid_plural "%d licenses are expiring within the next 30 days."
+msgstr[0] "%d Lizenz läuft innerhalb der nächsten 30 Tage ab."
+msgstr[1] "%d Lizenzen laufen innerhalb der nächsten 30 Tage ab."
+
+msgid "REST API Endpoints"
+msgstr "REST-API-Endpunkte"
+
+msgid "The following REST API endpoints are available for retrieving license statistics:"
+msgstr "Die folgenden REST-API-Endpunkte sind für den Abruf von Lizenz-Statistiken verfügbar:"
+
+msgid "Endpoint"
+msgstr "Endpunkt"
+
+msgid "Description"
+msgstr "Beschreibung"
+
+msgid "Get license statistics with time-series data"
+msgstr "Lizenz-Statistiken mit Zeitreihen-Daten abrufen"
+
+msgid "Get license counts by product"
+msgstr "Lizenz-Anzahl pro Produkt abrufen"
diff --git a/languages/wc-licensed-product.pot b/languages/wc-licensed-product.pot
index 3fe9de9..e2ed34d 100644
--- a/languages/wc-licensed-product.pot
+++ b/languages/wc-licensed-product.pot
@@ -2,7 +2,7 @@
# This file is distributed under the GPL-2.0-or-later.
msgid ""
msgstr ""
-"Project-Id-Version: WC Licensed Product 0.0.10\n"
+"Project-Id-Version: WC Licensed Product 0.0.11\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/magdev/wc-licensed-product/issues\n"
"POT-Creation-Date: 2026-01-21T00:00:00+00:00\n"
"MIME-Version: 1.0\n"
@@ -939,3 +939,34 @@ msgstr ""
msgid "Failed to update license domain."
msgstr ""
+
+#. Admin - License Overview (Created column)
+msgid "Created"
+msgstr ""
+
+#. Admin - License Statistics
+msgid "License Statistics"
+msgstr ""
+
+msgid "%d license is expiring within the next 30 days."
+msgid_plural "%d licenses are expiring within the next 30 days."
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "REST API Endpoints"
+msgstr ""
+
+msgid "The following REST API endpoints are available for retrieving license statistics:"
+msgstr ""
+
+msgid "Endpoint"
+msgstr ""
+
+msgid "Description"
+msgstr ""
+
+msgid "Get license statistics with time-series data"
+msgstr ""
+
+msgid "Get license counts by product"
+msgstr ""
diff --git a/src/Admin/AdminController.php b/src/Admin/AdminController.php
index 6251646..15fc39b 100644
--- a/src/Admin/AdminController.php
+++ b/src/Admin/AdminController.php
@@ -1253,6 +1253,7 @@ final class AdminController
|
|
|
+ |
|
|
@@ -1260,7 +1261,7 @@ final class AdminController
- |
+ |
@@ -1320,6 +1321,9 @@ final class AdminController
+
+ getCreatedAt()->format(get_option('date_format'))); ?>
+ |
getExpiresAt(); ?>
@@ -1387,6 +1391,7 @@ final class AdminController
| |
|
|
+ |
|
|
diff --git a/src/Admin/AnalyticsController.php b/src/Admin/AnalyticsController.php
new file mode 100644
index 0000000..b4b02b8
--- /dev/null
+++ b/src/Admin/AnalyticsController.php
@@ -0,0 +1,523 @@
+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
+ {
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0): ?>
+
+
+
+
+
+
+
+
+
+ |
+ |
+
+
+ |
+ |
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $count):
+ $height = ($count / $maxValue * 100);
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+ GET /wc-licensed-product/v1/analytics/stats |
+ |
+
+
+ GET /wc-licensed-product/v1/analytics/products |
+ |
+
+
+
+
+
+ versionManager);
new OrderLicenseController($this->licenseManager);
new SettingsController();
+ (new AnalyticsController($this->licenseManager))->init();
}
}
diff --git a/templates/admin/licenses.html.twig b/templates/admin/licenses.html.twig
index ce7a9f3..530d4d8 100644
--- a/templates/admin/licenses.html.twig
+++ b/templates/admin/licenses.html.twig
@@ -95,6 +95,7 @@
{{ __('Customer') }} |
{{ __('Domain') }} |
{{ __('Status') }} |
+ {{ __('Created') }} |
{{ __('Expires') }} |
{{ __('Actions') }} |
@@ -102,7 +103,7 @@
{% if licenses is empty %}
- | {{ __('No licenses found.') }} |
+ {{ __('No licenses found.') }} |
{% else %}
{% for item in licenses %}
@@ -160,6 +161,9 @@
+
+ {{ item.license.createdAt|date('Y-m-d') }}
+ |
{% if item.license.expiresAt %}
@@ -219,6 +223,7 @@
| {{ __('Customer') }} |
{{ __('Domain') }} |
{{ __('Status') }} |
+ {{ __('Created') }} |
{{ __('Expires') }} |
{{ __('Actions') }} |
diff --git a/templates/admin/statistics.html.twig b/templates/admin/statistics.html.twig
new file mode 100644
index 0000000..360b6c8
--- /dev/null
+++ b/templates/admin/statistics.html.twig
@@ -0,0 +1,196 @@
+
+
{{ __('License Statistics') }}
+
+
+
+
+
+
+ {{ stats.total }}
+ {{ __('Total Licenses') }}
+
+
+
+
+
+ {{ stats.by_status.active }}
+ {{ __('Active') }}
+
+
+
+
+
+ {{ stats.by_status.inactive }}
+ {{ __('Inactive') }}
+
+
+
+
+
+ {{ stats.by_status.expired }}
+ {{ __('Expired') }}
+
+
+
+
+
+ {{ stats.by_status.revoked }}
+ {{ __('Revoked') }}
+
+
+
+
+ {% if stats.expiring_soon > 0 %}
+
+
+
+ {{ __('Attention:') }}
+ {{ stats.expiring_soon }} {{ stats.expiring_soon == 1 ? __('license is') : __('licenses are') }}
+ {{ __('expiring within the next 30 days.') }}
+ {{ __('View Licenses') }}
+
+
+ {% endif %}
+
+
+
+
{{ __('License Types') }}
+
+
+
+ | {{ __('Lifetime Licenses') }} |
+ {{ stats.lifetime }} |
+
+
+ | {{ __('Time-limited Licenses') }} |
+ {{ stats.expiring }} |
+
+
+ | {{ __('Expiring Soon (30 days)') }} |
+
+ {{ stats.expiring_soon }}
+ |
+
+
+
+
+
+
+
{{ __('Top Products by Licenses') }}
+ {% if stats.by_product is empty %}
+
{{ __('No license data available yet.') }}
+ {% else %}
+
+
+
+ | {{ __('Product') }} |
+ {{ __('Licenses') }} |
+
+
+
+ {% for product in stats.by_product %}
+
+ | {{ esc_html(product.product_name) }} |
+ {{ product.count }} |
+
+ {% endfor %}
+
+
+ {% endif %}
+
+
+
+
{{ __('Top Domains') }}
+ {% if stats.top_domains is empty %}
+
{{ __('No license data available yet.') }}
+ {% else %}
+
+
+
+ | {{ __('Domain') }} |
+ {{ __('Licenses') }} |
+
+
+
+ {% for domain in stats.top_domains %}
+
+ {{ esc_html(domain.domain) }} |
+ {{ domain.count }} |
+
+ {% endfor %}
+
+
+ {% endif %}
+
+
+
+
+
{{ __('Licenses Created (Last 12 Months)') }}
+ {% if stats.monthly is empty %}
+
{{ __('No license data available yet.') }}
+ {% else %}
+
+
+ {% 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 %}
+
+
+ {{ count }}
+
+
{{ month|date('M Y') }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+
+
+
+
{{ __('Quick Actions') }}
+
+
+
+
+
{{ __('REST API Endpoints') }}
+
+ {{ __('The following REST API endpoints are available for retrieving license statistics:') }}
+
+
+
+
+ | {{ __('Endpoint') }} |
+ {{ __('Description') }} |
+
+
+
+
+ GET {{ rest_url }}stats |
+ {{ __('Get license statistics with time-series data') }} |
+
+
+ GET {{ rest_url }}products |
+ {{ __('Get license counts by product') }} |
+
+
+
+
+
diff --git a/wc-licensed-product.php b/wc-licensed-product.php
index dc57e35..02f63c0 100644
--- a/wc-licensed-product.php
+++ b/wc-licensed-product.php
@@ -3,7 +3,7 @@
* Plugin Name: WooCommerce Licensed Product
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wc-licensed-product
* Description: WooCommerce plugin to sell software products using license keys with domain-based validation.
- * Version: 0.0.10
+ * Version: 0.0.11
* Author: Marco Graetsch
* Author URI: https://src.bundespruefstelle.ch/magdev
* License: GPL-2.0-or-later
@@ -28,7 +28,7 @@ if (!defined('ABSPATH')) {
}
// Plugin constants
-define('WC_LICENSED_PRODUCT_VERSION', '0.0.10');
+define('WC_LICENSED_PRODUCT_VERSION', '0.0.11');
define('WC_LICENSED_PRODUCT_PLUGIN_FILE', __FILE__);
define('WC_LICENSED_PRODUCT_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WC_LICENSED_PRODUCT_PLUGIN_URL', plugin_dir_url(__FILE__));