209 lines
5.9 KiB
PHP
209 lines
5.9 KiB
PHP
<?php
|
|
/**
|
|
* Manager plugin dependency notice.
|
|
*
|
|
* Media Audit ships without a self-updater; updates are delivered by the
|
|
* Manager (by ROBOTSTXT) plugin. This component nudges the administrator
|
|
* when Manager is missing: a dismissible notice on the Plugins page and a
|
|
* permanent inline notice on the plugin Settings pages.
|
|
*
|
|
* @package MediaRightsAudit\Admin
|
|
*/
|
|
|
|
namespace MediaRightsAudit\Admin;
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Shows update-manager dependency notices.
|
|
*/
|
|
final class ManagerNotice {
|
|
|
|
/**
|
|
* Manager plugin folder slug.
|
|
*/
|
|
public const MANAGER_SLUG = 'robotstxt-manager';
|
|
|
|
/**
|
|
* Manager plugin page URL.
|
|
*/
|
|
public const MANAGER_URL = 'https://www.robotstxt.software/plugins/robotstxt-manager/';
|
|
|
|
/**
|
|
* User-meta key that records a dismissed notice (per user).
|
|
*/
|
|
private const DISMISS_KEY = 'robotstxt_mediaaudit_manager_notice_dismissed';
|
|
|
|
/**
|
|
* GET argument used by the dismiss link.
|
|
*/
|
|
private const DISMISS_ARG = 'robotstxt_mediaaudit_dismiss_manager_notice';
|
|
|
|
/**
|
|
* Nonce action for the dismiss link.
|
|
*/
|
|
private const DISMISS_ACTION = 'robotstxt_mediaaudit_dismiss_manager_notice';
|
|
|
|
/**
|
|
* Registers the admin hooks (site and network admin).
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function register_hooks(): void {
|
|
add_action( 'admin_notices', array( __CLASS__, 'render_plugins_page_notice' ) );
|
|
add_action( 'network_admin_notices', array( __CLASS__, 'render_plugins_page_notice' ) );
|
|
add_action( 'admin_init', array( __CLASS__, 'handle_dismiss' ) );
|
|
}
|
|
|
|
/**
|
|
* Indicates whether the Manager plugin is installed and active.
|
|
*
|
|
* Checks site-level and network-wide activation, plus a filter so the
|
|
* Manager itself can report its own state.
|
|
*
|
|
* @return bool True when Manager is active.
|
|
*/
|
|
public static function is_manager_active(): bool {
|
|
if ( ! function_exists( 'is_plugin_active' ) ) {
|
|
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
|
}
|
|
|
|
if ( ! function_exists( 'is_plugin_active' ) ) {
|
|
return false;
|
|
}
|
|
|
|
$active = false;
|
|
|
|
// Canonical main file first (fast path).
|
|
$basename = self::MANAGER_SLUG . '/' . self::MANAGER_SLUG . '.php';
|
|
if ( is_plugin_active( $basename ) || is_plugin_active_for_network( $basename ) ) {
|
|
$active = true;
|
|
}
|
|
|
|
// Cover any other main-file name inside the canonical folder.
|
|
if ( ! $active && function_exists( 'get_plugins' ) ) {
|
|
foreach ( array_keys( get_plugins( '/' . self::MANAGER_SLUG ) ) as $file ) {
|
|
if ( is_plugin_active( self::MANAGER_SLUG . '/' . $file ) ) {
|
|
$active = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filters whether the Manager (by ROBOTSTXT) plugin is active.
|
|
*
|
|
* @param bool $active Whether Manager is detected as active.
|
|
*/
|
|
return (bool) apply_filters( 'robotstxt_mediaaudit_manager_active', $active );
|
|
}
|
|
|
|
/**
|
|
* Renders the dismissible notice on the Plugins page when Manager is missing.
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function render_plugins_page_notice(): void {
|
|
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
|
|
if ( ! $screen instanceof \WP_Screen || ! in_array( $screen->base, array( 'plugins', 'plugins-network' ), true ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( self::is_manager_active() ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! current_user_can( 'install_plugins' ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( '1' === get_user_meta( get_current_user_id(), self::DISMISS_KEY, true ) ) {
|
|
return;
|
|
}
|
|
|
|
$dismiss_url = wp_nonce_url(
|
|
add_query_arg( self::DISMISS_ARG, 1 ),
|
|
self::DISMISS_ACTION
|
|
);
|
|
|
|
echo '<div class="notice notice-warning"><p>'
|
|
. wp_kses( self::message(), array( 'a' => array( 'href' => true ) ) )
|
|
. ' <a href="' . esc_url( $dismiss_url ) . '" class="button button-small">' . esc_html__( 'Dismiss', 'robotstxt-mediaaudit' ) . '</a>'
|
|
. '</p></div>';
|
|
}
|
|
|
|
/**
|
|
* Renders the permanent inline notice for the Settings pages (not dismissible).
|
|
*
|
|
* Used on both the site Settings page and the Network Settings page.
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function render_settings_notice(): void {
|
|
if ( self::is_manager_active() ) {
|
|
return;
|
|
}
|
|
|
|
echo '<div class="notice notice-warning inline" style="margin:16px 0;">'
|
|
. '<p>' . wp_kses( self::message(), array( 'a' => array( 'href' => true ) ) ) . '</p>'
|
|
. '</div>';
|
|
}
|
|
|
|
/**
|
|
* Handles the dismiss link: verifies the nonce, stores the dismissal (PRG).
|
|
*
|
|
* Also clears a stored dismissal once Manager is active again, so the
|
|
* notice returns if Manager is ever removed.
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function handle_dismiss(): void {
|
|
$user_id = get_current_user_id();
|
|
$dismissed = $user_id && get_user_meta( $user_id, self::DISMISS_KEY, true );
|
|
|
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- presence check only; state changes require the nonce below.
|
|
if ( ! isset( $_GET[ self::DISMISS_ARG ] ) && ! $dismissed ) {
|
|
return;
|
|
}
|
|
|
|
if ( self::is_manager_active() ) {
|
|
if ( $dismissed ) {
|
|
delete_user_meta( $user_id, self::DISMISS_KEY );
|
|
}
|
|
return;
|
|
}
|
|
|
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- no state change without the nonce check below.
|
|
if ( ! isset( $_GET[ self::DISMISS_ARG ] ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! current_user_can( 'install_plugins' ) ) {
|
|
return;
|
|
}
|
|
|
|
check_admin_referer( self::DISMISS_ACTION );
|
|
|
|
update_user_meta( $user_id, self::DISMISS_KEY, '1' );
|
|
|
|
wp_safe_redirect( remove_query_arg( array( self::DISMISS_ARG, '_wpnonce' ) ) );
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Builds the shared notice message (translation with a link placeholder).
|
|
*
|
|
* The result must be passed through wp_kses() at output time.
|
|
*
|
|
* @return string Unescaped message HTML.
|
|
*/
|
|
private static function message(): string {
|
|
return sprintf(
|
|
/* translators: %s: Manager plugin page URL. */
|
|
__( 'To receive plugin updates, the plugin <a href="%s">Manager (by ROBOTSTXT)</a> must be installed and active.', 'robotstxt-mediaaudit' ),
|
|
esc_url( self::MANAGER_URL )
|
|
);
|
|
}
|
|
}
|