Part 3 of 5 · Testimonial Carousel

Do Not Reinvent the Wheel, Use a Proven Library

The testimonial carousel’s most important code is code I did not write. The sliding, the touch gestures, the pagination dots, all come from Swiper, a mature open source carousel library, and this post is that choice defended honestly, plus the integration details that make a library behave inside an Elementor widget, which is where the real work lived.

The build-versus-use question deserves the honest tally. A carousel looks like a weekend project, translate slides, loop back, two arrows, until the real requirements arrive, touch and swipe on phones, momentum physics, responsive breakpoints, right-to-left languages, autoplay that pauses on interaction, accessibility, resize handling. Swiper has years of production hardening on every one of those, and my weekend version would have been a bug list wearing a feature’s name. The maker’s pride urge to build it myself is real, and the discipline this blog keeps learning is to spend originality where the project differs, the widget’s controls and integration, not where the world has a solved answer.

The integration is where craft was actually needed. The render method prints Swiper’s expected markup from the repeater’s saved entries, then initialises the library with settings taken from the widget’s controls, so the editor’s choices drive the behaviour:

protected function render() {
    $s = $this->get_settings_for_display();
    wp_enqueue_style('everse-swiper');      // enqueue ONLY when rendering
    wp_enqueue_script('everse-swiper');

    echo '<div class="swiper everse-carousel"><div class="swiper-wrapper">';
    foreach ($s['testimonials'] as $t) {
        printf(
            '<div class="swiper-slide"><blockquote>%s</blockquote><cite>%s, %s</cite></div>',
            esc_html($t['quote']), esc_html($t['name']), esc_html($t['role'])
        );
    }
    echo '</div><div class="swiper-pagination"></div></div>';
}
new Swiper('.everse-carousel', {
    loop: true,
    autoplay: { delay: autoplaySpeed, disableOnInteraction: true },
    slidesPerView: 1,
    breakpoints: { 768: { slidesPerView: perViewTablet },
                   1024: { slidesPerView: perViewDesktop } },
    pagination: { el: '.swiper-pagination', clickable: true },
});

Three integration details did the heavy lifting. Enqueueing inside render keeps the politeness promise from the first post, Swiper loads only on pages where a carousel exists. The breakpoints map is the editor’s slides-per-view controls translated into responsive behaviour, one on phones, their chosen counts upward. And the Elementor editor needed special handling, widgets re-render live in the editor preview, so the initialisation hooks Elementor’s frontend events to re-run when the widget refreshes, without which the carousel works on the live site and sits frozen in the editor, a classic addon bug that makes clients think the widget is broken exactly where they judge it.

A few things people ask me about this

Why does my carousel work on the site but not in the Elementor editor? The editor re-renders widgets without reloading the page, so your initialisation never re-runs. Hook Elementor’s frontend init events and re-initialise the carousel when the widget refreshes.

Why load the carousel library only in render? Because a reusable widget ships to whole sites, and most pages have no carousel. Register early, enqueue at render, and you cost nothing where you do not appear.

Next

Real client sites brought two demands the demo never faced, testimonials in more than one language, and the question of where the quotes come from at all. Both are the next post.

Leave a Reply

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