alerts.php

I’ll build this as a reusable WordPress shortcode module for your rx-theme, focused on safe output, many alert styles, icons, dismissible alerts, CTA buttons, schema/ARIA support, and optional inline CSS/JS helpers.

Below is an advanced inc/shortcodes/alerts.php file for your rx theme.

It gives you a powerful shortcode:

[rx_alert type="success" title="Success!" dismissible="yes"]Your message here[/rx_alert]

Create this file:

<?php
/**
 * RX Theme Alerts Shortcodes
 *
 * File: inc/shortcodes/alerts.php
 *
 * Provides advanced, accessible, SEO-friendly alert/notice/message shortcodes.
 *
 * Main shortcode:
 * [rx_alert type="success" title="Saved!" icon="yes" dismissible="yes"]Message here[/rx_alert]
 *
 * Extra shortcodes:
 * [rx_notice]Message[/rx_notice]
 * [rx_success]Message[/rx_success]
 * [rx_warning]Message[/rx_warning]
 * [rx_error]Message[/rx_error]
 * [rx_info]Message[/rx_info]
 * [rx_tip]Message[/rx_tip]
 * [rx_medical_alert]Message[/rx_medical_alert]
 *
 * @package RX_Theme
 */

defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'RX_Theme_Alerts_Shortcodes' ) ) :

final class RX_Theme_Alerts_Shortcodes {

	/**
	 * Shortcode init state.
	 *
	 * @var bool
	 */
	private static bool $did_assets = false;

	/**
	 * Allowed alert types.
	 *
	 * @var array<string, string>
	 */
	private static array $types = array(
		'default'   => 'Default',
		'primary'   => 'Primary',
		'secondary' => 'Secondary',
		'success'   => 'Success',
		'info'      => 'Info',
		'warning'   => 'Warning',
		'danger'    => 'Danger',
		'error'     => 'Error',
		'notice'    => 'Notice',
		'tip'       => 'Tip',
		'medical'   => 'Medical',
		'doctor'    => 'Doctor',
		'emergency' => 'Emergency',
		'quote'     => 'Quote',
		'note'      => 'Note',
		'download'  => 'Download',
		'update'    => 'Update',
		'question'  => 'Question',
		'checklist' => 'Checklist',
	);

	/**
	 * Boot shortcodes.
	 *
	 * @return void
	 */
	public static function init(): void {
		add_shortcode( 'rx_alert', array( __CLASS__, 'render_alert' ) );

		// Friendly alias shortcodes.
		add_shortcode( 'rx_notice', array( __CLASS__, 'render_notice' ) );
		add_shortcode( 'rx_success', array( __CLASS__, 'render_success' ) );
		add_shortcode( 'rx_warning', array( __CLASS__, 'render_warning' ) );
		add_shortcode( 'rx_error', array( __CLASS__, 'render_error' ) );
		add_shortcode( 'rx_danger', array( __CLASS__, 'render_error' ) );
		add_shortcode( 'rx_info', array( __CLASS__, 'render_info' ) );
		add_shortcode( 'rx_tip', array( __CLASS__, 'render_tip' ) );
		add_shortcode( 'rx_note', array( __CLASS__, 'render_note' ) );
		add_shortcode( 'rx_medical_alert', array( __CLASS__, 'render_medical' ) );
		add_shortcode( 'rx_emergency_alert', array( __CLASS__, 'render_emergency' ) );
	}

	/**
	 * Render notice alias.
	 *
	 * @param array<string, mixed> $atts Shortcode attributes.
	 * @param string|null          $content Content.
	 * @return string
	 */
	public static function render_notice( $atts, $content = null ): string {
		$atts = is_array( $atts ) ? $atts : array();
		$atts['type'] = $atts['type'] ?? 'notice';
		return self::render_alert( $atts, $content );
	}

	/**
	 * Render success alias.
	 */
	public static function render_success( $atts, $content = null ): string {
		$atts = is_array( $atts ) ? $atts : array();
		$atts['type'] = 'success';
		return self::render_alert( $atts, $content );
	}

	/**
	 * Render warning alias.
	 */
	public static function render_warning( $atts, $content = null ): string {
		$atts = is_array( $atts ) ? $atts : array();
		$atts['type'] = 'warning';
		return self::render_alert( $atts, $content );
	}

	/**
	 * Render error alias.
	 */
	public static function render_error( $atts, $content = null ): string {
		$atts = is_array( $atts ) ? $atts : array();
		$atts['type'] = 'danger';
		return self::render_alert( $atts, $content );
	}

