Easy image carousel

image software

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.


<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">

<?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 } ?>



I used CSS animation to create a fade effect between slides. I position the navigation dots using CSS flexbox layout.

	position: relative;
	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}
	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;


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;

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"; 
	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");
}, 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

Carousel showcasing artwork
Carousel showcasing artwork

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 = [];
<?php if (have_posts()): while (have_posts()) : the_post(); 

$featured_img_url = get_the_post_thumbnail_url(); 


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>" })

<?php } ?>

<script src="/galleria/galleria-1.5.7.js"></script>
<script type="text/javascript">
// Load the classic theme
    imageCrop: false,
    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() {
		this.bind('image', function(e) {


About the author

Anthony Pace

Anthony is a seasoned software engineer with a flair for design and a knack for problem-solving. Specializing in web development, his expertise extends beyond just coding. He crafts solutions tailored to the unique needs of small to medium-sized businesses.

Get in touch, send a text message


Let's work together!

Leave a Reply

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