notice.php

I’ll build this as a full reusable inc/admin/notice.php module for your RX theme: admin notices, dismissible notices, theme checks, plugin recommendations, update/security warnings, dashboard notices, and safe option-based dismiss logic.

Below is an advanced inc/admin/notice.php file for your RX Theme. It includes many possible admin notice features: welcome notice, theme setup warnings, required/recommended plugin notices, PHP/WordPress version notices, SSL notice, permalink notice, debug notice, upload directory notice, dismissed notice memory, admin dashboard widget, AJAX dismiss system, and helper functions.

Create this file:

<?php
/**
 * RX Theme Admin Notices
 *
 * File: inc/admin/notice.php
 *
 * @package RX_Theme
 */

defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'RX_Theme_Admin_Notices' ) ) :

final class RX_Theme_Admin_Notices {

	/**
	 * Option key for dismissed notices.
	 */
	const DISMISSED_OPTION = 'rx_theme_dismissed_admin_notices';

	/**
	 * Theme slug.
	 */
	const THEME_SLUG = 'rx-theme';

	/**
	 * Minimum PHP version.
	 */
	const MIN_PHP_VERSION = '7.4';

	/**
	 * Minimum WordPress version.
	 */
	const MIN_WP_VERSION = '6.0';

	/**
	 * Initialize hooks.
	 */
	public static function init() {
		add_action( 'admin_init', array( __CLASS__, 'maybe_set_activation_notice' ) );
		add_action( 'admin_notices', array( __CLASS__, 'render_admin_notices' ) );
		add_action( 'network_admin_notices', array( __CLASS__, 'render_network_admin_notices' ) );
		add_action( 'wp_ajax_rx_theme_dismiss_notice', array( __CLASS__, 'ajax_dismiss_notice' ) );
		add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_admin_assets' ) );
		add_action( 'wp_dashboard_setup', array( __CLASS__, 'register_dashboard_widget' ) );
		add_action( 'admin_menu', array( __CLASS__, 'register_notice_page' ) );
	}

	/**
	 * Add activation notice once after theme activation.
	 */
	public static function maybe_set_activation_notice() {
		if ( get_option( 'rx_theme_activation_notice_shown' ) ) {
			return;
		}

		set_transient( 'rx_theme_show_welcome_notice', 1, DAY_IN_SECONDS );
		update_option( 'rx_theme_activation_notice_shown', 1, false );
	}

	/**
	 * Enqueue small inline admin JS/CSS.
	 */
	public static function enqueue_admin_assets( $hook ) {
		if ( ! is_admin() ) {
			return;
		}

		wp_register_script(
			'rx-theme-admin-notice',
			'',
			array( 'jquery' ),
			defined( 'RX_THEME_VERSION' ) ? RX_THEME_VERSION : '1.0.0',
			true
		);

		wp_enqueue_script( 'rx-theme-admin-notice' );

		wp_localize_script(
			'rx-theme-admin-notice',
			'rxThemeNotice',
			array(
				'ajaxUrl' => admin_url( 'admin-ajax.php' ),
				'nonce'   => wp_create_nonce( 'rx_theme_dismiss_notice_nonce' ),
			)
		);

		$js = "
		jQuery(document).on('click', '.rx-notice .notice-dismiss, .rx-dismiss-notice', function(e) {
			var notice = jQuery(this).closest('.rx-notice');
			var noticeId = notice.data('notice-id');

			if (!noticeId) {
				return;
			}

			jQuery.post(rxThemeNotice.ajaxUrl, {
				action: 'rx_theme_dismiss_notice',
				nonce: rxThemeNotice.nonce,
				notice_id: noticeId
			});
		});
		";

		wp_add_inline_script( 'rx-theme-admin-notice', $js );

		wp_register_style(
			'rx-theme-admin-notice-style',
			false,
			array(),
			defined( 'RX_THEME_VERSION' ) ? RX_THEME_VERSION : '1.0.0'
		);

		wp_enqueue_style( 'rx-theme-admin-notice-style' );

		$css = "
		.rx-notice {
			border-left-width: 4px;
		}
		.rx-notice .rx-notice-title {
			font-size: 15px;
			font-weight: 700;
			margin: 0 0 6px;
		}
		.rx-notice .rx-notice-actions {
			margin-top: 10px;
		}
		.rx-notice .button {
			margin-right: 6px;
		}
		.rx-theme-dashboard-widget ul {
			margin-left: 18px;
			list-style: disc;
		}
		.rx-theme-status-good {
			color: #008a20;
			font-weight: 600;
		}
		.rx-theme-status-warning {
			color: #b26200;
			font-weight: 600;
		}
		.rx-theme-status-danger {
			color: #b32d2e;
			font-weight: 600;
		}
		";

		wp_add_inline_style( 'rx-theme-admin-notice-style', $css );
	}

