* Description * [/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 = ''; // .custom-carousel-wrapper return $output; } ); } );