diff --git a/admin/views/page-catalog.php b/admin/views/page-catalog.php index 51b2c23..08a103b 100644 --- a/admin/views/page-catalog.php +++ b/admin/views/page-catalog.php @@ -298,10 +298,18 @@ $compat_warnings = 0; $raw_bound = $sub_row['bound_domain'] ?? ''; $bound_text = is_string( $raw_bound ) ? trim( $raw_bound ) : ''; + // Multi-license: how many licenses the account + // holds for this plugin (Core 1.14.0+). + $raw_count = $sub_row['license_count'] ?? 1; + $count_int = is_numeric( $raw_count ) ? (int) ( $raw_count + 0 ) : 1; + $count_txt = $count_int > 1 ? ' ×' . $count_int : ''; + if ( '' !== $bound_text && in_array( $sub_status, array( 'active', 'payment_failed' ), true ) ) { $sub_text = '' !== $sub_text - ? $sub_text . ' @ ' . $bound_text - : $bound_text; + ? $sub_text . ' @ ' . $bound_text . $count_txt + : $bound_text . $count_txt; + } elseif ( '' !== $count_txt ) { + $sub_text = '' !== $sub_text ? $sub_text . $count_txt : 'Subscribed' . $count_txt; } } diff --git a/changelog.txt b/changelog.txt index 4f83844..2f3fd47 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,19 @@ == Changelog == += 1.8.0 = + +_Release date: 2026-08-24_ + +**Added** + +* Multi-domain license awareness (with Core 1.14.0): `Robotstxt_Manager_Core_Client::get_subscriptions()` groups the flat `/me/subscriptions` rows per plugin slug — any-active status wins, the first bound domain is shown, and a `license_count` is kept. Catalog subscription pills render the count when a plugin has more than one license (e.g. "Subscribed @ example.com ×2"). + +**Tests** + +* PHPCS (WordPress-Core, WordPress-Docs, WordPress-Extra): pass +* PHPStan level 9 + wp-compat: pass +* PHPUnit: 149 tests, 391 assertions + = 1.7.0 = _Release date: 2026-08-18_ diff --git a/includes/class-robotstxt-manager-core-client.php b/includes/class-robotstxt-manager-core-client.php index 8c2ec54..ca38fb4 100644 --- a/includes/class-robotstxt-manager-core-client.php +++ b/includes/class-robotstxt-manager-core-client.php @@ -358,10 +358,35 @@ class Robotstxt_Manager_Core_Client { $raw_expires_at = $row['expires_at'] ?? ''; $raw_bound = $row['bound_domain'] ?? ''; + $status = is_string( $raw_status ) ? $raw_status : ''; + $expires_at = is_string( $raw_expires_at ) ? $raw_expires_at : ''; + $bound = is_string( $raw_bound ) ? $raw_bound : ''; + + // Group multi-license rows (Core 1.14.0+: one row per domain) + // into one entry per slug: any-active wins, first bound domain + // shown, license count kept for the pill. + if ( isset( $rows[ $slug ] ) ) { + $existing = $rows[ $slug ]; + + if ( 'active' === $status && 'active' !== $existing['status'] ) { + $existing['status'] = 'active'; + $existing['expires_at'] = $expires_at; + } + + if ( '' === $existing['bound_domain'] && '' !== $bound ) { + $existing['bound_domain'] = $bound; + } + + $existing['license_count'] = (int) $existing['license_count'] + 1; + $rows[ $slug ] = $existing; + continue; + } + $rows[ $slug ] = array( - 'status' => is_string( $raw_status ) ? $raw_status : '', - 'expires_at' => is_string( $raw_expires_at ) ? $raw_expires_at : '', - 'bound_domain' => is_string( $raw_bound ) ? $raw_bound : '', + 'status' => $status, + 'expires_at' => $expires_at, + 'bound_domain' => $bound, + 'license_count' => 1, ); } diff --git a/languages/robotstxt-manager.pot b/languages/robotstxt-manager.pot index 5e842d5..f7ac393 100644 --- a/languages/robotstxt-manager.pot +++ b/languages/robotstxt-manager.pot @@ -2,7 +2,7 @@ # This file is distributed under the GPL-3.0-or-later. msgid "" msgstr "" -"Project-Id-Version: Manager (by ROBOTSTXT) 1.7.0\n" +"Project-Id-Version: Manager (by ROBOTSTXT) 1.8.0\n" "Report-Msgid-Bugs-To: https://www.robotstxt.software/plugins/robotstxt-manager/\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/readme.txt b/readme.txt index 64bece5..1a52e3a 100644 --- a/readme.txt +++ b/readme.txt @@ -3,9 +3,9 @@ Contributors: robotstxt, javiercasares Tags: dashboard, catalog, updates, subscriptions, management Requires at least: 4.4 Tested up to: 7.1 -Stable tag: 1.7.0 +Stable tag: 1.8.0 Requires PHP: 8.0 -Version: 1.7.0 +Version: 1.8.0 License: GPL-3.0-or-later License URI: https://www.gnu.org/licenses/gpl-3.0.txt @@ -94,6 +94,12 @@ Encrypted at rest using AES-256-CBC with a key derived from your site's WordPres Only the 3 last versions. The full changelog will be at changelog.txt += 1.8.0 = + +_Release date: 2026-08-24_ + +* New: multi-domain license awareness (with Core 1.14.0) — the account's subscriptions are grouped per plugin and catalog pills show how many licenses you hold (e.g. "Subscribed @ example.com ×2") with the domain of the first bound license. + = 1.7.0 = _Release date: 2026-08-18_ @@ -107,12 +113,6 @@ _Release date: 2026-08-18_ * Added: `ROBOTSTXT_MANAGER_NOTICED` presence constant (guarded, `true`) — ecosystem plugins detect Manager via a constant check instead of scanning the plugin list. -= 1.6.1 = - -_Release date: 2026-08-18_ - -* Fixed: "headers already sent" warning after saving the settings — the form handler now runs on `admin_init`, before any output. - = Previous versions = If you want to see the full changelog, visit the [plugin page](https://www.robotstxt.software/plugins/robotstxt-manager/). diff --git a/robotstxt-manager.php b/robotstxt-manager.php index 8b423ac..ab4af19 100644 --- a/robotstxt-manager.php +++ b/robotstxt-manager.php @@ -3,7 +3,7 @@ * Plugin Name: Manager (by ROBOTSTXT) * Plugin URI: https://www.robotstxt.software/plugins/robotstxt-manager/ * Description: Client-side dashboard for the ROBOTSTXT plugin ecosystem. Lists the catalog from a remote Plugins Core install, resolves local install/update state, and installs, activates, and updates plugins directly from the store. - * Version: 1.7.0 + * Version: 1.8.0 * Requires at least: 4.4 * Requires PHP: 8.0 * Update URI: https://www.robotstxt.software/plugins/robotstxt-manager/ @@ -23,7 +23,7 @@ if ( ! defined( 'ABSPATH' ) ) { } /** Plugin version. */ -define( 'ROBOTSTXT_MANAGER_VERSION', '1.7.0' ); +define( 'ROBOTSTXT_MANAGER_VERSION', '1.8.0' ); /** Absolute path to the plugin directory, with trailing slash. */ define( 'ROBOTSTXT_MANAGER_DIR', plugin_dir_path( __FILE__ ) );