robotstxt-2fa/includes/admin/class-manager-notice.php
2026-08-24 08:18:14 +00:00

198 lines
4.9 KiB
PHP

<?php
/**
* Manager plugin dependency notice.
*
* @package Robotstxt_2FA
*/
namespace Robotstxt\TwoFA\Admin;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Notifies administrators when the Manager (by ROBOTSTXT) plugin is missing.
*
* The Manager plugin delivers updates for ROBOTSTXT plugins. Without it, this
* plugin cannot receive updates. A dismissible notice is shown on the plugins
* list screen and a persistent notice is rendered on the plugin settings page.
*/
class Manager_Notice {
/**
* URL of the Manager plugin page.
*/
private const MANAGER_URL = 'https://www.robotstxt.software/plugins/robotstxt-manager/';
/**
* Action used to dismiss the plugins screen notice.
*/
private const DISMISS_ACTION = 'robotstxt_2fa_dismiss_manager_notice';
/**
* User meta key storing the dismissal flag.
*/
private const DISMISSED_META_KEY = 'robotstxt_2fa_manager_notice_dismissed';
/**
* Register WordPress hooks.
*
* @since 1.6.2
*
* @return void
*/
public function register_hooks(): void {
add_action( 'admin_notices', array( $this, 'maybe_show_plugins_notice' ) );
add_action( 'network_admin_notices', array( $this, 'maybe_show_plugins_notice' ) );
add_action( 'admin_init', array( $this, 'maybe_handle_dismiss' ) );
}
/**
* Whether the Manager (by ROBOTSTXT) plugin is active.
*
* Uses the ecosystem presence constant (Manager 1.6.2+) and falls back
* to a plugin-list scan for older Manager versions.
*
* @since 1.6.2
*
* @return bool True when the Manager plugin is present and activated.
*/
public static function is_manager_active(): bool {
if ( defined( 'ROBOTSTXT_MANAGER_NOTICED' ) && ROBOTSTXT_MANAGER_NOTICED ) {
return true;
}
if ( ! function_exists( 'get_plugins' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
foreach ( get_plugins() as $file => $data ) {
$slug = dirname( $file );
if ( '.' === $slug ) {
$slug = basename( $file, '.php' );
}
if ( 'robotstxt-manager' === $slug ) {
return is_plugin_active( $file );
}
}
return false;
}
/**
* Show a dismissible notice on the plugins list screen when the manager is missing.
*
* @since 1.6.2
*
* @return void
*/
public function maybe_show_plugins_notice(): void {
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
if ( null === $screen ) {
return;
}
if ( ! in_array( $screen->id, array( 'plugins', 'plugins-network' ), true ) ) {
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
if ( self::is_manager_active() ) {
return;
}
if ( get_user_meta( get_current_user_id(), self::DISMISSED_META_KEY, true ) ) {
return;
}
$dismiss_url = wp_nonce_url(
add_query_arg( 'action', self::DISMISS_ACTION, self_admin_url( 'admin.php' ) ),
self::DISMISS_ACTION
);
?>
<div class="notice notice-warning">
<p>
<strong><?php esc_html_e( '2FA (by ROBOTSTXT):', 'robotstxt-2fa' ); ?></strong>
<?php
echo wp_kses_post(
sprintf(
/* translators: %s: URL of the Manager (by ROBOTSTXT) plugin page. */
__( 'This plugin needs <a href="%s">Manager (by ROBOTSTXT)</a> to be installed and active to receive updates.', 'robotstxt-2fa' ),
esc_url( self::MANAGER_URL )
)
);
?>
</p>
<p style="margin-top:0;">
<a href="<?php echo esc_url( $dismiss_url ); ?>" style="font-size:0.875em;"><?php esc_html_e( 'Dismiss this notice', 'robotstxt-2fa' ); ?></a>
</p>
</div>
<?php
}
/**
* Render the persistent manager notice shown on the plugin settings page.
*
* @since 1.6.2
*
* @return void
*/
public static function render_settings_notice(): void {
if ( self::is_manager_active() ) {
return;
}
?>
<div class="notice notice-warning inline">
<p>
<strong><?php esc_html_e( 'Manager (by ROBOTSTXT) is not active.', 'robotstxt-2fa' ); ?></strong>
<?php
echo wp_kses_post(
sprintf(
/* translators: %s: URL of the Manager (by ROBOTSTXT) plugin page. */
__( 'This plugin needs <a href="%s">Manager (by ROBOTSTXT)</a> to be installed and active to receive updates.', 'robotstxt-2fa' ),
esc_url( self::MANAGER_URL )
)
);
?>
</p>
</div>
<?php
}
/**
* Handle the dismiss-notice GET request.
*
* @since 1.6.2
*
* @return void
*/
public function maybe_handle_dismiss(): void {
if ( ! isset( $_GET['action'] ) || self::DISMISS_ACTION !== $_GET['action'] ) {
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$nonce_raw = isset( $_GET['_wpnonce'] ) && is_string( $_GET['_wpnonce'] )
? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) )
: '';
if ( ! wp_verify_nonce( $nonce_raw, self::DISMISS_ACTION ) ) {
return;
}
update_user_meta( get_current_user_id(), self::DISMISSED_META_KEY, 1 );
wp_safe_redirect( remove_query_arg( array( 'action', '_wpnonce' ) ) );
exit;
}
}