	/**
	 * Render info alias.
	 */
	public static function render_info( $atts, $content = null ): string {
		$atts = is_array( $atts ) ? $atts : array();
		$atts['type'] = 'info';
		return self::render_alert( $atts, $content );
	}

	/**
	 * Render tip alias.
	 */
	public static function render_tip( $atts, $content = null ): string {
		$atts = is_array( $atts ) ? $atts : array();
		$atts['type'] = 'tip';
		return self::render_alert( $atts, $content );
	}

	/**
	 * Render note alias.
	 */
	public static function render_note( $atts, $content = null ): string {
		$atts = is_array( $atts ) ? $atts : array();
		$atts['type'] = 'note';
		return self::render_alert( $atts, $content );
	}

	/**
	 * Render medical alias.
	 */
	public static function render_medical( $atts, $content = null ): string {
		$atts = is_array( $atts ) ? $atts : array();
		$atts['type'] = 'medical';
		$atts['title'] = $atts['title'] ?? 'Medical Note';
		return self::render_alert( $atts, $content );
	}

	/**
	 * Render emergency alias.
	 */
	public static function render_emergency( $atts, $content = null ): string {
		$atts = is_array( $atts ) ? $atts : array();
		$atts['type'] = 'emergency';
		$atts['title'] = $atts['title'] ?? 'Emergency Warning';
		$atts['role']  = $atts['role'] ?? 'alert';
		return self::render_alert( $atts, $content );
	}

