diff --git a/admin/class-robotstxt-manager-admin.php b/admin/class-robotstxt-manager-admin.php index 400631c..1921cc6 100644 --- a/admin/class-robotstxt-manager-admin.php +++ b/admin/class-robotstxt-manager-admin.php @@ -72,6 +72,8 @@ class Robotstxt_Manager_Admin { // Admin notices for subscriptions needing attention. $manager_notices = $this->build_subscription_notices( $catalog, $subscriptions ); $manager_subscriptions = $subscriptions; + $manager_has_api_key = $client->has_api_key(); + $manager_store_url = $client->get_store_url(); require ROBOTSTXT_MANAGER_DIR . 'admin/views/page-catalog.php'; } diff --git a/admin/class-robotstxt-manager-settings.php b/admin/class-robotstxt-manager-settings.php index b8d5d76..cddc28f 100644 --- a/admin/class-robotstxt-manager-settings.php +++ b/admin/class-robotstxt-manager-settings.php @@ -263,7 +263,7 @@ class Robotstxt_Manager_Settings { } echo '

'; } else { - echo '

' . esc_html__( 'Account-level API key issued by the ROBOTSTXT store. Required to authenticate catalog and subscription requests. The value is encrypted before storage.', 'robotstxt-manager' ) . '

'; + echo '

' . esc_html__( 'Account-level API key from the ROBOTSTXT store (create your free account there to get one). Optional — the free catalog works without it — but required to link your subscriptions, install premium plugins, and receive their updates. Encrypted before storage.', 'robotstxt-manager' ) . '

'; } // Action buttons. diff --git a/admin/views/page-catalog.php b/admin/views/page-catalog.php index 0cc556d..522a2a5 100644 --- a/admin/views/page-catalog.php +++ b/admin/views/page-catalog.php @@ -25,6 +25,8 @@ if ( ! defined( 'ABSPATH' ) ) { * @var array $local * @var array> $manager_subscriptions * @var list $manager_notices + * @var bool $manager_has_api_key + * @var string $manager_store_url */ $client_configured = Robotstxt_Manager_Core_Client::from_options()->is_configured(); @@ -77,6 +79,22 @@ $compat_warnings = 0; + +
+

+ ROBOTSTXT store to get your personal API key. The key links your subscriptions to this site and unlocks premium plugins and updates.', 'robotstxt-manager' ), + esc_url( $manager_store_url . '/wp-login.php?action=register' ) + ) + ); + ?> +

+
+ +

@@ -149,6 +167,14 @@ $compat_warnings = 0; $website_url = '' !== $page_url ? $page_url : $homepage; $has_detail = ( '' !== $website_url || '' !== $desc ); + // Subscription state: premium plugins are only usable + // (install/update) with an active or in-grace subscription. + $is_premium = ( $cost > 0.0 || 'premium' === $kind ); + $sub_row = $manager_subscriptions[ $slug ] ?? null; + $raw_status = is_array( $sub_row ) ? ( $sub_row['status'] ?? '' ) : ''; + $sub_status = is_string( $raw_status ) ? $raw_status : ''; + $subscribed = in_array( $sub_status, array( 'active', 'payment_failed' ), true ); + $raw_reqs = $entry['requires_plugins'] ?? ''; $req_slugs = array(); if ( is_string( $raw_reqs ) && '' !== trim( $raw_reqs ) ) { @@ -220,7 +246,7 @@ $compat_warnings = 0; 0.0 || 'premium' === $kind ) { + if ( $is_premium ) { echo esc_html( sprintf( /* translators: %s: formatted price number. */ @@ -230,13 +256,10 @@ $compat_warnings = 0; ); // Subscription pill for premium plugins. - $sub_row = $manager_subscriptions[ $slug ] ?? null; $sub_text = ''; if ( is_array( $sub_row ) ) { - $raw_sub_status = $sub_row['status'] ?? ''; $raw_sub_expiry = $sub_row['expires_at'] ?? ''; - $sub_status = is_string( $raw_sub_status ) ? $raw_sub_status : ''; $sub_expiry = is_string( $raw_sub_expiry ) ? $raw_sub_expiry : ''; if ( 'active' === $sub_status && '' !== $sub_expiry ) { @@ -261,11 +284,8 @@ $compat_warnings = 0; } if ( '' !== $sub_text ) { - $raw_pill_status = is_array( $sub_row ) ? ( $sub_row['status'] ?? '' ) : ''; - $pill_status = is_string( $raw_pill_status ) ? $raw_pill_status : ''; - echo '
' . esc_html( $sub_text ) . ''; } } else { @@ -274,18 +294,16 @@ $compat_warnings = 0; ?> - - - + + + + + - 0.0 && '' !== $page_url ) : ?> - - - 0.0 && '' !== $page_url ) ? 'button-secondary' : 'button-primary'; - ?> - + — + + diff --git a/changelog.txt b/changelog.txt index c032561..0fcf438 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,24 @@ == Changelog == += 1.3.0 = + +_Release date: 2026-08-17_ + +**Highlights** + +* The catalog now works **without an API key**: only the Store URL is required. The free catalog, prices, and product pages are public on Core, so a fresh install shows the store immediately. An info notice invites visitors to create their free account at the store to get a personal API key (linking subscriptions and unlocking premium plugins and updates). + +**Changed** + +* Action buttons follow subscription state: premium plugins without an active subscription show **Buy** only (Install/Update hidden — the download would be rejected); with an active or in-grace subscription (and for free plugins) they show **Install / Activate / Update** as usual. Previously premium rows always offered Install alongside Buy. +* The API-key setting description clarifies the key is optional for browsing, required for subscriptions/premium. +* Plugin version 1.2.1 → 1.3.0. No database schema changes (no custom tables). + +**Compatibility** + +* WordPress: 4.4 - 7.1 (scan-verified: wp-compat clean from 4.4) +* PHP: 8.0 - 8.5 (scan-verified: PHPCompatibility + manual feature audit) + = 1.2.1 = _Release date: 2026-08-17_ diff --git a/includes/class-robotstxt-manager-core-client.php b/includes/class-robotstxt-manager-core-client.php index adb6e93..672c66f 100644 --- a/includes/class-robotstxt-manager-core-client.php +++ b/includes/class-robotstxt-manager-core-client.php @@ -91,12 +91,25 @@ class Robotstxt_Manager_Core_Client { } /** - * Returns whether the client has both a URL and a key configured. + * Returns whether the client can talk to the store. + * + * Only the Store URL is required: the catalog (free plugins, prices, + * product pages) is public on Core. The API key is optional — it is + * needed for subscription data and premium downloads, not for listing. * * @return bool */ public function is_configured(): bool { - return '' !== $this->store_url && '' !== $this->api_key; + return '' !== $this->store_url; + } + + /** + * Returns whether an API key is configured. + * + * @return bool + */ + public function has_api_key(): bool { + return '' !== $this->api_key; } /** @@ -269,13 +282,16 @@ class Robotstxt_Manager_Core_Client { private function get( string $endpoint ) { $url = $this->store_url . '/wp-json/' . self::REST_NAMESPACE . $endpoint; + $headers = array( 'Accept' => 'application/json' ); + + if ( '' !== $this->api_key ) { + $headers['Authorization'] = 'Bearer ' . $this->api_key; + } + return wp_remote_get( $url, array( - 'headers' => array( - 'Authorization' => 'Bearer ' . $this->api_key, - 'Accept' => 'application/json', - ), + 'headers' => $headers, 'timeout' => self::TIMEOUT, ) ); diff --git a/languages/robotstxt-manager-ca.mo b/languages/robotstxt-manager-ca.mo index 6d9335f..e313bbf 100644 Binary files a/languages/robotstxt-manager-ca.mo and b/languages/robotstxt-manager-ca.mo differ diff --git a/languages/robotstxt-manager-ca.po b/languages/robotstxt-manager-ca.po index 0552f8f..3c5406d 100644 --- a/languages/robotstxt-manager-ca.po +++ b/languages/robotstxt-manager-ca.po @@ -293,3 +293,9 @@ msgid "The subscription for %1$s expires in %2$d day." msgid_plural "The subscription for %1$s expires in %2$d days." msgstr[0] "La subscripció de %1$s caduca en %2$d dia." msgstr[1] "La subscripció de %1$s caduca en %2$d dies." + +msgid "Create your free account at the ROBOTSTXT store to get your personal API key. The key links your subscriptions to this site and unlocks premium plugins and updates." +msgstr "Crea el teu compte gratuït a la botiga de ROBOTSTXT per obtenir la teva clau API personal. La clau vincula les teves subscripcions a aquest lloc i desbloqueja els plugins premium i les seves actualitzacions." + +msgid "Account-level API key from the ROBOTSTXT store (create your free account there to get one). Optional — the free catalog works without it — but required to link your subscriptions, install premium plugins, and receive their updates. Encrypted before storage." +msgstr "Clau API a nivell de compte de la botiga de ROBOTSTXT (crea allà el teu compte gratuït per obtenir-la). Opcional: el catàleg de plugins gratuïts funciona sense ella, però és necessària per vincular les teves subscripcions, instal·lar plugins premium i rebre les actualitzacions. Es xifra abans de desar-se." diff --git a/languages/robotstxt-manager-es_ES.mo b/languages/robotstxt-manager-es_ES.mo index 9d6dc71..40903e8 100644 Binary files a/languages/robotstxt-manager-es_ES.mo and b/languages/robotstxt-manager-es_ES.mo differ diff --git a/languages/robotstxt-manager-es_ES.po b/languages/robotstxt-manager-es_ES.po index 8083a59..fb239cd 100644 --- a/languages/robotstxt-manager-es_ES.po +++ b/languages/robotstxt-manager-es_ES.po @@ -293,3 +293,9 @@ msgid "The subscription for %1$s expires in %2$d day." msgid_plural "The subscription for %1$s expires in %2$d days." msgstr[0] "La suscripción de %1$s caduca en %2$d día." msgstr[1] "La suscripción de %1$s caduca en %2$d días." + +msgid "Create your free account at the ROBOTSTXT store to get your personal API key. The key links your subscriptions to this site and unlocks premium plugins and updates." +msgstr "Crea tu cuenta gratuita en la tienda de ROBOTSTXT para obtener tu clave API personal. La clave vincula tus suscripciones a este sitio y desbloquea los plugins premium y sus actualizaciones." + +msgid "Account-level API key from the ROBOTSTXT store (create your free account there to get one). Optional — the free catalog works without it — but required to link your subscriptions, install premium plugins, and receive their updates. Encrypted before storage." +msgstr "Clave API a nivel de cuenta de la tienda de ROBOTSTXT (crea allí tu cuenta gratuita para obtenerla). Opcional: el catálogo de plugins gratis funciona sin ella, pero es necesaria para vincular tus suscripciones, instalar plugins premium y recibir sus actualizaciones. Se cifra antes de guardarse." diff --git a/languages/robotstxt-manager.pot b/languages/robotstxt-manager.pot index 38a56d3..4d2d0c3 100644 --- a/languages/robotstxt-manager.pot +++ b/languages/robotstxt-manager.pot @@ -25,3 +25,9 @@ msgstr "" msgid "Expired" msgstr "" + +msgid "Create your free account at the ROBOTSTXT store to get your personal API key. The key links your subscriptions to this site and unlocks premium plugins and updates." +msgstr "" + +msgid "Account-level API key from the ROBOTSTXT store (create your free account there to get one). Optional — the free catalog works without it — but required to link your subscriptions, install premium plugins, and receive their updates. Encrypted before storage." +msgstr "" diff --git a/readme.txt b/readme.txt index 7b8c566..e19ed1b 100644 --- a/readme.txt +++ b/readme.txt @@ -3,9 +3,9 @@ Contributors: javiercasares, robotstxt Tags: dashboard, catalog, updates, subscriptions, management Requires at least: 4.4 Tested up to: 7.1 -Stable tag: 1.2.1 +Stable tag: 1.3.0 Requires PHP: 8.0 -Version: 1.2.1 +Version: 1.3.0 License: GPL-3.0-or-later License URI: https://www.gnu.org/licenses/gpl-3.0.txt @@ -92,6 +92,12 @@ Encrypted at rest using AES-256-CBC with a key derived from your site's WordPres == Changelog == += 1.3.0 = + +_Release date: 2026-08-17_ + +* Catalog works without an API key (only the Store URL is needed); free plugins are listed and installable, and an info notice links to the store to register and get a personal key. Premium plugins show Buy only until subscribed; with an active subscription they show Install/Update. + = 1.2.1 = _Release date: 2026-08-17_ diff --git a/robotstxt-manager.php b/robotstxt-manager.php index c6d5428..ea76084 100644 --- a/robotstxt-manager.php +++ b/robotstxt-manager.php @@ -3,7 +3,7 @@ * Plugin Name: Manager (by ROBOTSTXT) * Plugin URI: https://git.robotstxt.es/ROBOTSTXT/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.2.1 + * Version: 1.3.0 * Requires at least: 4.4 * Requires PHP: 8.0 * Author: ROBOTSTXT @@ -21,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) { } /** Plugin version. */ -define( 'ROBOTSTXT_MANAGER_VERSION', '1.2.1' ); +define( 'ROBOTSTXT_MANAGER_VERSION', '1.3.0' ); /** Absolute path to the plugin directory, with trailing slash. */ define( 'ROBOTSTXT_MANAGER_DIR', plugin_dir_path( __FILE__ ) );