*
* [/image_carousel]
*
* NOTES
* - First slide displays by default
* - Swipe requires 50px minimum movement to trigger
* - Modal displays same image in larger size
* - Click outside modal to close
* - CSS uses transform for smooth animations
*/
add_action(
'init',
function () {
add_shortcode(
'image_carousel',
function ( $atts, $content = null ) {
static $instance = 0;
++$instance;
if ( empty( $content ) ) {
return '';
}
// Register inline assets and enqueue only when shortcode is used
if ( function_exists( 'wp_add_inline_style' ) ) {
wp_register_style( 'custom-carousel-style', false ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
ob_start();
?>
loadHTML( '
' . $content . '
', LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
libxml_clear_errors();
libxml_use_internal_errors( $prev );
$xpath = new DOMXPath( $doc );
$imgs = $xpath->query( '//img' );
foreach ( $imgs as $img ) {
if ( $img->hasAttribute( 'src' ) ) {
$images[] = $img->getAttribute( 'src' );
}
}
if ( empty( $images ) ) {
// If no
, parse as newline-separated URLs
$cleaned_string = str_replace( '
', "\n", $content );
$lines = explode( "\n", $cleaned_string );
foreach ( $lines as $line ) {
$line = trim( wp_strip_all_tags( $line ) );
if ( '' === $line ) {
continue;
}
$images[] = $line;
}
}
// Filter only http/https URLs and sanitize
$images = array_values(
array_filter(
array_map(
static function ( $u ) {
$u = trim( (string) $u );
if ( '' === $u ) {
return null; }
$valid = wp_http_validate_url( $u );
if ( ! $valid ) {
return null; }
$parts = wp_parse_url( $u );
if ( ! $parts || ! isset( $parts['scheme'] ) || ! in_array( strtolower( $parts['scheme'] ), [ 'http', 'https' ], true ) ) {
return null; }
return esc_url_raw( $u );
},
$images
),
static function ( $x ) {
return ! empty( $x ); }
)
);
if ( empty( $images ) ) {
return '';
}
$wrapper_id = 'custom-carousel-' . $instance;
$modal_id = $wrapper_id . '-modal';
$output = '';
$output .= '
';
foreach ( $images as $index => $url ) {
$url = esc_url( $url );
$output .= '
';
}
$output .= '
'; // .custom-carousel-container
$output .= '
Slide 1 of ' . count( $images ) . '
';
$output .= '
';
$output .= '
';
$output .= '
';
foreach ( $images as $index => $_ ) {
$is_active = ( 0 === $index );
$output .= '';
}
$output .= '
'; // .custom-carousel-dots
// Per-instance modal structure
$output .= '
';
$output .= '
'; // .custom-carousel-wrapper
return $output;
}
);
}
);