should_render_slider() ) { return; } wp_enqueue_style( 'multipix-swiper', MULTIPIX_PLUGIN_URL . 'assets/vendor/swiper/swiper-bundle.min.css', array(), MULTIPIX_VERSION ); wp_enqueue_style( 'multipix-frontend', MULTIPIX_PLUGIN_URL . 'assets/frontend/css/multipix-frontend.css', array( 'multipix-swiper' ), MULTIPIX_VERSION ); wp_enqueue_script( 'multipix-swiper', MULTIPIX_PLUGIN_URL . 'assets/vendor/swiper/swiper-bundle.min.js', array(), MULTIPIX_VERSION, true ); wp_enqueue_script( 'multipix-frontend', MULTIPIX_PLUGIN_URL . 'assets/frontend/js/multipix-frontend.js', array( 'multipix-swiper' ), MULTIPIX_VERSION, true ); /** * Opzioni passate a Swiper in fase di init. Punto di estensione per * un eventuale add-on Pro (autoplay, effetti di transizione, zoom, * miniature...) senza dover modificare il file JS del core. */ $slider_options = apply_filters( 'multipix_slider_options', array() ); wp_localize_script( 'multipix-frontend', 'multipixFrontend', array( 'options' => $slider_options, ) ); } /** * Verifica se nella richiesta corrente va mostrato lo slider. * * @return bool */ protected function should_render_slider() { $post_types = apply_filters( 'multipix_supported_post_types', array( 'post' ) ); if ( ! is_singular( $post_types ) || ! is_main_query() ) { return false; } $post_id = get_queried_object_id(); /** * Punto di estensione per un eventuale add-on Pro: permette di far * comparire lo slider anche su un post senza immagini, se ha altro * tipo di slide (es. video) da mostrare. */ return (bool) apply_filters( 'multipix_has_gallery', ! empty( $this->get_gallery_ids( $post_id ) ), $post_id ); } /** * Inserisce lo slider subito dopo l'HTML dell'immagine in evidenza. * * Si aggancia a 'post_thumbnail_html', il filtro applicato all'output di * the_post_thumbnail(), così lo slider compare sempre e soltanto * immediatamente sotto l'immagine in evidenza, indipendentemente da * dove il tema la stampi in pagina. * * Il controllo su in_the_loop() è essenziale quanto quello già * presente in inject_fallback(): alcuni temi/plugin chiamano * the_post_thumbnail() FUORI dal Loop principale (es. per generare i * meta tag Open Graph in wp_head, o markup nascosto che poi viene * ricostruito da un builder invece di essere stampato così com'è). * Senza questo controllo, quella chiamata "fantasma" marca l'articolo * come già mostrato: lo slider finisce appeso a un HTML che non verrà * mai stampato, e sia il rendering vero sotto l'immagine sia il * fallback su the_content saltano entrambi, senza che lo slider * compaia da nessuna parte. * * @param string $html HTML dell'immagine in evidenza. * @param int $post_id ID del post a cui appartiene l'immagine. * @return string */ public function inject_after_thumbnail( $html, $post_id ) { if ( empty( $html ) || ! $this->should_render_slider() || ! in_the_loop() ) { return $html; } $post_id = absint( $post_id ); if ( $post_id !== get_queried_object_id() || isset( $this->rendered_for[ $post_id ] ) ) { return $html; } $slider_markup = $this->render_slider_markup( $this->get_gallery_ids( $post_id ), $post_id ); if ( empty( $slider_markup ) ) { return $html; } $this->rendered_for[ $post_id ] = true; return $html . $slider_markup; } /** * Fallback: se il tema non ha stampato l'immagine in evidenza (quindi * inject_after_thumbnail() non è mai scattato), mostra comunque lo * slider in cima al contenuto dell'articolo. * * Il controllo su in_the_loop() è essenziale: plugin come Yoast SEO * calcolano conteggio parole/tempo di lettura applicando il filtro * 'the_content' al contenuto grezzo del post FUORI dal Loop (spesso * in wp_head, prima ancora che il tema stampi la pagina). Senza * questo controllo, quella chiamata "fantasma" marca l'articolo come * già mostrato e il rendering vero, dentro il Loop, salta lo slider. * * @param string $content Contenuto del post. * @return string */ public function inject_fallback( $content ) { if ( ! $this->should_render_slider() || ! in_the_loop() ) { return $content; } $post_id = get_queried_object_id(); if ( isset( $this->rendered_for[ $post_id ] ) ) { return $content; } $slider_markup = $this->render_slider_markup( $this->get_gallery_ids( $post_id ), $post_id ); if ( empty( $slider_markup ) ) { return $content; } $this->rendered_for[ $post_id ] = true; return $slider_markup . $content; } /** * Shortcode [multipix_gallery] da inserire manualmente nel builder del * tema (es. BeTheme/Muffin Builder) subito dopo l'elemento immagine * in evidenza, quando il tema non passa da the_post_thumbnail(). * * @param array $atts Attributi dello shortcode. Supporta 'id' per * forzare un post diverso da quello corrente. * @return string */ public function render_shortcode( $atts ) { $atts = shortcode_atts( array( 'id' => 0 ), $atts, 'multipix_gallery' ); $post_id = $atts['id'] ? absint( $atts['id'] ) : get_the_ID(); if ( ! $post_id ) { return ''; } $slider_markup = $this->render_slider_markup( $this->get_gallery_ids( $post_id ), $post_id ); if ( empty( $slider_markup ) ) { return ''; } // Evita che il fallback su the_content lo aggiunga una seconda volta. $this->rendered_for[ $post_id ] = true; return $slider_markup; } /** * Costruisce il markup HTML dello slider: immagine grande (Swiper) + * striscia di miniature cliccabili centrate sotto (stile "pagina * prodotto"). Le miniature sono semplici bottoni, non un secondo * Swiper: così restano sempre centrate come gruppo via CSS, invece * di seguire la slide attiva (comportamento di Swiper con * centeredSlides, che centra la singola slide attiva e non il * gruppo). Le miniature vengono omesse se c'è una sola immagine. * * @param int[] $image_ids ID delle immagini della galleria. * @param int $post_id ID del post a cui appartiene la galleria. * @return string */ protected function render_slider_markup( $image_ids, $post_id ) { $slides = array(); $image_size = apply_filters( 'multipix_main_image_size', 'large' ); foreach ( $image_ids as $attachment_id ) { $main_html = wp_get_attachment_image( $attachment_id, $image_size, false, array( 'loading' => 'lazy' ) ); if ( ! $main_html ) { continue; } $slides[] = array( 'main' => $main_html, 'thumb' => wp_get_attachment_image( $attachment_id, 'thumbnail', false, array( 'loading' => 'lazy', 'alt' => '', ) ), ); } /** * Punto di estensione per un eventuale add-on Pro: permette di * aggiungere altre slide (es. video) in coda a quelle immagine, * senza toccare questo file. Ogni slide è un array con chiavi * 'main' e 'thumb' già pronte come HTML. */ $slides = apply_filters( 'multipix_gallery_slides', $slides, $post_id ); if ( empty( $slides ) ) { return ''; } $has_thumbs = count( $slides ) > 1; $show_arrows = $has_thumbs && apply_filters( 'multipix_show_navigation_arrows', true ); ob_start(); ?>
$slide ) : ?>