diff --git a/admin/class-robotstxt-manager-admin.php b/admin/class-robotstxt-manager-admin.php
index 1921cc6..ef4ef1a 100644
--- a/admin/class-robotstxt-manager-admin.php
+++ b/admin/class-robotstxt-manager-admin.php
@@ -33,8 +33,11 @@ class Robotstxt_Manager_Admin {
* @return void
*/
public function register( Robotstxt_Manager_Loader $loader ): void {
- $loader->add_action( 'admin_menu', $this, 'add_menu' );
+ $menu_hook = is_multisite() ? 'network_admin_menu' : 'admin_menu';
+ $loader->add_action( $menu_hook, $this, 'add_menu' );
$loader->add_action( 'admin_post_robotstxt_manager_refresh_catalog', $this, 'handle_refresh' );
+ $loader->add_action( 'admin_notices', $this, 'security_update_notices' );
+ $loader->add_action( 'network_admin_notices', $this, 'security_update_notices' );
}
/**
@@ -43,10 +46,11 @@ class Robotstxt_Manager_Admin {
* @return void
*/
public function add_menu(): void {
+ $cap = is_multisite() ? 'manage_network_options' : 'manage_options';
add_menu_page(
esc_html__( 'Manager (by ROBOTSTXT) — Plugins', 'robotstxt-manager' ),
esc_html__( 'ROBOTSTXT', 'robotstxt-manager' ),
- 'manage_options',
+ $cap,
self::PAGE_SLUG,
array( $this, 'render_page' ),
'dashicons-screenoptions',
@@ -60,7 +64,7 @@ class Robotstxt_Manager_Admin {
* @return void
*/
public function render_page(): void {
- if ( ! current_user_can( 'manage_options' ) ) {
+ if ( ! current_user_can( is_multisite() ? 'manage_network_options' : 'manage_options' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'robotstxt-manager' ) );
}
@@ -75,9 +79,103 @@ class Robotstxt_Manager_Admin {
$manager_has_api_key = $client->has_api_key();
$manager_store_url = $client->get_store_url();
+ // Security patches declared for exactly the versions this site runs.
+ $manager_security_updates = $this->get_security_updates( $catalog, $local );
+
require ROBOTSTXT_MANAGER_DIR . 'admin/views/page-catalog.php';
}
+ /**
+ * Returns the security patches that apply to the exact versions this
+ * site runs (Core 1.16.0+ `security_patches` catalog data).
+ *
+ * @param list ';
+ echo wp_kses_post(
+ sprintf(
+ /* translators: 1: plugin name, 2: installed version, 3: patch version, 4: update URL. */
+ __( 'Security update available: %1$s (v%2$s → v%3$s). Update now — this is a security patch for the version this site runs, not a feature update.', 'robotstxt-manager' ),
+ esc_html( $update['name'] ),
+ esc_html( $update['installed'] ),
+ esc_html( $update['patch'] ),
+ esc_url( self::action_url( 'update', $update['slug'] ) )
+ )
+ );
+ 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' ) . '
'; + printf( + '%s
', + wp_kses_post( + sprintf( + /* translators: %s: Registration URL. */ + __( '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' ), + esc_url( 'https://www.robotstxt.software/wp-login.php?action=register' ) + ) + ) + ); } // Action buttons. @@ -288,7 +363,7 @@ class Robotstxt_Manager_Settings { * @return void */ public function render_field_cache_ttl(): void { - $raw = get_option( 'robotstxt_manager_cache_ttl_minutes', 60 ); + $raw = get_site_option( 'robotstxt_manager_cache_ttl_minutes', 60 ); $value = is_numeric( $raw ) ? (int) $raw : 60; printf( @@ -304,7 +379,7 @@ class Robotstxt_Manager_Settings { * @return void */ public function render_field_delete_on_uninstall(): void { - $value = (bool) get_option( 'robotstxt_manager_delete_data_on_uninstall', false ); + $value = (bool) get_site_option( 'robotstxt_manager_delete_data_on_uninstall', false ); echo '