	/**
	 * Main alert renderer.
	 *
	 * @param array<string, mixed> $atts Shortcode attributes.
	 * @param string|null          $content Shortcode content.
	 * @return string
	 */
	public static function render_alert( $atts, $content = null ): string {
		self::enqueue_inline_assets_once();

		$defaults = array(
			'type'          => 'info',
			'title'         => '',
			'subtitle'      => '',
			'icon'          => 'yes',
			'custom_icon'   => '',
			'dismissible'   => 'no',
			'remember'      => 'no',
			'id'            => '',
			'class'         => '',
			'align'         => 'none',
			'size'          => 'normal',
			'style'         => 'solid',
			'rounded'       => 'yes',
			'shadow'        => 'soft',
			'border'        => 'yes',
			'animation'     => 'none',
			'role'          => '',
			'aria_live'     => '',
			'button_text'   => '',
			'button_url'    => '',
			'button_target' => '_self',
			'button_rel'    => '',
			'button_style'  => 'filled',
			'more_text'     => '',
			'more_url'      => '',
			'tag'           => 'div',
			'schema'        => 'no',
			'compact'       => 'no',
			'print'         => 'yes',
			'escape'        => 'yes',
		);

		$atts = shortcode_atts( $defaults, $atts, 'rx_alert' );

		$type        = self::sanitize_type( $atts['type'] );
		$title       = sanitize_text_field( (string) $atts['title'] );
		$subtitle    = sanitize_text_field( (string) $atts['subtitle'] );
		$icon        = self::to_bool( $atts['icon'] );
		$custom_icon = sanitize_text_field( (string) $atts['custom_icon'] );

		$dismissible = self::to_bool( $atts['dismissible'] );
		$remember    = self::to_bool( $atts['remember'] );

		$id_raw = sanitize_key( (string) $atts['id'] );
		$id     = $id_raw ? $id_raw : 'rx-alert-' . wp_generate_uuid4();

		$extra_class = sanitize_html_class( (string) $atts['class'] );
		$align       = self::sanitize_choice( $atts['align'], array( 'none', 'left', 'center', 'right', 'wide', 'full' ), 'none' );
		$size        = self::sanitize_choice( $atts['size'], array( 'small', 'normal', 'large' ), 'normal' );
		$style       = self::sanitize_choice( $atts['style'], array( 'solid', 'outline', 'soft', 'minimal', 'gradient' ), 'solid' );
		$rounded     = self::to_bool( $atts['rounded'] );
		$shadow      = self::sanitize_choice( $atts['shadow'], array( 'none', 'soft', 'medium', 'strong' ), 'soft' );
		$border      = self::to_bool( $atts['border'] );
		$animation   = self::sanitize_choice( $atts['animation'], array( 'none', 'fade', 'slide', 'pulse' ), 'none' );
		$tag         = self::sanitize_choice( $atts['tag'], array( 'div', 'section', 'aside' ), 'div' );
		$compact     = self::to_bool( $atts['compact'] );
		$print       = self::to_bool( $atts['print'] );

		$role = sanitize_key( (string) $atts['role'] );
		if ( empty( $role ) ) {
			$role = in_array( $type, array( 'danger', 'error', 'emergency', 'warning' ), true ) ? 'alert' : 'status';
		}

		$aria_live = sanitize_key( (string) $atts['aria_live'] );
		if ( empty( $aria_live ) ) {
			$aria_live = 'alert' === $role ? 'assertive' : 'polite';
		}

		$button_text   = sanitize_text_field( (string) $atts['button_text'] );
		$button_url    = esc_url( (string) $atts['button_url'] );
		$button_target = self::sanitize_choice( $atts['button_target'], array( '_self', '_blank' ), '_self' );
		$button_rel    = sanitize_text_field( (string) $atts['button_rel'] );
		$button_style  = self::sanitize_choice( $atts['button_style'], array( 'filled', 'outline', 'text' ), 'filled' );

		$more_text = sanitize_text_field( (string) $atts['more_text'] );
		$more_url  = esc_url( (string) $atts['more_url'] );

		$schema = self::to_bool( $atts['schema'] );
		$escape = self::to_bool( $atts['escape'] );

		$content = null === $content ? '' : (string) $content;
		$content = do_shortcode( $content );

		if ( $escape ) {
			$content = wp_kses_post( wpautop( $content ) );
		} else {
			$content = wp_kses_post( $content );
		}

		$classes = array(
			'rx-alert',
			'rx-alert--' . $type,
			'rx-alert--style-' . $style,
			'rx-alert--size-' . $size,
			'rx-alert--align-' . $align,
			'rx-alert--shadow-' . $shadow,
			'rx-alert--animation-' . $animation,
		);

		if ( $rounded ) {
			$classes[] = 'rx-alert--rounded';
		}

		if ( $border ) {
			$classes[] = 'rx-alert--border';
		}

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

		if ( $compact ) {
			$classes[] = 'rx-alert--compact';
		}

		if ( ! $print ) {
			$classes[] = 'rx-alert--no-print';
		}

		if ( $extra_class ) {
			$classes[] = $extra_class;
		}

		$class_attr = implode( ' ', array_map( 'sanitize_html_class', $classes ) );

		$icon_markup = '';
		if ( $icon ) {
			$icon_markup = sprintf(
				'<span class="rx-alert__icon" aria-hidden="true">%s</span>',
				esc_html( $custom_icon ? $custom_icon : self::get_icon( $type ) )
			);
		}

		$button_markup = '';
		if ( $button_text && $button_url ) {
			$rel = $button_rel;

			if ( '_blank' === $button_target && empty( $rel ) ) {
				$rel = 'noopener noreferrer';
			}

			$button_markup = sprintf(
				'<a class="rx-alert__button rx-alert__button--%1$s" href="%2$s" target="%3$s" rel="%4$s">%5$s</a>',
				esc_attr( $button_style ),
				esc_url( $button_url ),
				esc_attr( $button_target ),
				esc_attr( $rel ),
				esc_html( $button_text )
			);
		}

		$more_markup = '';
		if ( $more_text && $more_url ) {
			$more_markup = sprintf(
				'<a class="rx-alert__more" href="%1$s">%2$s</a>',
				esc_url( $more_url ),
				esc_html( $more_text )
			);
		}

		$dismiss_markup = '';
		if ( $dismissible ) {
			$dismiss_markup = sprintf(
				'<button type="button" class="rx-alert__dismiss" aria-label="%1$s" data-rx-alert-dismiss data-rx-alert-id="%2$s" data-rx-alert-remember="%3$s">×</button>',
				esc_attr__( 'Dismiss alert', 'rx-theme' ),
				esc_attr( $id ),
				esc_attr( $remember ? 'yes' : 'no' )
			);
		}

		$title_markup = '';
		if ( $title ) {
			$title_markup = sprintf(
				'<strong class="rx-alert__title">%s</strong>',
				esc_html( $title )
			);
		}

		$subtitle_markup = '';
		if ( $subtitle ) {
			$subtitle_markup = sprintf(
				'<span class="rx-alert__subtitle">%s</span>',
				esc_html( $subtitle )
			);
		}

		$schema_attrs = '';
		if ( $schema ) {
			$schema_attrs = ' itemscope itemtype="https://schema.org/SpecialAnnouncement"';
		}

		$hidden_attr = '';
		if ( $dismissible && $remember ) {
			$hidden_attr = ' data-rx-alert-storage="yes"';
		}

		$output  = '';
		$output .= sprintf(
			'<%1$s id="%2$s" class="%3$s" role="%4$s" aria-live="%5$s" data-rx-alert%6$s%7$s>',
			tag_escape( $tag ),
			esc_attr( $id ),
			esc_attr( $class_attr ),
			esc_attr( $role ),
			esc_attr( $aria_live ),
			$schema_attrs,
			$hidden_attr
		);

		$output .= $icon_markup;
		$output .= '<div class="rx-alert__body">';

		if ( $title_markup || $subtitle_markup ) {
			$output .= '<div class="rx-alert__header">';
			$output .= $title_markup;
			$output .= $subtitle_markup;
			$output .= '</div>';
		}

		if ( $content ) {
			$output .= '<div class="rx-alert__content">';
			$output .= $content;
			$output .= '</div>';
		}

		if ( $button_markup || $more_markup ) {
			$output .= '<div class="rx-alert__actions">';
			$output .= $button_markup;
			$output .= $more_markup;
			$output .= '</div>';
		}

		$output .= '</div>';
		$output .= $dismiss_markup;
		$output .= sprintf( '</%s>', tag_escape( $tag ) );

		return apply_filters( 'rx_theme_alert_shortcode_output', $output, $atts, $content );
	}

