block-alert.php

I’ll build this as a reusable advanced Gutenberg-style PHP template part: configurable alert types, icons, dismissible mode, ARIA accessibility, schema/meta hooks, safe escaping, block supports, and theme filter hooks.

Yes friend — create this file:

/template-parts/blocks/block-alert.php

Use it like:

get_template_part(
	'template-parts/blocks/block-alert',
	null,
	array(
		'type'        => 'success',
		'title'       => 'Success!',
		'message'     => 'Your RX Theme alert block is working perfectly.',
		'dismissible' => true,
	)
);

Here is an advanced version:

<?php
/**
 * Template Part: RX Theme Advanced Alert Block
 *
 * File: /template-parts/blocks/block-alert.php
 *
 * Usage:
 *
 * get_template_part(
 *     'template-parts/blocks/block-alert',
 *     null,
 *     array(
 *         'type'        => 'info',
 *         'title'       => 'Important Notice',
 *         'message'     => 'This is an advanced RX Theme alert message.',
 *         'dismissible' => true,
 *     )
 * );
 *
 * @package RX_Theme
 */

defined( 'ABSPATH' ) || exit;

/**
 * ------------------------------------------------------------
 * Default Alert Configuration
 * ------------------------------------------------------------
 */

$rx_alert_defaults = array(
	/**
	 * Alert style type.
	 *
	 * Available:
	 * info, success, warning, error, danger, primary, secondary,
	 * medical, emergency, tip, note, update, custom
	 */
	'type' => 'info',

	/**
	 * Content.
	 */
	'title'       => '',
	'subtitle'    => '',
	'message'     => '',
	'description' => '',
	'content'     => '',

	/**
	 * Optional list items.
	 */
	'items' => array(),

	/**
	 * Icon settings.
	 */
	'show_icon'   => true,
	'icon'        => '',
	'icon_label'  => '',
	'icon_markup' => '',

	/**
	 * Layout settings.
	 */
	'layout'       => 'default', // default, compact, wide, inline, card.
	'align'        => '',        // left, center, right, wide, full.
	'text_align'   => 'left',
	'width'        => '',
	'max_width'    => '',
	'min_height'   => '',
	'border_style' => '',        // solid, dashed, dotted, none.
	'shadow'       => false,
	'rounded'      => true,

	/**
	 * Behavior.
	 */
	'dismissible'       => false,
	'dismiss_label'     => __( 'Dismiss alert', 'rx-theme' ),
	'dismiss_storage'   => false,
	'dismiss_storage_id'=> '',
	'auto_dismiss'      => false,
	'auto_dismiss_delay'=> 8000,
	'is_collapsible'    => false,
	'is_open'           => true,

	/**
	 * Accessibility.
	 */
	'role'       => '',
	'aria_live'  => '',
	'aria_label' => '',
	'tabindex'   => '',

	/**
	 * CTA buttons / links.
	 */
	'actions' => array(),

	/**
	 * Extra HTML attributes.
	 */
	'id'          => '',
	'class'       => '',
	'classes'     => array(),
	'attributes'  => array(),
	'data'        => array(),

	/**
	 * Custom style values.
	 */
	'background'   => '',
	'color'        => '',
	'border_color' => '',
	'accent_color' => '',

	/**
	 * Optional meta.
	 */
	'meta'       => '',
	'time'       => '',
	'time_label' => '',

	/**
	 * Advanced controls.
	 */
	'allow_html'       => true,
	'allowed_tags'     => array(),
	'print_schema'     => false,
	'animation'        => '',
	'priority'         => '',
	'is_preview'       => false,
	'block_name'       => 'rx-alert',
	'wrapper_tag'      => 'div',
	'inner_tag'        => 'div',
);

/**
 * ------------------------------------------------------------
 * Merge User Args
 * ------------------------------------------------------------
 */

$rx_alert_args = isset( $args ) && is_array( $args ) ? $args : array();

$rx_alert = wp_parse_args( $rx_alert_args, $rx_alert_defaults );

