This commit is contained in:
Javier Casares 2026-08-18 10:47:06 +00:00
commit b2849880ec
8 changed files with 91 additions and 16 deletions

View file

@ -263,7 +263,16 @@ class Robotstxt_Manager_Settings {
}
echo '</p>';
} else {
echo '<p class="description">' . 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' ) . '</p>';
printf(
'<p class="description">%s</p>',
wp_kses_post(
sprintf(
/* translators: %s: Registration URL. */
__( 'Account-level API key from the ROBOTSTXT store (<a href="%s" target="_blank" rel="noopener">create your free account there to get one</a>). 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' ),
esc_url( 'https://www.robotstxt.software/wp-login.php?action=register' )
)
)
);
}
// Action buttons.
@ -333,6 +342,14 @@ class Robotstxt_Manager_Settings {
return is_string( $raw ) ? $raw : '';
}
// If the input is already encrypted (v2: prefix), it means the browser
// auto-filled the password field with the stored encrypted value.
// Return it as-is (already encrypted) rather than re-encrypting or
// trying to read the option (which may not be saved yet in the WP flow).
if ( str_starts_with( $plain, 'v2:' ) ) {
return $plain;
}
// Account keys are UUIDs issued by the store; reject anything that
// cannot be one rather than storing a mangled key that only fails
// later at connection time.
@ -379,7 +396,25 @@ class Robotstxt_Manager_Settings {
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'robotstxt-manager' ) ) );
}
$client = Robotstxt_Manager_Core_Client::from_options();
// Allow testing a key from the form field (not yet saved) by passing it in the request.
$input_key = '';
if ( isset( $_POST['robotstxt_manager_api_key'] ) ) {
$unslashed = wp_unslash( $_POST['robotstxt_manager_api_key'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized below.
if ( is_string( $unslashed ) ) {
$input_key = sanitize_text_field( $unslashed );
}
}
$store_url = get_option( 'robotstxt_manager_store_url', 'https://www.robotstxt.software' );
$store_url = is_string( $store_url ) ? $store_url : 'https://www.robotstxt.software';
// Use input key if provided, otherwise fall back to saved (decrypted) key.
if ( '' !== $input_key ) {
$client = new Robotstxt_Manager_Core_Client( $store_url, $input_key );
} else {
$client = Robotstxt_Manager_Core_Client::from_options();
}
$result = $client->test_connection();
if ( $result['ok'] ) {

View file

@ -20,11 +20,14 @@
$btn.prop( 'disabled', true ).text( RobotstxtManagerSettings.i18n.testing );
$result.text( '' ).css( 'color', '' );
var apiKey = $( '#robotstxt_manager_api_key' ).val();
$.post(
RobotstxtManagerSettings.ajaxUrl,
{
action: 'robotstxt_manager_test_connection',
nonce: RobotstxtManagerSettings.nonce,
robotstxt_manager_api_key: apiKey,
},
function ( response ) {
if ( response.success ) {

View file

@ -11,6 +11,7 @@ if ( ! defined( 'ABSPATH' ) ) {
?>
<div class="wrap">
<h1><?php esc_html_e( 'Manager (by ROBOTSTXT) — Settings', 'robotstxt-manager' ); ?></h1>
<?php settings_errors(); ?>
<form method="post" action="<?php echo esc_url( admin_url( 'options.php' ) ); ?>">
<?php
settings_fields( Robotstxt_Manager_Settings::OPTION_GROUP );

View file

@ -1,5 +1,26 @@
== Changelog ==
= 1.5.0 =
_Release date: 2026-08-18_
**Fixed**
* API key not saving when the browser auto-fills the password field with the stored encrypted value — the sanitizer now detects already-encrypted input (`v2:` prefix) and returns it as-is instead of failing UUID validation.
* "Test connection" validated against the public catalog endpoint (`/plugins`), so invalid API keys reported "Connected". Now uses the authenticated `/me/subscriptions` endpoint; a 401 response produces "Invalid API key".
* "Test connection" read the key from saved options only — entering a new key and testing before saving always tested the old (or empty) key. The AJAX handler now accepts the key from the form field.
**Added**
* `settings_errors()` call on the settings page so validation messages (e.g. "invalid API key format") are actually visible to the user.
* Registration link (`https://www.robotstxt.software/wp-login.php?action=register`) in the API key field description.
**Tests**
* PHPCS (WordPress-Core, WordPress-Docs, WordPress-Extra): pass
* PHPStan level 9 + wp-compat: pass
* PHPUnit: 146 tests, 385 assertions
= 1.4.1 =
_Release date: 2026-08-17_

View file

@ -149,7 +149,7 @@ class Robotstxt_Manager_Core_Client {
);
}
$response = $this->get( '/plugins' );
$response = $this->get( '/me/subscriptions' );
if ( is_wp_error( $response ) ) {
return array(
@ -161,6 +161,13 @@ class Robotstxt_Manager_Core_Client {
$code = (int) wp_remote_retrieve_response_code( $response );
if ( 401 === $code ) {
return array(
'ok' => false,
'message' => __( 'Invalid API key. Please check your key and try again.', 'robotstxt-manager' ),
);
}
if ( 200 !== $code ) {
return array(
'ok' => false,
@ -175,7 +182,7 @@ class Robotstxt_Manager_Core_Client {
return array(
'ok' => true,
'message' => __( 'Connected.', 'robotstxt-manager' ),
'catalog_count' => $count,
'subscriptions' => $count,
);
}

View file

@ -2,7 +2,7 @@
# This file is distributed under the GPL-3.0-or-later.
msgid ""
msgstr ""
"Project-Id-Version: Manager (by ROBOTSTXT) 1.4.1\n"
"Project-Id-Version: Manager (by ROBOTSTXT) 1.5.0\n"
"Report-Msgid-Bugs-To: https://www.robotstxt.software/plugins/robotstxt-manager/\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -259,7 +259,7 @@ msgid "A key is stored but could not be decoded. You can replace it by entering
msgstr ""
#: admin/class-robotstxt-manager-settings.php:266
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."
msgid "Account-level API key from the ROBOTSTXT store (<a href=\"%s\" target=\"_blank\" rel=\"noopener\">create your free account there to get one</a>). Optional — the free catalog works without it — but required to link your subscriptions, install premium plugins, and receive their updates. Encrypted before storage."
msgstr ""
#: admin/class-robotstxt-manager-settings.php:298
@ -475,6 +475,10 @@ msgstr ""
msgid "The store responded with HTTP %d. Check the Store URL and API key."
msgstr ""
#: includes/class-robotstxt-manager-core-client.php:164
msgid "Invalid API key. Please check your key and try again."
msgstr ""
#: includes/class-robotstxt-manager-core-client.php:177
msgid "Connected."
msgstr ""

View file

@ -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.4.1
Stable tag: 1.5.0
Requires PHP: 8.0
Version: 1.4.1
Version: 1.5.0
License: GPL-3.0-or-later
License URI: https://www.gnu.org/licenses/gpl-3.0.txt
@ -94,6 +94,16 @@ 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.5.0 =
_Release date: 2026-08-18_
* Fixed: API key not saving when the browser auto-fills the password field with the stored encrypted value.
* Fixed: "Test connection" now validates the API key against an authenticated Core endpoint (`/me/subscriptions`) instead of the public catalog — invalid keys are correctly rejected.
* Fixed: "Test connection" reads the key from the form field, so a key can be tested before saving.
* Added: Validation errors now display on the settings page (missing `settings_errors()` call).
* Added: Registration link in the API key field description.
= 1.4.1 =
_Release date: 2026-08-17_
@ -107,12 +117,6 @@ _Release date: 2026-08-17_
* Premium update URLs carry a short-lived download token (Core 1.9.0+) instead of the API key; automatic fallback on older Core.
= 1.3.1 =
_Release date: 2026-08-17_
* Descriptions render in the admin's language (Core 1.8.0+ `description_translations`), English fallback.
= Previous versions =
If you want to see the full changelog, visit the [plugin page](https://www.robotstxt.software/plugins/robotstxt-manager/).

View file

@ -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.4.1
* Version: 1.5.0
* Requires at least: 4.4
* Requires PHP: 8.0
* Update URI: https://www.robotstxt.software/plugins/robotstxt-manager/
@ -22,7 +22,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
/** Plugin version. */
define( 'ROBOTSTXT_MANAGER_VERSION', '1.4.1' );
define( 'ROBOTSTXT_MANAGER_VERSION', '1.5.0' );
/** Absolute path to the plugin directory, with trailing slash. */
define( 'ROBOTSTXT_MANAGER_DIR', plugin_dir_path( __FILE__ ) );