	/**
	 * Get alert icon.
	 *
	 * @param string $type Alert type.
	 * @return string
	 */
	private static function get_icon( string $type ): string {
		$icons = array(
			'default'   => '●',
			'primary'   => '★',
			'secondary' => '◆',
			'success'   => '✓',
			'info'      => 'ℹ',
			'warning'   => '⚠',
			'danger'    => '!',
			'error'     => '!',
			'notice'    => '📌',
			'tip'       => '💡',
			'medical'   => '✚',
			'doctor'    => '⚕',
			'emergency' => '🚨',
			'quote'     => '❝',
			'note'      => '✎',
			'download'  => '⬇',
			'update'    => '↻',
			'question'  => '?',
			'checklist' => '☑',
		);

		return $icons[ $type ] ?? $icons['info'];
	}

	/**
	 * Sanitize alert type.
	 *
	 * @param mixed $type Type.
	 * @return string
	 */
	private static function sanitize_type( $type ): string {
		$type = sanitize_key( (string) $type );

		if ( 'error' === $type ) {
			$type = 'danger';
		}

		return array_key_exists( $type, self::$types ) ? $type : 'info';
	}

	/**
	 * Sanitize enum choice.
	 *
	 * @param mixed  $value Value.
	 * @param array  $allowed Allowed values.
	 * @param string $default Default value.
	 * @return string
	 */
	private static function sanitize_choice( $value, array $allowed, string $default ): string {
		$value = sanitize_key( (string) $value );
		return in_array( $value, $allowed, true ) ? $value : $default;
	}

	/**
	 * Convert common shortcode values to boolean.
	 *
	 * @param mixed $value Value.
	 * @return bool
	 */
	private static function to_bool( $value ): bool {
		$value = strtolower( trim( (string) $value ) );
		return in_array( $value, array( '1', 'true', 'yes', 'y', 'on', 'enable', 'enabled' ), true );
	}

	/**
	 * Print inline CSS and JS once.
	 *
	 * For best performance, later you can move this CSS to:
	 * assets/css/shortcodes/alerts.css
	 *
	 * And this JS to:
	 * assets/js/shortcodes/alerts.js
	 *
	 * @return void
	 */
	private static function enqueue_inline_assets_once(): void {
		if ( self::$did_assets ) {
			return;
		}

		self::$did_assets = true;

		add_action(
			'wp_footer',
			array( __CLASS__, 'print_inline_script' ),
			20
		);

		add_action(
			'wp_head',
			array( __CLASS__, 'print_inline_style' ),
			20
		);
	}