/**
 * Allow child themes/plugins to modify alert args.
 */
$rx_alert = apply_filters( 'rx_theme_block_alert_args', $rx_alert, $rx_alert_args );

/**
 * ------------------------------------------------------------
 * Sanitization
 * ------------------------------------------------------------
 */

$rx_alert_type = sanitize_key( $rx_alert['type'] );

$rx_allowed_types = array(
	'info',
	'success',
	'warning',
	'error',
	'danger',
	'primary',
	'secondary',
	'medical',
	'emergency',
	'tip',
	'note',
	'update',
	'custom',
);

if ( ! in_array( $rx_alert_type, $rx_allowed_types, true ) ) {
	$rx_alert_type = 'info';
}

$rx_block_name = sanitize_html_class( $rx_alert['block_name'] );
$rx_wrapper_tag = tag_escape( $rx_alert['wrapper_tag'] );
$rx_inner_tag   = tag_escape( $rx_alert['inner_tag'] );

$rx_allowed_wrapper_tags = array( 'div', 'section', 'aside', 'article' );
$rx_allowed_inner_tags   = array( 'div', 'section' );

if ( ! in_array( $rx_wrapper_tag, $rx_allowed_wrapper_tags, true ) ) {
	$rx_wrapper_tag = 'div';
}

if ( ! in_array( $rx_inner_tag, $rx_allowed_inner_tags, true ) ) {
	$rx_inner_tag = 'div';
}

$rx_alert_id = ! empty( $rx_alert['id'] )
	? sanitize_html_class( $rx_alert['id'] )
	: 'rx-alert-' . wp_unique_id();

$rx_title       = is_string( $rx_alert['title'] ) ? $rx_alert['title'] : '';
$rx_subtitle    = is_string( $rx_alert['subtitle'] ) ? $rx_alert['subtitle'] : '';
$rx_message     = is_string( $rx_alert['message'] ) ? $rx_alert['message'] : '';
$rx_description = is_string( $rx_alert['description'] ) ? $rx_alert['description'] : '';
$rx_content     = is_string( $rx_alert['content'] ) ? $rx_alert['content'] : '';

/**
 * ------------------------------------------------------------
 * Allowed HTML
 * ------------------------------------------------------------
 */

$rx_default_allowed_tags = array(
	'a'      => array(
		'href'   => true,
		'title'  => true,
		'target' => true,
		'rel'    => true,
		'class'  => true,
	),
	'br'     => array(),
	'em'     => array(),
	'strong' => array(),
	'b'      => array(),
	'i'      => array(),
	'u'      => array(),
	'span'   => array(
		'class' => true,
	),
	'code'   => array(),
	'mark'   => array(),
	'small'  => array(),
);

$rx_allowed_tags = ! empty( $rx_alert['allowed_tags'] ) && is_array( $rx_alert['allowed_tags'] )
	? $rx_alert['allowed_tags']
	: $rx_default_allowed_tags;

$rx_allowed_tags = apply_filters( 'rx_theme_block_alert_allowed_html', $rx_allowed_tags, $rx_alert );

$rx_kses = static function ( $content ) use ( $rx_alert, $rx_allowed_tags ) {
	if ( empty( $content ) || ! is_string( $content ) ) {
		return '';
	}

	if ( ! empty( $rx_alert['allow_html'] ) ) {
		return wp_kses( $content, $rx_allowed_tags );
	}

	return esc_html( wp_strip_all_tags( $content ) );
};

/**
 * ------------------------------------------------------------
 * Icon System
 * ------------------------------------------------------------
 */