	/**
	 * Main notice renderer.
	 */
	public static function render_admin_notices() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		self::welcome_notice();
		self::php_version_notice();
		self::wordpress_version_notice();
		self::ssl_notice();
		self::permalink_notice();
		self::debug_mode_notice();
		self::missing_homepage_notice();
		self::site_icon_notice();
		self::timezone_notice();
		self::upload_directory_notice();
		self::required_plugins_notice();
		self::recommended_plugins_notice();
		self::woocommerce_notice();
		self::elementor_notice();
		self::seo_plugin_notice();
		self::cache_plugin_notice();
		self::security_plugin_notice();
		self::backup_plugin_notice();
		self::theme_file_permission_notice();
		self::memory_limit_notice();
		self::maintenance_mode_notice();
		self::discourage_search_engine_notice();
	}

	/**
	 * Network admin notice renderer.
	 */
	public static function render_network_admin_notices() {
		if ( ! current_user_can( 'manage_network_options' ) ) {
			return;
		}

		self::render_notice(
			'rx-network-theme-notice',
			'info',
			__( 'RX Theme Network Notice', 'rx-theme' ),
			__( 'RX Theme is active in a multisite environment. Please make sure all child sites use compatible plugins, SSL, caching, and security settings.', 'rx-theme' ),
			true
		);
	}

	/**
	 * Welcome notice after activation.
	 */
	public static function welcome_notice() {
		if ( ! get_transient( 'rx_theme_show_welcome_notice' ) ) {
			return;
		}

		if ( self::is_dismissed( 'rx-welcome-notice' ) ) {
			return;
		}

		$message = sprintf(
			wp_kses_post(
				__( 'Thank you for activating <strong>RX Theme</strong>. You can now configure theme options, menus, widgets, homepage settings, performance options, and SEO settings.', 'rx-theme' )
			)
		);

		$actions = array(
			array(
				'label' => __( 'Customize Theme', 'rx-theme' ),
				'url'   => admin_url( 'customize.php' ),
				'class' => 'button button-primary',
			),
			array(
				'label' => __( 'Theme Notices', 'rx-theme' ),
				'url'   => admin_url( 'themes.php?page=rx-theme-notices' ),
				'class' => 'button',
			),
		);

		self::render_notice( 'rx-welcome-notice', 'success', __( 'Welcome to RX Theme', 'rx-theme' ), $message, true, $actions );
	}

	/**
	 * PHP version warning.
	 */
	public static function php_version_notice() {
		if ( version_compare( PHP_VERSION, self::MIN_PHP_VERSION, '>=' ) ) {
			return;
		}

		self::render_notice(
			'rx-php-version-notice',
			'error',
			__( 'PHP Version Too Old', 'rx-theme' ),
			sprintf(
				esc_html__( 'RX Theme recommends PHP %1$s or higher. Your server is using PHP %2$s. Please update PHP from your hosting control panel.', 'rx-theme' ),
				esc_html( self::MIN_PHP_VERSION ),
				esc_html( PHP_VERSION )
			),
			false
		);
	}

	/**
	 * WordPress version warning.
	 */
	public static function wordpress_version_notice() {
		global $wp_version;

		if ( version_compare( $wp_version, self::MIN_WP_VERSION, '>=' ) ) {
			return;
		}

		self::render_notice(
			'rx-wp-version-notice',
			'error',
			__( 'WordPress Version Too Old', 'rx-theme' ),
			sprintf(
				esc_html__( 'RX Theme recommends WordPress %1$s or higher. Your site is using WordPress %2$s. Please update WordPress for better security and compatibility.', 'rx-theme' ),
				esc_html( self::MIN_WP_VERSION ),
				esc_html( $wp_version )
			),
			false
		);
	}

	/**
	 * SSL notice.
	 */
	public static function ssl_notice() {
		if ( is_ssl() || self::is_dismissed( 'rx-ssl-notice' ) ) {
			return;
		}

		self::render_notice(
			'rx-ssl-notice',
			'warning',
			__( 'SSL Is Not Active', 'rx-theme' ),
			__( 'Your website is not loading through HTTPS. SSL is important for SEO, security, login protection, and user trust. Please enable SSL from your hosting panel.', 'rx-theme' ),
			true
		);
	}

	/**
	 * Permalink notice.
	 */
	public static function permalink_notice() {
		if ( get_option( 'permalink_structure' ) || self::is_dismissed( 'rx-permalink-notice' ) ) {
			return;
		}

		$actions = array(
			array(
				'label' => __( 'Open Permalink Settings', 'rx-theme' ),
				'url'   => admin_url( 'options-permalink.php' ),
				'class' => 'button button-primary',
			),
		);

		self::render_notice(
			'rx-permalink-notice',
			'warning',
			__( 'Pretty Permalinks Are Disabled', 'rx-theme' ),
			__( 'Your site is using plain permalink structure. For better SEO and clean URLs, use Post name permalink structure.', 'rx-theme' ),
			true,
			$actions
		);
	}

	/**
	 * Debug mode notice.
	 */
	public static function debug_mode_notice() {
		if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG || self::is_dismissed( 'rx-debug-notice' ) ) {
			return;
		}

		self::render_notice(
			'rx-debug-notice',
			'warning',
			__( 'WP_DEBUG Is Enabled', 'rx-theme' ),
			__( 'Debug mode is active. This is useful during development, but on a live website it may expose technical information. Disable WP_DEBUG on production.', 'rx-theme' ),
			true
		);
	}

	/**
	 * Homepage notice.
	 */
	public static function missing_homepage_notice() {
		if ( self::is_dismissed( 'rx-homepage-notice' ) ) {
			return;
		}

		$show_on_front = get_option( 'show_on_front' );
		$page_on_front = get_option( 'page_on_front' );

		if ( 'page' === $show_on_front && ! empty( $page_on_front ) ) {
			return;
		}

		$actions = array(
			array(
				'label' => __( 'Set Homepage', 'rx-theme' ),
				'url'   => admin_url( 'options-reading.php' ),
				'class' => 'button button-primary',
			),
		);

		self::render_notice(
			'rx-homepage-notice',
			'info',
			__( 'Homepage Is Not Set', 'rx-theme' ),
			__( 'For a professional website layout, you may set a static homepage from Reading Settings.', 'rx-theme' ),
			true,
			$actions
		);
	}

	/**
	 * Site icon notice.
	 */
	public static function site_icon_notice() {
		if ( has_site_icon() || self::is_dismissed( 'rx-site-icon-notice' ) ) {
			return;
		}

		$actions = array(
			array(
				'label' => __( 'Add Site Icon', 'rx-theme' ),
				'url'   => admin_url( 'customize.php?autofocus[section]=title_tagline' ),
				'class' => 'button button-primary',
			),
		);

		self::render_notice(
			'rx-site-icon-notice',
			'info',
			__( 'Site Icon Missing', 'rx-theme' ),
			__( 'Your website does not have a site icon/favicon yet. Add one to improve branding in browser tabs, bookmarks, and mobile devices.', 'rx-theme' ),
			true,
			$actions
		);
	}

	/**
	 * Timezone notice.
	 */
	public static function timezone_notice() {
		if ( self::is_dismissed( 'rx-timezone-notice' ) ) {
			return;
		}

		$timezone = get_option( 'timezone_string' );

		if ( ! empty( $timezone ) ) {
			return;
		}

		$actions = array(
			array(
				'label' => __( 'Set Timezone', 'rx-theme' ),
				'url'   => admin_url( 'options-general.php' ),
				'class' => 'button button-primary',
			),
		);

		self::render_notice(
			'rx-timezone-notice',
			'info',
			__( 'Timezone Is Not Properly Set', 'rx-theme' ),
			__( 'Your WordPress timezone is not set by city. Setting the correct timezone helps scheduled posts, cron jobs, analytics, and logs.', 'rx-theme' ),
			true,
			$actions
		);
	}

	/**
	 * Upload directory notice.
	 */
	public static function upload_directory_notice() {
		if ( self::is_dismissed( 'rx-upload-dir-notice' ) ) {
			return;
		}

		$upload_dir = wp_upload_dir();

		if ( empty( $upload_dir['error'] ) ) {
			return;
		}

		self::render_notice(
			'rx-upload-dir-notice',
			'error',
			__( 'Upload Directory Problem', 'rx-theme' ),
			sprintf(
				esc_html__( 'WordPress upload directory has a problem: %s', 'rx-theme' ),
				esc_html( $upload_dir['error'] )
			),
			true
		);
	}

	/**
	 * Required plugin notice.
	 */
	public static function required_plugins_notice() {
		if ( self::is_dismissed( 'rx-required-plugins-notice' ) ) {
			return;
		}

		$missing = array();

		if ( ! self::is_plugin_active_by_file( 'classic-editor/classic-editor.php' ) ) {
			$missing[] = 'Classic Editor';
		}

		if ( empty( $missing ) ) {
			return;
		}

		self::render_notice(
			'rx-required-plugins-notice',
			'warning',
			__( 'RX Theme Required/Useful Plugins Missing', 'rx-theme' ),
			sprintf(
				esc_html__( 'For the best editing experience, you may install: %s.', 'rx-theme' ),
				esc_html( implode( ', ', $missing ) )
			),
			true
		);
	}

	/**
	 * Recommended plugin notice.
	 */
	public static function recommended_plugins_notice() {
		if ( self::is_dismissed( 'rx-recommended-plugins-notice' ) ) {
			return;
		}

		$recommended = array();

		if ( ! self::has_any_active_plugin(
			array(
				'wordpress-seo/wp-seo.php',
				'rank-math/rank-math.php',
				'all-in-one-seo-pack/all_in_one_seo_pack.php',
			)
		) ) {
			$recommended[] = 'SEO plugin';
		}

		if ( ! self::has_any_active_plugin(
			array(
				'wordfence/wordfence.php',
				'better-wp-security/better-wp-security.php',
				'sucuri-scanner/sucuri.php',
			)
		) ) {
			$recommended[] = 'Security plugin';
		}

		if ( ! self::has_any_active_plugin(
			array(
				'wp-super-cache/wp-cache.php',
				'w3-total-cache/w3-total-cache.php',
				'litespeed-cache/litespeed-cache.php',
				'wp-rocket/wp-rocket.php',
			)
		) ) {
			$recommended[] = 'Cache plugin';
		}

		if ( empty( $recommended ) ) {
			return;
		}

		$actions = array(
			array(
				'label' => __( 'Install Plugins', 'rx-theme' ),
				'url'   => admin_url( 'plugin-install.php' ),
				'class' => 'button button-primary',
			),
		);

		self::render_notice(
			'rx-recommended-plugins-notice',
			'info',
			__( 'Recommended Plugins for RX Theme', 'rx-theme' ),
			sprintf(
				esc_html__( 'For better SEO, speed, and security, you may add: %s.', 'rx-theme' ),
				esc_html( implode( ', ', $recommended ) )
			),
			true,
			$actions
		);
	}

	/**
	 * WooCommerce notice.
	 */
	public static function woocommerce_notice() {
		if ( self::is_dismissed( 'rx-woocommerce-notice' ) ) {
			return;
		}

		if ( class_exists( 'WooCommerce' ) ) {
			return;
		}

		if ( ! current_theme_supports( 'woocommerce' ) ) {
			return;
		}

		self::render_notice(
			'rx-woocommerce-notice',
			'info',
			__( 'WooCommerce Support Available', 'rx-theme' ),
			__( 'RX Theme supports WooCommerce layout. Install WooCommerce only if you want to create an online store.', 'rx-theme' ),
			true
		);
	}

	/**
	 * Elementor notice.
	 */
	public static function elementor_notice() {
		if ( self::is_dismissed( 'rx-elementor-notice' ) ) {
			return;
		}

		if ( did_action( 'elementor/loaded' ) ) {
			return;
		}

		self::render_notice(
			'rx-elementor-notice',
			'info',
			__( 'Page Builder Optional', 'rx-theme' ),
			__( 'RX Theme can work with Elementor or other page builders, but it is optional. Use it only if you need drag-and-drop design.', 'rx-theme' ),
			true
		);
	}

	/**
	 * SEO plugin notice.
	 */
	public static function seo_plugin_notice() {
		if ( self::is_dismissed( 'rx-seo-plugin-notice' ) ) {
			return;
		}

		if ( self::has_any_active_plugin(
			array(
				'wordpress-seo/wp-seo.php',
				'rank-math/rank-math.php',
				'all-in-one-seo-pack/all_in_one_seo_pack.php',
			)
		) ) {
			return;
		}

		self::render_notice(
			'rx-seo-plugin-notice',
			'info',
			__( 'SEO Plugin Not Detected', 'rx-theme' ),
			__( 'For better search visibility, XML sitemap, meta title, meta description, Open Graph, and schema control, install a trusted SEO plugin.', 'rx-theme' ),
			true
		);
	}

	/**
	 * Cache plugin notice.
	 */
	public static function cache_plugin_notice() {
		if ( self::is_dismissed( 'rx-cache-plugin-notice' ) ) {
			return;
		}

		if ( self::has_any_active_plugin(
			array(
				'wp-super-cache/wp-cache.php',
				'w3-total-cache/w3-total-cache.php',
				'litespeed-cache/litespeed-cache.php',
				'wp-rocket/wp-rocket.php',
				'autoptimize/autoptimize.php',
			)
		) ) {
			return;
		}

		self::render_notice(
			'rx-cache-plugin-notice',
			'info',
			__( 'Cache Plugin Not Detected', 'rx-theme' ),
			__( 'A cache/performance plugin can improve page speed, Core Web Vitals, CSS/JS optimization, and user experience.', 'rx-theme' ),
			true
		);
	}

	/**
	 * Security plugin notice.
	 */
	public static function security_plugin_notice() {
		if ( self::is_dismissed( 'rx-security-plugin-notice' ) ) {
			return;
		}

		if ( self::has_any_active_plugin(
			array(
				'wordfence/wordfence.php',
				'better-wp-security/better-wp-security.php',
				'sucuri-scanner/sucuri.php',
			)
		) ) {
			return;
		}

		self::render_notice(
			'rx-security-plugin-notice',
			'warning',
			__( 'Security Plugin Not Detected', 'rx-theme' ),
			__( 'For login protection, firewall, malware scanning, and brute-force protection, consider adding a security plugin.', 'rx-theme' ),
			true
		);
	}

	/**
	 * Backup plugin notice.
	 */
	public static function backup_plugin_notice() {
		if ( self::is_dismissed( 'rx-backup-plugin-notice' ) ) {
			return;
		}

		if ( self::has_any_active_plugin(
			array(
				'updraftplus/updraftplus.php',
				'backwpup/backwpup.php',
				'duplicator/duplicator.php',
			)
		) ) {
			return;
		}

		self::render_notice(
			'rx-backup-plugin-notice',
			'info',
			__( 'Backup Plugin Not Detected', 'rx-theme' ),
			__( 'Regular backups protect your website from hosting problems, hacking, mistakes, and failed updates.', 'rx-theme' ),
			true
		);
	}

	/**
	 * Theme file permission notice.
	 */
	public static function theme_file_permission_notice() {
		if ( self::is_dismissed( 'rx-theme-permission-notice' ) ) {
			return;
		}

		$stylesheet_dir = get_stylesheet_directory();

		if ( is_readable( $stylesheet_dir ) ) {
			return;
		}

		self::render_notice(
			'rx-theme-permission-notice',
			'error',
			__( 'Theme Directory Permission Issue', 'rx-theme' ),
			__( 'RX Theme directory is not readable by WordPress. Please check your file permissions from hosting file manager or FTP.', 'rx-theme' ),
			true
		);
	}

	/**
	 * Memory limit notice.
	 */
	public static function memory_limit_notice() {
		if ( self::is_dismissed( 'rx-memory-limit-notice' ) ) {
			return;
		}

		$memory_limit = wp_convert_hr_to_bytes( WP_MEMORY_LIMIT );
		$recommended  = 128 * MB_IN_BYTES;

		if ( $memory_limit >= $recommended ) {
			return;
		}

		self::render_notice(
			'rx-memory-limit-notice',
			'warning',
			__( 'Low WordPress Memory Limit', 'rx-theme' ),
			sprintf(
				esc_html__( 'Your WordPress memory limit is %s. RX Theme recommends at least 128M for better admin performance.', 'rx-theme' ),
				esc_html( WP_MEMORY_LIMIT )
			),
			true
		);
	}

	/**
	 * Maintenance mode notice.
	 */
	public static function maintenance_mode_notice() {
		if ( ! file_exists( ABSPATH . '.maintenance' ) ) {
			return;
		}

		self::render_notice(
			'rx-maintenance-mode-notice',
			'warning',
			__( 'Maintenance File Detected', 'rx-theme' ),
			__( 'A .maintenance file exists in your WordPress root directory. If your site is stuck in maintenance mode, remove that file carefully.', 'rx-theme' ),
			false
		);
	}

	/**
	 * Search engine visibility notice.
	 */
	public static function discourage_search_engine_notice() {
		if ( self::is_dismissed( 'rx-search-engine-notice' ) ) {
			return;
		}

		if ( ! get_option( 'blog_public' ) ) {
			$actions = array(
				array(
					'label' => __( 'Open Reading Settings', 'rx-theme' ),
					'url'   => admin_url( 'options-reading.php' ),
					'class' => 'button button-primary',
				),
			);

			self::render_notice(
				'rx-search-engine-notice',
				'warning',
				__( 'Search Engines Are Discouraged', 'rx-theme' ),
				__( 'Your website currently discourages search engines from indexing it. If this is a live website, enable search engine visibility.', 'rx-theme' ),
				true,
				$actions
			);
		}
	}

	/**
	 * Register dashboard widget.
	 */
	public static function register_dashboard_widget() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		wp_add_dashboard_widget(
			'rx_theme_status_widget',
			__( 'RX Theme Status', 'rx-theme' ),
			array( __CLASS__, 'render_dashboard_widget' )
		);
	}

	/**
	 * Dashboard widget content.
	 */
	public static function render_dashboard_widget() {
		?>
		<div class="rx-theme-dashboard-widget">
			<p><strong><?php esc_html_e( 'Website health quick overview:', 'rx-theme' ); ?></strong></p>

			<ul>
				<li>
					<?php esc_html_e( 'PHP Version:', 'rx-theme' ); ?>
					<?php if ( version_compare( PHP_VERSION, self::MIN_PHP_VERSION, '>=' ) ) : ?>
						<span class="rx-theme-status-good"><?php echo esc_html( PHP_VERSION ); ?></span>
					<?php else : ?>
						<span class="rx-theme-status-danger"><?php echo esc_html( PHP_VERSION ); ?></span>
					<?php endif; ?>
				</li>

				<li>
					<?php esc_html_e( 'SSL:', 'rx-theme' ); ?>
					<?php if ( is_ssl() ) : ?>
						<span class="rx-theme-status-good"><?php esc_html_e( 'Enabled', 'rx-theme' ); ?></span>
					<?php else : ?>
						<span class="rx-theme-status-warning"><?php esc_html_e( 'Not enabled', 'rx-theme' ); ?></span>
					<?php endif; ?>
				</li>

				<li>
					<?php esc_html_e( 'Permalinks:', 'rx-theme' ); ?>
					<?php if ( get_option( 'permalink_structure' ) ) : ?>
						<span class="rx-theme-status-good"><?php esc_html_e( 'Pretty URLs enabled', 'rx-theme' ); ?></span>
					<?php else : ?>
						<span class="rx-theme-status-warning"><?php esc_html_e( 'Plain URLs', 'rx-theme' ); ?></span>
					<?php endif; ?>
				</li>

				<li>
					<?php esc_html_e( 'Search Engine Visibility:', 'rx-theme' ); ?>
					<?php if ( get_option( 'blog_public' ) ) : ?>
						<span class="rx-theme-status-good"><?php esc_html_e( 'Indexing allowed', 'rx-theme' ); ?></span>
					<?php else : ?>
						<span class="rx-theme-status-danger"><?php esc_html_e( 'Indexing discouraged', 'rx-theme' ); ?></span>
					<?php endif; ?>
				</li>

				<li>
					<?php esc_html_e( 'Site Icon:', 'rx-theme' ); ?>
					<?php if ( has_site_icon() ) : ?>
						<span class="rx-theme-status-good"><?php esc_html_e( 'Added', 'rx-theme' ); ?></span>
					<?php else : ?>
						<span class="rx-theme-status-warning"><?php esc_html_e( 'Missing', 'rx-theme' ); ?></span>
					<?php endif; ?>
				</li>
			</ul>

			<p>
				<a class="button button-primary" href="<?php echo esc_url( admin_url( 'themes.php?page=rx-theme-notices' ) ); ?>">
					<?php esc_html_e( 'Open RX Theme Notices', 'rx-theme' ); ?>
				</a>
				<a class="button" href="<?php echo esc_url( admin_url( 'customize.php' ) ); ?>">
					<?php esc_html_e( 'Customize Theme', 'rx-theme' ); ?>
				</a>
			</p>
		</div>
		<?php
	}

	/**
	 * Register notice page.
	 */
	public static function register_notice_page() {
		add_theme_page(
			__( 'RX Theme Notices', 'rx-theme' ),
			__( 'RX Notices', 'rx-theme' ),
			'manage_options',
			'rx-theme-notices',
			array( __CLASS__, 'render_notice_page' )
		);
	}

	/**
	 * Render notice management page.
	 */
	public static function render_notice_page() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		if ( isset( $_POST['rx_reset_notices'] ) && check_admin_referer( 'rx_reset_notices_action', 'rx_reset_notices_nonce' ) ) {
			delete_option( self::DISMISSED_OPTION );
			delete_transient( 'rx_theme_show_welcome_notice' );

			echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'RX Theme notices have been reset.', 'rx-theme' ) . '</p></div>';
		}

		$dismissed = self::get_dismissed_notices();
		?>
		<div class="wrap">
			<h1><?php esc_html_e( 'RX Theme Notices', 'rx-theme' ); ?></h1>

			<p>
				<?php esc_html_e( 'This page helps you manage RX Theme admin notices, dismissed warnings, and site health recommendations.', 'rx-theme' ); ?>
			</p>

			<h2><?php esc_html_e( 'Dismissed Notices', 'rx-theme' ); ?></h2>

			<?php if ( empty( $dismissed ) ) : ?>
				<p><?php esc_html_e( 'No dismissed notices found.', 'rx-theme' ); ?></p>
			<?php else : ?>
				<ul>
					<?php foreach ( $dismissed as $notice_id => $time ) : ?>
						<li>
							<code><?php echo esc_html( $notice_id ); ?></code><?php echo esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), absint( $time ) ) ); ?>
						</li>
					<?php endforeach; ?>
				</ul>
			<?php endif; ?>

			<form method="post">
				<?php wp_nonce_field( 'rx_reset_notices_action', 'rx_reset_notices_nonce' ); ?>
				<p>
					<button type="submit" name="rx_reset_notices" class="button button-primary">
						<?php esc_html_e( 'Reset All Dismissed Notices', 'rx-theme' ); ?>
					</button>
				</p>
			</form>

			<hr>

			<h2><?php esc_html_e( 'RX Theme Site Checklist', 'rx-theme' ); ?></h2>

			<ul style="list-style:disc;margin-left:20px;">
				<li><?php esc_html_e( 'Use updated WordPress version.', 'rx-theme' ); ?></li>
				<li><?php esc_html_e( 'Use PHP 7.4 or higher.', 'rx-theme' ); ?></li>
				<li><?php esc_html_e( 'Enable SSL/HTTPS.', 'rx-theme' ); ?></li>
				<li><?php esc_html_e( 'Set post name permalink.', 'rx-theme' ); ?></li>
				<li><?php esc_html_e( 'Add site icon/favicon.', 'rx-theme' ); ?></li>
				<li><?php esc_html_e( 'Install SEO plugin.', 'rx-theme' ); ?></li>
				<li><?php esc_html_e( 'Install cache/performance plugin.', 'rx-theme' ); ?></li>
				<li><?php esc_html_e( 'Install security plugin.', 'rx-theme' ); ?></li>
				<li><?php esc_html_e( 'Install backup plugin.', 'rx-theme' ); ?></li>
				<li><?php esc_html_e( 'Disable WP_DEBUG on live site.', 'rx-theme' ); ?></li>
			</ul>
		</div>
		<?php
	}

	/**
	 * Render reusable admin notice.
	 */
	private static function render_notice( $id, $type, $title, $message, $dismissible = true, $actions = array() ) {
		if ( $dismissible && self::is_dismissed( $id ) ) {
			return;
		}

		$allowed_types = array( 'success', 'error', 'warning', 'info' );

		if ( ! in_array( $type, $allowed_types, true ) ) {
			$type = 'info';
		}

		$classes = array(
			'notice',
			'notice-' . $type,
			'rx-notice',
		);

		if ( $dismissible ) {
			$classes[] = 'is-dismissible';
		}

		?>
		<div class="<?php echo esc_attr( implode( ' ', $classes ) ); ?>" data-notice-id="<?php echo esc_attr( $id ); ?>">
			<p class="rx-notice-title"><?php echo esc_html( $title ); ?></p>

			<p><?php echo wp_kses_post( $message ); ?></p>

			<?php if ( ! empty( $actions ) && is_array( $actions ) ) : ?>
				<p class="rx-notice-actions">
					<?php foreach ( $actions as $action ) : ?>
						<?php
						$label = isset( $action['label'] ) ? $action['label'] : '';
						$url   = isset( $action['url'] ) ? $action['url'] : '#';
						$class = isset( $action['class'] ) ? $action['class'] : 'button';

						if ( empty( $label ) ) {
							continue;
						}
						?>
						<a class="<?php echo esc_attr( $class ); ?>" href="<?php echo esc_url( $url ); ?>">
							<?php echo esc_html( $label ); ?>
						</a>
					<?php endforeach; ?>
				</p>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * AJAX dismiss notice.
	 */
	public static function ajax_dismiss_notice() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Permission denied.', 'rx-theme' ),
				),
				403
			);
		}

		check_ajax_referer( 'rx_theme_dismiss_notice_nonce', 'nonce' );

		$notice_id = isset( $_POST['notice_id'] ) ? sanitize_key( wp_unslash( $_POST['notice_id'] ) ) : '';

		if ( empty( $notice_id ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Invalid notice ID.', 'rx-theme' ),
				),
				400
			);
		}

		self::dismiss_notice( $notice_id );

		wp_send_json_success(
			array(
				'message' => __( 'Notice dismissed.', 'rx-theme' ),
			)
		);
	}

	/**
	 * Dismiss notice.
	 */
	private static function dismiss_notice( $notice_id ) {
		$dismissed               = self::get_dismissed_notices();
		$dismissed[ $notice_id ] = time();

		update_option( self::DISMISSED_OPTION, $dismissed, false );
	}

	/**
	 * Check notice dismissed.
	 */
	private static function is_dismissed( $notice_id ) {
		$dismissed = self::get_dismissed_notices();

		return isset( $dismissed[ $notice_id ] );
	}

	/**
	 * Get dismissed notices.
	 */
	private static function get_dismissed_notices() {
		$dismissed = get_option( self::DISMISSED_OPTION, array() );

		if ( ! is_array( $dismissed ) ) {
			$dismissed = array();
		}

		return $dismissed;
	}

	/**
	 * Check if plugin active by file.
	 */
	private static function is_plugin_active_by_file( $plugin_file ) {
		if ( ! function_exists( 'is_plugin_active' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}

		if ( is_plugin_active( $plugin_file ) ) {
			return true;
		}

		if ( is_multisite() && function_exists( 'is_plugin_active_for_network' ) && is_plugin_active_for_network( $plugin_file ) ) {
			return true;
		}

		return false;
	}

	/**
	 * Check if any plugin from list is active.
	 */
	private static function has_any_active_plugin( $plugins ) {
		if ( empty( $plugins ) || ! is_array( $plugins ) ) {
			return false;
		}

		foreach ( $plugins as $plugin ) {
			if ( self::is_plugin_active_by_file( $plugin ) ) {
				return true;
			}
		}

		return false;
	}
}

endif;

RX_Theme_Admin_Notices::init();

Now include it in your theme functions.php:

/**
 * RX Theme admin notices.
 */
if ( is_admin() ) {
	$rx_notice_file = get_template_directory() . '/inc/admin/notice.php';

	if ( file_exists( $rx_notice_file ) ) {
		require_once $rx_notice_file;
	}
}

Recommended folder structure:

rx-theme/
├── functions.php
└── inc/
    └── admin/
        └── notice.php

Important: this file is for admin area only, so it should not slow down your public frontend pages.

Leave a Reply

Your email address will not be published. Required fields are marked *