	/**
	 * Print alert CSS.
	 *
	 * @return void
	 */
	public static function print_inline_style(): void {
		?>
		<style id="rx-alert-shortcode-css">
			.rx-alert {
				--rx-alert-bg: #eef4ff;
				--rx-alert-text: #102033;
				--rx-alert-border: #9dbcf5;
				--rx-alert-accent: #2563eb;
				position: relative;
				display: flex;
				gap: 14px;
				width: 100%;
				margin: 20px 0;
				padding: 16px 18px;
				color: var(--rx-alert-text);
				background: var(--rx-alert-bg);
				border: 1px solid transparent;
				line-height: 1.65;
				box-sizing: border-box;
			}

			.rx-alert * {
				box-sizing: border-box;
			}

			.rx-alert--border {
				border-color: var(--rx-alert-border);
			}

			.rx-alert--rounded {
				border-radius: 14px;
			}

			.rx-alert--compact {
				padding: 10px 12px;
				gap: 10px;
				line-height: 1.5;
			}

			.rx-alert--size-small {
				font-size: 14px;
				padding: 12px 14px;
			}

			.rx-alert--size-normal {
				font-size: 16px;
			}

			.rx-alert--size-large {
				font-size: 18px;
				padding: 22px 24px;
			}

			.rx-alert--align-left {
				text-align: left;
			}

			.rx-alert--align-center {
				text-align: center;
				justify-content: center;
			}

			.rx-alert--align-right {
				text-align: right;
			}

			.rx-alert--align-wide {
				max-width: 1200px;
				margin-left: auto;
				margin-right: auto;
			}

			.rx-alert--align-full {
				width: 100vw;
				margin-left: calc(50% - 50vw);
				margin-right: calc(50% - 50vw);
				border-radius: 0;
			}

			.rx-alert--shadow-none {
				box-shadow: none;
			}

			.rx-alert--shadow-soft {
				box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
			}

			.rx-alert--shadow-medium {
				box-shadow: 0 14px 35px rgba(15, 23, 42, 0.12);
			}

			.rx-alert--shadow-strong {
				box-shadow: 0 20px 55px rgba(15, 23, 42, 0.18);
			}

			.rx-alert__icon {
				flex: 0 0 auto;
				display: inline-flex;
				align-items: center;
				justify-content: center;
				width: 32px;
				height: 32px;
				margin-top: 2px;
				color: #fff;
				background: var(--rx-alert-accent);
				border-radius: 999px;
				font-weight: 700;
				font-size: 16px;
				line-height: 1;
			}

			.rx-alert__body {
				flex: 1 1 auto;
				min-width: 0;
			}

			.rx-alert__header {
				display: flex;
				flex-direction: column;
				gap: 2px;
				margin-bottom: 6px;
			}

			.rx-alert__title {
				display: block;
				font-size: 1.08em;
				font-weight: 800;
				line-height: 1.35;
			}

			.rx-alert__subtitle {
				display: block;
				opacity: 0.82;
				font-size: 0.94em;
			}

			.rx-alert__content > :first-child {
				margin-top: 0;
			}

			.rx-alert__content > :last-child {
				margin-bottom: 0;
			}

			.rx-alert__actions {
				display: flex;
				flex-wrap: wrap;
				gap: 10px;
				margin-top: 14px;
			}

			.rx-alert__button,
			.rx-alert__more {
				display: inline-flex;
				align-items: center;
				justify-content: center;
				min-height: 38px;
				padding: 8px 14px;
				border-radius: 999px;
				font-weight: 700;
				text-decoration: none;
				transition: transform 0.2s ease, opacity 0.2s ease, background 0.2s ease;
			}

			.rx-alert__button:hover,
			.rx-alert__more:hover {
				transform: translateY(-1px);
				text-decoration: none;
			}

			.rx-alert__button--filled {
				color: #fff;
				background: var(--rx-alert-accent);
			}

			.rx-alert__button--outline {
				color: var(--rx-alert-accent);
				border: 1px solid var(--rx-alert-accent);
				background: transparent;
			}

			.rx-alert__button--text,
			.rx-alert__more {
				color: var(--rx-alert-accent);
				background: transparent;
				padding-left: 0;
				padding-right: 0;
			}

			.rx-alert__dismiss {
				position: absolute;
				top: 8px;
				right: 10px;
				width: 32px;
				height: 32px;
				padding: 0;
				border: 0;
				color: currentColor;
				background: transparent;
				font-size: 26px;
				line-height: 1;
				cursor: pointer;
				opacity: 0.65;
			}

			.rx-alert__dismiss:hover,
			.rx-alert__dismiss:focus {
				opacity: 1;
			}

			.rx-alert--dismissible {
				padding-right: 52px;
			}

			.rx-alert--primary {
				--rx-alert-bg: #eef4ff;
				--rx-alert-text: #102033;
				--rx-alert-border: #93c5fd;
				--rx-alert-accent: #2563eb;
			}

			.rx-alert--secondary {
				--rx-alert-bg: #f8fafc;
				--rx-alert-text: #1e293b;
				--rx-alert-border: #cbd5e1;
				--rx-alert-accent: #475569;
			}

			.rx-alert--success {
				--rx-alert-bg: #ecfdf5;
				--rx-alert-text: #064e3b;
				--rx-alert-border: #86efac;
				--rx-alert-accent: #16a34a;
			}

			.rx-alert--info,
			.rx-alert--notice,
			.rx-alert--note {
				--rx-alert-bg: #eff6ff;
				--rx-alert-text: #1e3a8a;
				--rx-alert-border: #93c5fd;
				--rx-alert-accent: #2563eb;
			}

			.rx-alert--warning {
				--rx-alert-bg: #fffbeb;
				--rx-alert-text: #78350f;
				--rx-alert-border: #fcd34d;
				--rx-alert-accent: #d97706;
			}

			.rx-alert--danger,
			.rx-alert--emergency {
				--rx-alert-bg: #fef2f2;
				--rx-alert-text: #7f1d1d;
				--rx-alert-border: #fca5a5;
				--rx-alert-accent: #dc2626;
			}

			.rx-alert--tip {
				--rx-alert-bg: #f0fdf4;
				--rx-alert-text: #14532d;
				--rx-alert-border: #86efac;
				--rx-alert-accent: #22c55e;
			}

			.rx-alert--medical,
			.rx-alert--doctor {
				--rx-alert-bg: #ecfeff;
				--rx-alert-text: #164e63;
				--rx-alert-border: #67e8f9;
				--rx-alert-accent: #0891b2;
			}

			.rx-alert--quote {
				--rx-alert-bg: #faf5ff;
				--rx-alert-text: #581c87;
				--rx-alert-border: #d8b4fe;
				--rx-alert-accent: #9333ea;
			}

			.rx-alert--download {
				--rx-alert-bg: #f0fdfa;
				--rx-alert-text: #134e4a;
				--rx-alert-border: #5eead4;
				--rx-alert-accent: #0d9488;
			}

			.rx-alert--update {
				--rx-alert-bg: #f5f3ff;
				--rx-alert-text: #4c1d95;
				--rx-alert-border: #c4b5fd;
				--rx-alert-accent: #7c3aed;
			}

			.rx-alert--question {
				--rx-alert-bg: #fdf4ff;
				--rx-alert-text: #701a75;
				--rx-alert-border: #f0abfc;
				--rx-alert-accent: #c026d3;
			}

			.rx-alert--checklist {
				--rx-alert-bg: #f7fee7;
				--rx-alert-text: #365314;
				--rx-alert-border: #bef264;
				--rx-alert-accent: #65a30d;
			}

			.rx-alert--style-outline {
				background: transparent;
				border-color: var(--rx-alert-accent);
			}

			.rx-alert--style-soft {
				background: color-mix(in srgb, var(--rx-alert-bg), white 35%);
			}

			.rx-alert--style-minimal {
				background: transparent;
				border-color: transparent;
				border-left: 5px solid var(--rx-alert-accent);
				border-radius: 0;
				box-shadow: none;
			}

			.rx-alert--style-gradient {
				background: linear-gradient(135deg, var(--rx-alert-bg), #ffffff);
			}

			.rx-alert--animation-fade {
				animation: rxAlertFade 0.45s ease both;
			}

			.rx-alert--animation-slide {
				animation: rxAlertSlide 0.45s ease both;
			}

			.rx-alert--animation-pulse {
				animation: rxAlertPulse 1.8s ease-in-out infinite;
			}

			@keyframes rxAlertFade {
				from {
					opacity: 0;
				}
				to {
					opacity: 1;
				}
			}

			@keyframes rxAlertSlide {
				from {
					opacity: 0;
					transform: translateY(12px);
				}
				to {
					opacity: 1;
					transform: translateY(0);
				}
			}

			@keyframes rxAlertPulse {
				0%, 100% {
					box-shadow: 0 0 0 0 color-mix(in srgb, var(--rx-alert-accent), transparent 75%);
				}
				50% {
					box-shadow: 0 0 0 8px color-mix(in srgb, var(--rx-alert-accent), transparent 100%);
				}
			}

			@media (max-width: 600px) {
				.rx-alert {
					flex-direction: row;
					gap: 10px;
					padding: 14px;
				}

				.rx-alert--dismissible {
					padding-right: 44px;
				}

				.rx-alert__icon {
					width: 28px;
					height: 28px;
					font-size: 14px;
				}

				.rx-alert__actions {
					flex-direction: column;
					align-items: flex-start;
				}
			}

			@media print {
				.rx-alert--no-print {
					display: none !important;
				}

				.rx-alert {
					box-shadow: none !important;
					border: 1px solid #999 !important;
					color: #000 !important;
					background: #fff !important;
				}

				.rx-alert__dismiss {
					display: none !important;
				}
			}
		</style>
		<?php
	}

	/**
	 * Print alert JS.
	 *
	 * @return void
	 */
	public static function print_inline_script(): void {
		?>
		<script id="rx-alert-shortcode-js">
			(function () {
				'use strict';

				var storagePrefix = 'rx_alert_dismissed_';

				function canUseStorage() {
					try {
						var key = '__rx_alert_test__';
						window.localStorage.setItem(key, '1');
						window.localStorage.removeItem(key);
						return true;
					} catch (e) {
						return false;
					}
				}

				var hasStorage = canUseStorage();

				function hideRememberedAlerts() {
					if (!hasStorage) {
						return;
					}

					var alerts = document.querySelectorAll('[data-rx-alert-storage="yes"]');

					alerts.forEach(function (alert) {
						var id = alert.getAttribute('id');

						if (!id) {
							return;
						}

						if (window.localStorage.getItem(storagePrefix + id) === '1') {
							alert.style.display = 'none';
						}
					});
				}

				function bindDismissButtons() {
					document.addEventListener('click', function (event) {
						var button = event.target.closest('[data-rx-alert-dismiss]');

						if (!button) {
							return;
						}

						var id = button.getAttribute('data-rx-alert-id');
						var remember = button.getAttribute('data-rx-alert-remember') === 'yes';
						var alert = id ? document.getElementById(id) : button.closest('[data-rx-alert]');

						if (!alert) {
							return;
						}

						if (remember && hasStorage && id) {
							window.localStorage.setItem(storagePrefix + id, '1');
						}

						alert.style.transition = 'opacity 0.22s ease, transform 0.22s ease';
						alert.style.opacity = '0';
						alert.style.transform = 'translateY(-6px)';

						window.setTimeout(function () {
							alert.remove();
						}, 230);
					});
				}

				if (document.readyState === 'loading') {
					document.addEventListener('DOMContentLoaded', function () {
						hideRememberedAlerts();
						bindDismissButtons();
					});
				} else {
					hideRememberedAlerts();
					bindDismissButtons();
				}
			})();
		</script>
		<?php
	}
}

RX_Theme_Alerts_Shortcodes::init();

endif;

Now include it in your theme functions.php:

require_once get_template_directory() . '/inc/shortcodes/alerts.php';

Usage examples

[rx_alert type="success" title="Success" dismissible="yes"]
Your profile has been updated successfully.
[/rx_alert]
[rx_alert type="warning" title="Important Warning" icon="yes" style="soft"]
Please check all information before submitting.
[/rx_alert]
[rx_alert type="medical" title="Medical Disclaimer" icon="yes" border="yes"]
This article is for educational purposes only and does not replace professional medical advice.
[/rx_alert]
[rx_alert type="danger" title="Emergency" role="alert" dismissible="yes"]
Seek urgent medical care if symptoms are severe or rapidly worsening.
[/rx_alert]
[rx_alert type="info" title="Read More" button_text="Open Guide" button_url="https://example.com"]
Click the button for the full guideline.
[/rx_alert]

Supported types:

default, primary, secondary, success, info, warning, danger, error, notice,
tip, medical, doctor, emergency, quote, note, download, update, question, checklist

Supported styles:

solid, outline, soft, minimal, gradient

Supported shortcode aliases:

[rx_notice]Message[/rx_notice]
[rx_success]Message[/rx_success]
[rx_warning]Message[/rx_warning]
[rx_error]Message[/rx_error]
[rx_info]Message[/rx_info]
[rx_tip]Message[/rx_tip]
[rx_note]Message[/rx_note]
[rx_medical_alert]Message[/rx_medical_alert]
[rx_emergency_alert]Message[/rx_emergency_alert]

Leave a Reply

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