$rx_default_icons = array(
	'info' => '<svg class="rx-alert__icon-svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M11 17h2v-6h-2v6zm0-8h2V7h-2v2zm1 13A10 10 0 1 1 12 2a10 10 0 0 1 0 20z"/></svg>',

	'success' => '<svg class="rx-alert__icon-svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9.5 16.6 5.7 12.8l-1.4 1.4 5.2 5.2L20.3 8.6l-1.4-1.4-9.4 9.4z"/></svg>',

	'warning' => '<svg class="rx-alert__icon-svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>',

	'error' => '<svg class="rx-alert__icon-svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 2a10 10 0 1 0 .01 0H12zm5 13.6L15.6 17 12 13.4 8.4 17 7 15.6l3.6-3.6L7 8.4 8.4 7l3.6 3.6L15.6 7 17 8.4 13.4 12 17 15.6z"/></svg>',

	'danger' => '<svg class="rx-alert__icon-svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 2 1 21h22L12 2zm1 16h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>',

	'medical' => '<svg class="rx-alert__icon-svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M19 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm-1 11h-4v4h-4v-4H6v-4h4V6h4v4h4v4z"/></svg>',

	'emergency' => '<svg class="rx-alert__icon-svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M13 3h-2v10h2V3zm4.83 2.17-1.42 1.42A7 7 0 1 1 7.59 6.6L6.17 5.17A9 9 0 1 0 17.83 5.17z"/></svg>',

	'tip' => '<svg class="rx-alert__icon-svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M9 21h6v-1H9v1zm3-19a7 7 0 0 0-4 12.74V17a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-2.26A7 7 0 0 0 12 2z"/></svg>',

	'note' => '<svg class="rx-alert__icon-svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6zm-1 7V3.5L18.5 9H13z"/></svg>',

	'update' => '<svg class="rx-alert__icon-svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 6V3L8 7l4 4V8a4 4 0 1 1-4 4H6a6 6 0 1 0 6-6z"/></svg>',
);

$rx_default_icons['primary']   = $rx_default_icons['info'];
$rx_default_icons['secondary'] = $rx_default_icons['note'];
$rx_default_icons['custom']    = $rx_default_icons['info'];

$rx_default_icons = apply_filters( 'rx_theme_block_alert_icons', $rx_default_icons, $rx_alert );

$rx_icon_markup = '';

if ( ! empty( $rx_alert['show_icon'] ) ) {
	if ( ! empty( $rx_alert['icon_markup'] ) ) {
		$rx_icon_markup = wp_kses(
			$rx_alert['icon_markup'],
			array(
				'svg'   => array(
					'class'       => true,
					'width'       => true,
					'height'      => true,
					'viewBox'     => true,
					'aria-hidden' => true,
					'focusable'   => true,
					'fill'        => true,
					'role'        => true,
				),
				'path'  => array(
					'd'    => true,
					'fill' => true,
				),
				'span'  => array(
					'class'       => true,
					'aria-hidden' => true,
				),
				'i'     => array(
					'class'       => true,
					'aria-hidden' => true,
				),
			)
		);
	} elseif ( ! empty( $rx_alert['icon'] ) ) {
		$rx_icon_markup = '<span class="rx-alert__icon-text" aria-hidden="true">' . esc_html( $rx_alert['icon'] ) . '</span>';
	} elseif ( isset( $rx_default_icons[ $rx_alert_type ] ) ) {
		$rx_icon_markup = $rx_default_icons[ $rx_alert_type ];
	}
}

/**
 * ------------------------------------------------------------
 * Accessibility Logic
 * ------------------------------------------------------------
 */

$rx_role = ! empty( $rx_alert['role'] ) ? sanitize_key( $rx_alert['role'] ) : '';

if ( empty( $rx_role ) ) {
	$rx_role = in_array( $rx_alert_type, array( 'error', 'danger', 'emergency', 'warning' ), true ) ? 'alert' : 'status';
}

$rx_aria_live = ! empty( $rx_alert['aria_live'] ) ? sanitize_key( $rx_alert['aria_live'] ) : '';

if ( empty( $rx_aria_live ) ) {
	$rx_aria_live = in_array( $rx_alert_type, array( 'error', 'danger', 'emergency', 'warning' ), true ) ? 'assertive' : 'polite';
}

