On a recent project, I needed a simple image carousel on the homepage. And then, on the gallery page I needed a fully polished solution. Sometimes, using a framework is the right choice. Others, a fully built out toolkit can be overkill.
The Vanilla Option
First, here is the home-rolled version that I came up with. It was integrated into a custom WordPress template. I loop through a set of posts within my carousel wrapper, creating a slide div with that record’s featured image. I keep track of how many slides get built. Beneath the carousel wrapper I create a navigation div, and build a dot button for each slide. Each dot gets an index assigned to it, saved to its button’s data attribute.
HTML:
<div class="ap-carousel"> <?php $num_slides = 0; foreach($posts as $post){ $num_slides++; ?> <div class="ap-slide"> <a href="<?php the_permalink($post->ID); ?>" title="<?php the_title(); ?>"> <img src="<?php echo esc_url(get_the_post_thumbnail_url($post->ID)); ?>" class="zoom"> </a> </div> <?php } ?> <div class="nav-dots"> <?php $active = "active-dot"; for($x = 0; $x < $num_slides; $x++){ ?> <div class="dot"><button data="<?php echo $x; ?>" type="button" class="dot-button <?php echo $active; $active = ''; ?>">b</button></div> <?php } ?> </div> </div>
CSS:
I used CSS animation to create a fade effect between slides. I position the navigation dots using CSS flexbox layout.
.ap-carousel{ position: relative; } .ap-slide{ display: none; margin: 0 auto; } .ap-slide img{ width: auto; display: block; margin: 0 auto; max-height: 90vh; -webkit-animation-name: fade; -webkit-animation-duration: 1.5s; animation-name: fade; animation-duration: 1.5s; } @-webkit-keyframes fade { from {opacity: .4} to {opacity: 1} } @keyframes fade { from {opacity: .4} to {opacity: 1} } .nav-dots{ display: flex; justify-content: center; } .dot button{ display: block; border-radius: 100%; width: 12px; height: 12px; margin-right: 10px; padding: 0; border: none; text-indent: -9999px; background: black; cursor: pointer; } .dot button.active-dot{ background: red; }
JavaScript:
Finally, I create a JS function to change the slide and active dot based on a timer. I attach an event listener to the dots that will change the active slide based on the saved index data.
var slideIndex = 0; showSlides(); function showSlides() { var i; var slides = document.getElementsByClassName("ap-slide"); var dots = document.getElementsByClassName("dot-button"); for (i = 0; i < slides.length; i++) { slides[i].style.display = "none"; dots[i].classList.remove("active-dot"); } slideIndex++; if (slideIndex > slides.length) {slideIndex = 1} slides[slideIndex-1].style.display = "block"; dots[slideIndex-1].classList.add("active-dot") setTimeout(showSlides, 5000); // Change image every 5 seconds } document.addEventListener('click', function(event){ if(!event.target.matches('.dot-button')) return; slideIndex = event.target.getAttribute("data"); showSlides(); }, false);
That’s a simple and lite solution. It worked fine for the homepage of this recent project, but the main gallery page needed something more complex. I choose Galleria, a JavaScript framework.
The Framework Option
I implemented this option onto the WordPress category archive page. For this project, each piece of artwork is its own post. In my category template file I loop through posts, and populate a JSON object with the data about each slide. Initially, I had built HTML elements for each slide, but that caused slow page load times. The JSON data option is significantly faster. Here’s what my code setup looked like:
<div id="galleria"></div> <script type="text/javascript"> window.galleryData = []; </script> <?php if (have_posts()): while (have_posts()) : the_post(); $featured_img_url = get_the_post_thumbnail_url(); ?> <script> window.galleryData.push({ image: "<?php echo esc_url($featured_img_url); ?>", artinfo: "<div class='galleria-img-info'><h3 class='title'><a href='<?php the_permalink(); ?>'><?php the_title(); ?></a></h3><?php $size=get_post_meta(get_the_ID(), 'size', true);$size=addslashes($size);$date=get_post_meta(get_the_ID(), 'date', true);$materials=get_post_meta(get_the_ID(), 'materials', true);if(! empty ( $size ) ){echo '<p><strong>Dimensions:</strong> ' . $size . '</p>';}if(! empty ( $date ) ){echo '<p><strong>Date:</strong> ' . $date . '</p>';}if(! empty ( $materials ) ){echo '<p><strong>Materials:</strong> ' . $materials . '</p>';} ?><p class='you-can-mouse'>You can click the image to enlarge it. </p></div></div>" }) </script> <?php } ?> <script src="/galleria/galleria-1.5.7.js"></script> <script type="text/javascript"> // Load the classic theme Galleria.loadTheme('/galleria/galleria.classic.min.js'); //https://docs.galleria.io/collection/25-options Galleria.configure({ imageCrop: false, transitionSpeed:1000, maxScaleRatio:1, swipe:true, thumbnails: 'none', transition: 'fade', lightbox: true }); // Initialize Galleria Galleria.run('#galleria', {dataSource: window.galleryData, autoplay: 5000, extend: function() { // var gallery = this; // "this" is the gallery instance // gallery.play(); // call the play method } }); Galleria.ready(function() { $(".loading").hide(); this.bind('image', function(e) { }); }); </script>