DEV Community

IndiSnw
IndiSnw

Posted on

DIY Image gallery for Shopify blog posts

For the past few months, I've been busy with a Shopify website project. Recently, my client began focusing on content marketing, and over the last two weeks, they ran into an issue. They couldn't add image galleries to their blog posts using the content manager.

I did some research, and to my surprise, Shopify doesn't allow adding galleries to a blog post. All it offers is a rich text editor and the option to insert single images.

Some folks recommend switching to a dedicated blogging platform like WordPress. However, that approach didn't suit me since it would mean more effort. So, I came up with a clever and user-friendly workaround instead.

Solution

The solution involves just one JavaScript and one CSS file. After it's all set up, you won't need any coding skills to use it. I believe even someone without coding experience can handle the setup.

How to set up

  1. Add this CSS to your website's assets. I simply made a separate file called "blog-carousel.css" in the assets folder. It only includes CSS styles for the gallery, with no need for third-party dependencies.
/* Slideshow container */
.slideshow__photo {
    max-width: 500px;
    position: relative;
    margin: auto;
}

.slideshow-container {
    margin-bottom: 32px;
}


/* Next & previous buttons */
.slideshow__prev, .slideshow__next {
    cursor: pointer !important;
    position: absolute;
    top: 50%;
    width: auto;
    margin-top: -22px;
    padding: 16px;
    color: white !important;
    font-weight: bold;
    font-size: 18px;
    transition: 0.6s ease !important;
    border-radius: 0 3px 3px 0 !important;
    user-select: none !important;
}

/* Position the "next button" to the right */
.slideshow__next {
    right: 0;
    border-radius: 3px 0 0 3px;
}

/* On hover, add a black background color with a little bit see-through */
.slideshow__prev:hover, .slideshow__next:hover {
    background-color: rgba(0,0,0,0.8);
}

.slideshow__thumbnails {
    display: flex;
    justify-content: center;
}

.slideshow__thumbnails img {
    max-width: 200px;
    max-height: 170px;
    margin-left: 3px;
    margin-right: 3px;
    cursor: pointer;
}
Enter fullscreen mode Exit fullscreen mode

2.Add this js file that will initialize the galleries.

function slideShowChangeImage(e) {
    const newUrl = e.src;
    const img = e.parentNode.parentNode.getElementsByClassName('slideimg');
    img[0].src=newUrl;
}

function slideShowPrev(e) {
    changeToNextOrPrevImage(e, -1);
}

function slideShowNext(e) {
    changeToNextOrPrevImage(e, 1);
}

function getAllGalleryImages(parent) {
    const images = parent.getElementsByClassName('gallery-thumbnail');
    let allUrls = [];
    for (let i = 0; i < images.length; ++i) {
        allUrls.push(images[i].src);
    }
    return allUrls;
}

function changeToNextOrPrevImage(e, change){
    // get all available images

    // try to find the next one
    let allUrls = getAllGalleryImages(e.parentNode.parentNode);

    const img = e.parentNode.getElementsByClassName('slideimg');
    const currentUrl = img[0].src;

    const pos = allUrls.findIndex(v => currentUrl === v);
    let nextSlide = pos + change;
    if (nextSlide < 0) {
        nextSlide = allUrls.length - 1;
    } else {
        nextSlide = nextSlide % allUrls.length;
    }

    img[0].src = allUrls[nextSlide];
}

function initImageGalleries() {
    for (let i = 0; i <= 15; ++i) {
        createGallery(i.toString().padStart(2, '0'));
    }
}

function createGallery(id) {
    // get galleries grouped by number
    let allImages = document.querySelectorAll(`img[alt*="gallery ${id}"]`);

    let imgInCurrentGallery = [];
    let parent;

    let galleryStartNode = null;

    // delete the old images
    for(let i = 0; i < allImages.length; ++i) {
        const img = allImages[i];

        imgInCurrentGallery.push(allImages[i].cloneNode(true));

        parent = img.parentNode.parentNode;
        if (!galleryStartNode) {
            galleryStartNode = img.parentNode.nextSibling;
            console.log(galleryStartNode);
        }

        img.parentNode.remove();
    }

    if (allImages.length > 0) {
        buildGalleryHtml(parent, galleryStartNode, imgInCurrentGallery);
    }

    return allImages.length > 0;
}

function buildGalleryHtml(parent, insertBefore, imgs) {
    // class="slideshow-container"
    const container = document.createElement('div');
    container.className = 'slideshow-container';

    // init controls
    const controlsHtml = ` <div class="slideshow__photo">
                <div class="mySlides">
                    <img class="slideimg" src="" style="width:100%">
                </div>

                <a class="slideshow__prev" onclick="slideShowPrev(this)">&#10094;</a>
                <a class="slideshow__next" onclick="slideShowNext(this)">&#10095;</a>
                <br>
            </div>`;
    container.innerHTML = controlsHtml;

    // init thumbnails
    const thumbNailsSection = document.createElement('div');
    thumbNailsSection.className = 'slideshow__thumbnails';
    container.append(thumbNailsSection);

    for(let i = 0; i < imgs.length; ++i) {
        const img = document.createElement('img');
        img.className = 'gallery-thumbnail';
        img.src = imgs[i].src;
        img.addEventListener('click', () => slideShowChangeImage(img));
        thumbNailsSection.appendChild(img);
    }

    // set image to the first
    const img = container.getElementsByClassName('slideimg');
    img[0].src = imgs[0].src;

    parent.insertBefore(container, insertBefore);
}

document.addEventListener('DOMContentLoaded', () => initImageGalleries());
Enter fullscreen mode Exit fullscreen mode

3.Add those two files to your website. I prefer to add it only to our blogs pages… That's what it looks for me

{{ 'blog-carousell.css' | asset_url | stylesheet_tag }}
<script src="{{ 'blog-carousell.js' | asset_url }}" defer="defer"></script>
Enter fullscreen mode Exit fullscreen mode

4.If you want to put a gallery in your blog post, remember to include an "alt" attribute for your images. The "alt" attribute should end with 'gallery {id}'. The "id" can be a number between 01 and 15 (leading zeros are needed).

For example, let's say I have a few galleries within the same post. The images for the first gallery would have "alt" attributes like 'First Beef image, gallery 01' and 'Another Beef image, gallery 01'. Meanwhile, the images in another gallery would have "alt" attributes like 'Pork, gallery 02' and 'Pork, gallery 02'.

How it works

Javascript file tries to group all images presented on the page based on alt attribute. Then it creates required dom elements and attach even handlers.

Demo

The demo could be found here Wine bars in Singapore

Top comments (1)

Collapse
 
allengray03 profile image
Allen Gray

Thank you for sharing this clever workaround for adding image galleries to Shopify blog posts. It's a great solution for those who prefer to stick with Shopify for their blogging needs.

For anyone looking for Shopify Store Development Services to enhance their e-commerce website, feel free to check out ShopifyDigital.com. They specialize in Shopify development and can help you take your online store to the next level.