$rx_aria_label = ! empty( $rx_alert['aria_label'] ) ? sanitize_text_field( $rx_alert['aria_label'] ) : '';

if ( empty( $rx_aria_label ) ) {
	$rx_aria_label = ucfirst( $rx_alert_type ) . ' ' . __( 'alert', 'rx-theme' );
}

/**
 * ------------------------------------------------------------
 * Classes
 * ------------------------------------------------------------
 */

$rx_classes = array(
	$rx_block_name,
	'rx-alert',
	'rx-alert--' . $rx_alert_type,
	'rx-alert--layout-' . sanitize_html_class( $rx_alert['layout'] ),
	'has-alert-type-' . $rx_alert_type,
);

if ( ! empty( $rx_alert['align'] ) ) {
	$rx_classes[] = 'align' . sanitize_html_class( $rx_alert['align'] );
}

if ( ! empty( $rx_alert['text_align'] ) ) {
	$rx_classes[] = 'has-text-align-' . sanitize_html_class( $rx_alert['text_align'] );
}

if ( ! empty( $rx_alert['dismissible'] ) ) {
	$rx_classes[] = 'is-dismissible';
}

if ( ! empty( $rx_alert['dismiss_storage'] ) ) {
	$rx_classes[] = 'has-dismiss-storage';
}

if ( ! empty( $rx_alert['auto_dismiss'] ) ) {
	$rx_classes[] = 'has-auto-dismiss';
}

if ( ! empty( $rx_alert['is_collapsible'] ) ) {
	$rx_classes[] = 'is-collapsible';
	$rx_classes[] = ! empty( $rx_alert['is_open'] ) ? 'is-open' : 'is-closed';
}

if ( ! empty( $rx_alert['shadow'] ) ) {
	$rx_classes[] = 'has-shadow';
}

if ( ! empty( $rx_alert['rounded'] ) ) {
	$rx_classes[] = 'has-rounded-corners';
}

if ( ! empty( $rx_alert['priority'] ) ) {
	$rx_classes[] = 'has-priority-' . sanitize_html_class( $rx_alert['priority'] );
}

if ( ! empty( $rx_alert['animation'] ) ) {
	$rx_classes[] = 'has-animation';
	$rx_classes[] = 'has-animation-' . sanitize_html_class( $rx_alert['animation'] );
}

if ( ! empty( $rx_alert['is_preview'] ) ) {
	$rx_classes[] = 'is-preview';
}

if ( ! empty( $rx_alert['class'] ) ) {
	$rx_classes[] = sanitize_html_class( $rx_alert['class'] );
}

if ( ! empty( $rx_alert['classes'] ) && is_array( $rx_alert['classes'] ) ) {
	foreach ( $rx_alert['classes'] as $rx_extra_class ) {
		if ( is_string( $rx_extra_class ) && '' !== $rx_extra_class ) {
			$rx_classes[] = sanitize_html_class( $rx_extra_class );
		}
	}
}

$rx_classes = array_filter( array_unique( $rx_classes ) );

$rx_classes = apply_filters( 'rx_theme_block_alert_classes', $rx_classes, $rx_alert );

/**
 * ------------------------------------------------------------
 * Inline CSS Variables
 * ------------------------------------------------------------
 */

$rx_style_vars = array();

if ( ! empty( $rx_alert['background'] ) ) {
	$rx_style_vars[] = '--rx-alert-background:' . sanitize_hex_color( $rx_alert['background'] );
}

if ( ! empty( $rx_alert['color'] ) ) {
	$rx_style_vars[] = '--rx-alert-color:' . sanitize_hex_color( $rx_alert['color'] );
}

if ( ! empty( $rx_alert['border_color'] ) ) {
	$rx_style_vars[] = '--rx-alert-border-color:' . sanitize_hex_color( $rx_alert['border_color'] );
}

if ( ! empty( $rx_alert['accent_color'] ) ) {
	$rx_style_vars[] = '--rx-alert-accent-color:' . sanitize_hex_color( $rx_alert['accent_color'] );
}

if ( ! empty( $rx_alert['width'] ) ) {
	$rx_style_vars[] = '--rx-alert-width:' . esc_attr( $rx_alert['width'] );
}

if ( ! empty( $rx_alert['max_width'] ) ) {
	$rx_style_vars[] = '--rx-alert-max-width:' . esc_attr( $rx_alert['max_width'] );
}

if ( ! empty( $rx_alert['min_height'] ) ) {
	$rx_style_vars[] = '--rx-alert-min-height:' . esc_attr( $rx_alert['min_height'] );
}

if ( ! empty( $rx_alert['border_style'] ) ) {
	$rx_style_vars[] = '--rx-alert-border-style:' . esc_attr( $rx_alert['border_style'] );
}

$rx_style_attr = ! empty( $rx_style_vars ) ? implode( ';', $rx_style_vars ) . ';' : '';

/**
 * ------------------------------------------------------------
 * Attributes
 * ------------------------------------------------------------
 */

$rx_attributes = array(
	'id'          => $rx_alert_id,
	'class'       => implode( ' ', $rx_classes ),
	'role'        => $rx_role,
	'aria-live'   => $rx_aria_live,
	'aria-label'  => $rx_aria_label,
	'data-alert'  => 'rx-theme',
	'data-type'   => $rx_alert_type,
);

if ( ! empty( $rx_style_attr ) ) {
	$rx_attributes['style'] = $rx_style_attr;
}

if ( '' !== $rx_alert['tabindex'] ) {
	$rx_attributes['tabindex'] = intval( $rx_alert['tabindex'] );
}

if ( ! empty( $rx_alert['dismissible'] ) ) {
	$rx_attributes['data-dismissible'] = 'true';
}

if ( ! empty( $rx_alert['dismiss_storage'] ) ) {
	$rx_attributes['data-dismiss-storage'] = 'true';

	$rx_attributes['data-dismiss-storage-id'] = ! empty( $rx_alert['dismiss_storage_id'] )
		? sanitize_key( $rx_alert['dismiss_storage_id'] )
		: sanitize_key( $rx_alert_id );
}

if ( ! empty( $rx_alert['auto_dismiss'] ) ) {
	$rx_attributes['data-auto-dismiss'] = 'true';
	$rx_attributes['data-auto-dismiss-delay'] = absint( $rx_alert['auto_dismiss_delay'] );
}

if ( ! empty( $rx_alert['is_collapsible'] ) ) {
	$rx_attributes['data-collapsible'] = 'true';
	$rx_attributes['aria-expanded']    = ! empty( $rx_alert['is_open'] ) ? 'true' : 'false';
}

if ( ! empty( $rx_alert['animation'] ) ) {
	$rx_attributes['data-animation'] = sanitize_key( $rx_alert['animation'] );
}

/**
 * Extra data attributes.
 */
if ( ! empty( $rx_alert['data'] ) && is_array( $rx_alert['data'] ) ) {
	foreach ( $rx_alert['data'] as $rx_data_key => $rx_data_value ) {
		$rx_data_key = sanitize_key( $rx_data_key );

		if ( '' === $rx_data_key ) {
			continue;
		}

		$rx_attributes[ 'data-' . $rx_data_key ] = is_scalar( $rx_data_value )
			? sanitize_text_field( (string) $rx_data_value )
			: wp_json_encode( $rx_data_value );
	}
}

/**
 * Extra attributes.
 */
if ( ! empty( $rx_alert['attributes'] ) && is_array( $rx_alert['attributes'] ) ) {
	foreach ( $rx_alert['attributes'] as $rx_attr_key => $rx_attr_value ) {
		$rx_attr_key = sanitize_key( $rx_attr_key );

		if ( '' === $rx_attr_key ) {
			continue;
		}

		if ( in_array( $rx_attr_key, array( 'id', 'class', 'style' ), true ) ) {
			continue;
		}

		$rx_attributes[ $rx_attr_key ] = is_scalar( $rx_attr_value )
			? sanitize_text_field( (string) $rx_attr_value )
			: '';
	}
}

$rx_attributes = apply_filters( 'rx_theme_block_alert_attributes', $rx_attributes, $rx_alert );

$rx_render_attributes = static function ( $attributes ) {
	$output = '';

	foreach ( $attributes as $name => $value ) {
		if ( '' === $value || null === $value || false === $value ) {
			continue;
		}

		if ( true === $value ) {
			$output .= ' ' . esc_attr( $name );
			continue;
		}

		$output .= ' ' . esc_attr( $name ) . '="' . esc_attr( $value ) . '"';
	}

	return $output;
};

/**
 * ------------------------------------------------------------
 * Content Check
 * ------------------------------------------------------------
 */

$rx_has_text_content = (
	! empty( $rx_title ) ||
	! empty( $rx_subtitle ) ||
	! empty( $rx_message ) ||
	! empty( $rx_description ) ||
	! empty( $rx_content ) ||
	! empty( $rx_alert['items'] ) ||
	! empty( $rx_alert['actions'] )
);

if ( ! $rx_has_text_content ) {
	return;
}

/**
 * ------------------------------------------------------------
 * Action Button Renderer
 * ------------------------------------------------------------
 */

$rx_render_action = static function ( $action, $index ) {
	if ( ! is_array( $action ) ) {
		return '';
	}

	$label = isset( $action['label'] ) ? sanitize_text_field( $action['label'] ) : '';

	if ( '' === $label ) {
		return '';
	}

	$url      = isset( $action['url'] ) ? esc_url( $action['url'] ) : '';
	$type     = isset( $action['type'] ) ? sanitize_key( $action['type'] ) : 'link';
	$style    = isset( $action['style'] ) ? sanitize_html_class( $action['style'] ) : 'primary';
	$target   = isset( $action['target'] ) ? sanitize_key( $action['target'] ) : '';
	$rel      = isset( $action['rel'] ) ? sanitize_text_field( $action['rel'] ) : '';
	$aria     = isset( $action['aria_label'] ) ? sanitize_text_field( $action['aria_label'] ) : $label;
	$download = ! empty( $action['download'] );

	$classes = array(
		'rx-alert__action',
		'rx-alert__action--' . $style,
		'rx-button',
		'rx-button--' . $style,
	);

	if ( 'button' === $type ) {
		$button_type = isset( $action['button_type'] ) ? sanitize_key( $action['button_type'] ) : 'button';

		if ( ! in_array( $button_type, array( 'button', 'submit', 'reset' ), true ) ) {
			$button_type = 'button';
		}

		return sprintf(
			'<button type="%1$s" class="%2$s" aria-label="%3$s" data-action-index="%4$d">%5$s</button>',
			esc_attr( $button_type ),
			esc_attr( implode( ' ', $classes ) ),
			esc_attr( $aria ),
			absint( $index ),
			esc_html( $label )
		);
	}

	if ( empty( $url ) ) {
		return '';
	}

	$rel_parts = array();

	if ( $rel ) {
		$rel_parts[] = $rel;
	}

	if ( '_blank' === $target ) {
		$rel_parts[] = 'noopener';
		$rel_parts[] = 'noreferrer';
	}

	$rel_parts = array_unique( array_filter( $rel_parts ) );

	$attrs = array(
		'href'              => $url,
		'class'             => implode( ' ', $classes ),
		'aria-label'        => $aria,
		'data-action-index' => absint( $index ),
	);

	if ( $target ) {
		$attrs['target'] = $target;
	}

	if ( ! empty( $rel_parts ) ) {
		$attrs['rel'] = implode( ' ', $rel_parts );
	}

	if ( $download ) {
		$attrs['download'] = true;
	}

	$attr_html = '';

	foreach ( $attrs as $attr_name => $attr_value ) {
		if ( true === $attr_value ) {
			$attr_html .= ' ' . esc_attr( $attr_name );
		} else {
			$attr_html .= ' ' . esc_attr( $attr_name ) . '="' . esc_attr( $attr_value ) . '"';
		}
	}

	return '<a' . $attr_html . '>' . esc_html( $label ) . '</a>';
};

/**
 * ------------------------------------------------------------
 * Schema Data
 * ------------------------------------------------------------
 */

$rx_schema = array();

if ( ! empty( $rx_alert['print_schema'] ) ) {
	$rx_schema = array(
		'@context'    => 'https://schema.org',
		'@type'       => 'WebPageElement',
		'name'        => wp_strip_all_tags( $rx_title ? $rx_title : $rx_aria_label ),
		'description' => wp_strip_all_tags( $rx_message ? $rx_message : $rx_description ),
	);

	$rx_schema = apply_filters( 'rx_theme_block_alert_schema', $rx_schema, $rx_alert );
}

?>

<<?php echo esc_html( $rx_wrapper_tag ); ?><?php echo $rx_render_attributes( $rx_attributes ); ?>>

	<?php if ( ! empty( $rx_alert['print_schema'] ) && ! empty( $rx_schema ) ) : ?>
		<script type="application/ld+json">
			<?php echo wp_json_encode( $rx_schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); ?>
		</script>
	<?php endif; ?>

	<<?php echo esc_html( $rx_inner_tag ); ?> class="rx-alert__inner">

		<?php if ( ! empty( $rx_icon_markup ) ) : ?>
			<div class="rx-alert__icon" aria-hidden="true">
				<?php echo $rx_icon_markup; ?>
				<?php if ( ! empty( $rx_alert['icon_label'] ) ) : ?>
					<span class="screen-reader-text">
						<?php echo esc_html( $rx_alert['icon_label'] ); ?>
					</span>
				<?php endif; ?>
			</div>
		<?php endif; ?>

		<div class="rx-alert__body">

			<?php if ( ! empty( $rx_alert['meta'] ) || ! empty( $rx_alert['time'] ) ) : ?>
				<div class="rx-alert__meta">
					<?php if ( ! empty( $rx_alert['meta'] ) ) : ?>
						<span class="rx-alert__meta-text">
							<?php echo esc_html( $rx_alert['meta'] ); ?>
						</span>
					<?php endif; ?>

					<?php if ( ! empty( $rx_alert['time'] ) ) : ?>
						<time class="rx-alert__time" datetime="<?php echo esc_attr( $rx_alert['time'] ); ?>">
							<?php
							echo esc_html(
								! empty( $rx_alert['time_label'] )
									? $rx_alert['time_label']
									: $rx_alert['time']
							);
							?>
						</time>
					<?php endif; ?>
				</div>
			<?php endif; ?>

			<?php if ( ! empty( $rx_title ) ) : ?>
				<h3 class="rx-alert__title">
					<?php echo $rx_kses( $rx_title ); ?>
				</h3>
			<?php endif; ?>

			<?php if ( ! empty( $rx_subtitle ) ) : ?>
				<p class="rx-alert__subtitle">
					<?php echo $rx_kses( $rx_subtitle ); ?>
				</p>
			<?php endif; ?>

			<?php if ( ! empty( $rx_message ) ) : ?>
				<div class="rx-alert__message">
					<?php echo wpautop( $rx_kses( $rx_message ) ); ?>
				</div>
			<?php endif; ?>

			<?php if ( ! empty( $rx_description ) ) : ?>
				<div class="rx-alert__description">
					<?php echo wpautop( $rx_kses( $rx_description ) ); ?>
				</div>
			<?php endif; ?>

			<?php if ( ! empty( $rx_content ) ) : ?>
				<div class="rx-alert__content">
					<?php echo wpautop( $rx_kses( $rx_content ) ); ?>
				</div>
			<?php endif; ?>

			<?php if ( ! empty( $rx_alert['items'] ) && is_array( $rx_alert['items'] ) ) : ?>
				<ul class="rx-alert__list">
					<?php foreach ( $rx_alert['items'] as $rx_item ) : ?>
						<?php if ( is_string( $rx_item ) && '' !== trim( $rx_item ) ) : ?>
							<li class="rx-alert__list-item">
								<?php echo $rx_kses( $rx_item ); ?>
							</li>
						<?php endif; ?>
					<?php endforeach; ?>
				</ul>
			<?php endif; ?>

			<?php if ( ! empty( $rx_alert['actions'] ) && is_array( $rx_alert['actions'] ) ) : ?>
				<div class="rx-alert__actions">
					<?php
					foreach ( $rx_alert['actions'] as $rx_action_index => $rx_action ) {
						echo $rx_render_action( $rx_action, $rx_action_index ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
					}
					?>
				</div>
			<?php endif; ?>

		</div>

		<?php if ( ! empty( $rx_alert['dismissible'] ) ) : ?>
			<button
				type="button"
				class="rx-alert__dismiss"
				aria-label="<?php echo esc_attr( $rx_alert['dismiss_label'] ); ?>"
				data-rx-alert-dismiss
			>
				<span aria-hidden="true">&times;</span>
			</button>
		<?php endif; ?>

	</<?php echo esc_html( $rx_inner_tag ); ?>>

</<?php echo esc_html( $rx_wrapper_tag ); ?>>

Example with many features:

get_template_part(
	'template-parts/blocks/block-alert',
	null,
	array(
		'type'              => 'medical',
		'title'             => 'Medical Notice',
		'subtitle'          => 'Please read carefully',
		'message'           => 'This article is for general health education only.',
		'description'       => 'Always consult a qualified doctor for diagnosis and treatment.',
		'dismissible'       => true,
		'dismiss_storage'   => true,
		'dismiss_storage_id'=> 'rx-medical-notice-v1',
		'show_icon'         => true,
		'layout'            => 'card',
		'shadow'            => true,
		'rounded'           => true,
		'animation'         => 'fade-in',
		'items'             => array(
			'Do not ignore emergency symptoms.',
			'Do not stop medicine without medical advice.',
			'Visit a doctor if symptoms become severe.',
		),
		'actions'           => array(
			array(
				'label' => 'Read More',
				'url'   => home_url( '/health-disclaimer/' ),
				'style' => 'primary',
			),
			array(
				'label' => 'Contact Doctor',
				'url'   => home_url( '/contact/' ),
				'style' => 'secondary',
			),
		),
	)
);

For dismiss button, later add JS in:

/assets/js/components/alert.js

(function () {
	'use strict';

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

		if (!button) {
			return;
		}

		const alert = button.closest('.rx-alert');

		if (!alert) {
			return;
		}

		const useStorage = alert.getAttribute('data-dismiss-storage') === 'true';
		const storageId = alert.getAttribute('data-dismiss-storage-id');

		alert.setAttribute('hidden', 'hidden');

		if (useStorage && storageId && window.localStorage) {
			localStorage.setItem('rx_alert_dismissed_' + storageId, '1');
		}
	});

	document.addEventListener('DOMContentLoaded', function () {
		document.querySelectorAll('.rx-alert.has-dismiss-storage').forEach(function (alert) {
			const storageId = alert.getAttribute('data-dismiss-storage-id');

			if (storageId && window.localStorage && localStorage.getItem('rx_alert_dismissed_' + storageId) === '1') {
				alert.setAttribute('hidden', 'hidden');
			}
		});

		document.querySelectorAll('.rx-alert.has-auto-dismiss').forEach(function (alert) {
			const delay = parseInt(alert.getAttribute('data-auto-dismiss-delay'), 10) || 8000;

			window.setTimeout(function () {
				alert.setAttribute('hidden', 'hidden');
			}, delay);
		});
	});
})();

This file is safe, reusable, filterable, accessible, and advanced enough for RX Theme’s block system.

Leave a Reply

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