ARTICLES

How To Reuse Bricks Builder Theme’s Image Lightbox Library (PhotoSwipe) If The Post Or Page Is Not Built By Bricks

If you are using any page builder, the recommended way is to create a template for the post type instead of editing the post by using a page builder. But how to use an element or feature like an image lightbox if my post is not edited by using a page builder? I am using Bricks Builder and let me share this with you without installing another plugin. (Tutorial updated to support v1.8beta-2, see full code in last section.)

Open Lightbox When Clicking on Image

By default in WordPress, when you insert an image using the Gutenberg image block or classic image block, you have the option to link the media URL to the image. However, this behavior can be inconvenient for users since it opens the image in the current browser tab. Just imagine how much more user-friendly it would be if you could open the image in a modal and easily zoom in without being redirected to another URL.

Well, the lightbox feature is ready-made in Bricks Builder, but only if the element is used in the page or post. So, how should I use this lightbox feature in my non-Bricks post or page?

Lightbox is read-made in Bricks Builder.
Lightbox is read-made in Bricks Builder.

Reuse The Lightbox Javascript Library In Bricks Builder

After studying the Bricks theme, understand that Bricks is using PhotoSwipe pure javascript library for Lightbox. That’s great, just finding a way to reuse it will do!

PhotoSwipe is very handy and easy to use. Just need to:

  1. Load PhotoSwipe javascript and css style
  2. Add PhotoSwipe element (.pswp) to the DOM
  3. Listen to an event and initialize the PhotoSwipe when necessary
  4. If you are using 1.8beta-2 and above, you need to enqueue PhotoSwipeLightbox as well. (See last section)

Step 1 – Enqueue Bricks PhotoSwipe Script and Style

By reusing the Bricks’s codes, we can do the first and second steps easily. The handler is bricks-photoswipe. (1.8beta-2 and above, enqueue bricks-photoswipe-lightbox as well)

<?php
add_action( 'wp_enqueue_scripts', function() {

	// I just want to enqueue in single post
	if( is_single() ) {
		wp_enqueue_script( 'bricks-photoswipe' );
		wp_enqueue_style( 'bricks-photoswipe' );
	}

}, 10 );

?>

Why do we need to enqueue? Because Bricks theme is caring about your website speed, and so only load it when necessary. But the mechanism is not working if the page or post is not built by Bricks. So we need to do it manually according to our needs.

By enqueued the bricks-photoswipe, Bricks theme helps to create the PhotoSwipe element as well. You could search for pswp in developer tools.

After enqueued bricks-photoswipe script, pwsp element added to DOM.
After enqueued bricks-photoswipe script, pwsp element added to DOM.

Step 2 – Add Event Listener On WP Block Image

Now, we need to add event listener on our default wp block images, so the PhotoSwipe can be initialized when we click on the image. Let’s see how to write it in action.

// javascript
// define some variables
const lightbox = document.querySelector(".pswp");
const options = {"index" : 0};
const item = [
	{
		"src": 'https://mydomain.com/abc.jpg',
		"w": 400,
		"h": 300,
		"title": 'The text' //optional
	}
];

// Initialize the Lightbox
( new PhotoSwipe( lightbox , PhotoSwipeUI_Default, item, options ) ).init();

Looks easy right? Now let us apply it on a proper event listener. DOM selector is playing important role here, if we use the wrong selector, you wouldn’t be able to trigger the lightbox. In my example here, I inserted an image via Gutenberg, set link to media as none because I do not want to add anchor element to wrap on my image, then set a proper caption for my image.

My Gutenberg image block setting

I decided to use .wp-block-image img as my selector

I will use .wp-block-image img as my DOM selector. In javascript we just need to use document.querySelectorAll('.wp-block-image img') as our target elements. Please amend your selector based on your inspection in browser developer tool.

//javascript
(()=>{
	document.addEventListener( 'DOMContentLoaded', ()=>{
		
		// Define my lightbox / PhotoSwipe element from DOM
		const lightbox = document.querySelector(".pswp");
		
		// Do some checking if PhotoSwipe loaded and lightbox element exists 
		if( 'function' === typeof PhotoSwipe && 'function' === typeof PhotoSwipeUI_Default && lightbox) {

			// Function to get the largest image from my img srcset
			const getLargestImage = (srcsetArray)=>{
				let largestSet = srcsetArray.reduce((previousSet, currentSet)=>{
					let temp_p = previousSet.trim().split(' ');
					let width_p = parseInt(temp_p[1].replace('w',''));
					let temp_c = currentSet.trim().split(' ');
					let width_c = parseInt(temp_c[1].replace('w',''));
					return (width_c > width_p)? currentSet: previousSet;
				});
				return largestSet.trim().split(' ');
			}

			// Function to open the lightbox
			const openLightbox = (event)=>{
				const options = {
					"bgOpacity" : .9,
					"showHideOpacity" : true,
					"index" : 0,
					"closeOnScroll" : false,
					"closeOnVerticalDrag" : false
				};
				const wpImg = event.target;
				let imgSrc = wpImg.getAttribute('src');
				let imgW = wpImg.getAttribute('width');
				
				// Added on 2022-March-14, only choose from srcset if image has srcset
				if( wpImg.getAttribute('srcset') ) {
					let srcsetArray = wpImg.srcset.split(',');
					let largestSetArry = getLargestImage(srcsetArray);
					imgSrc = largestSetArry[0];
					imgW = parseInt(largestSetArry[1].replace('w',''));;
				}
				let item = [
					{
						"src": imgSrc,
						"w": imgW,
						"h": wpImg.getAttribute('height'),
						"title": wpImg.nextElementSibling.innerText // optional
					}
				];
				(new PhotoSwipe(lightbox, PhotoSwipeUI_Default, item, options)).init();
			}

			// Important! Please use your own selector!
			const wpImages = document.querySelectorAll('.wp-block-image img');

			if( wpImages ) {
				wpImages.forEach( wpImg => {
					wpImg.addEventListener( 'click', openLightbox.bind(event), false );
				})
			}
		
		}
	})

})()

From the example above, I am going to show the largest image from my image srcset. And so I purposely create the getLargestImage function separately. If you prefer to get the image from src, just simply change to src: wpImg.src and w: wpImg.getAttribute('width').

Try it out in frontend, and yeeess it works when I click on the images!

Lightbox triggered as expected.
Lightbox triggered as expected.

Next, to make it perfect, change the cursor when mouse hover on image.

/*CSS*/
/*Please use your own selector as well*/
.wp-block-image img {
    cursor: zoom-in;
}

Open Gallery Images In PhotoSwipe

Updated: 2022 July 25

Below is example to open gallery images in Gutenberg gallery images. I gave the gallery a custom class my-gallery.

const openGalleryLightbox = (event)=>{
	event.preventDefault();
	const options = {
		"bgOpacity" : .9,
		"showHideOpacity" : true,
		"index" : 0,
		"closeOnScroll" : false,
		"closeOnVerticalDrag" : false
	};

	const wpImg = event.target;

	// Get all images from the gallery
	const otherImages = wpImg.closest('.my-gallery').querySelectorAll('img');

	let items = [];
	if( otherImages ) {
		otherImages.forEach( otherImg => {
			let imgSrc = otherImg.getAttribute('src');
			let imgW = otherImg.getAttribute('width');
			let id = otherImg.getAttribute('data-id');
			
			if( otherImg.getAttribute('srcset') ) {
				let srcsetArray = otherImg.srcset.split(',');
				let largestSetArry = getLargestImage(srcsetArray);
				imgSrc = largestSetArry[0];
				imgW = parseInt(largestSetArry[1].replace('w',''));;
			}
			items.push({
				"src": imgSrc,
				"w": imgW,
				"h": otherImg.getAttribute('height'),
				"id": id
			})
		})
	}

	// Get the index of the clicked image
	let index = 0;
	for( let i = 0; i < items.length; i++ ) {
		if( items[i].id === wpImg.getAttribute('data-id') ) {
			index = i;
			break;
		}
	}

	// Rearrange the images to match the order of the gallery
	let arrangedImgs = [];
	if( index > 0 ) {
		arrangedImgs = items.splice( index, items.length - index )
		items.forEach( item => {
			arrangedImgs.push(item);
		} )
	} else {
		arrangedImgs = items;
	}

	(new PhotoSwipe(lightbox, PhotoSwipeUI_Default, arrangedImgs, options)).init();
}

// Important! .my-gallery is my Gutenberg gallery custom class.
const wpGalleries = document.querySelectorAll('.my-gallery img');

if( wpGalleries ) {
	wpGalleries.forEach( wpImg => {
		wpImg.addEventListener( 'click', openGalleryLightbox.bind(event), false );
	})
}

For Bricks 1.8 beta2 and above

It’s super easy to achieve the same.

// Enqueue scripts and styles
<?php
add_action( 'wp_enqueue_scripts', function() {

	// I just want to enqueue in single post
	if( is_single() ) {
		wp_enqueue_script( 'bricks-photoswipe' );
		wp_enqueue_script( 'bricks-photoswipe-lightbox' ); // v1.8-beta-2
		wp_enqueue_style( 'bricks-photoswipe' );
	}

}, 10 );

?>

Then the JavaScript part, we need to check if PhotoSwipe5 and PhotoSwipeLightbox exist. Just use PhotoSwipe5 to init it!

(()=>{
	document.addEventListener( 'DOMContentLoaded', ()=>{

		if( 'function' === typeof PhotoSwipe5 && 'function' === typeof PhotoSwipeLightbox ) {

			const getLargestImage = (srcsetArray)=>{
				let largestSet = srcsetArray.reduce((previousSet, currentSet)=>{
					let temp_p = previousSet.trim().split(' ');
					let width_p = parseInt(temp_p[1].replace('w',''));
					let temp_c = currentSet.trim().split(' ');
					let width_c = parseInt(temp_c[1].replace('w',''));
					return (width_c > width_p)? currentSet: previousSet;
				});
				return largestSet.trim().split(' ');
			}

			const openLightbox = (event)=>{

				const wpImg = event.target;
				let imgSrc = wpImg.getAttribute('src');
				let imgW = wpImg.getAttribute('width');
				if(wpImg.getAttribute('srcset')) {
					let srcsetArray = wpImg.srcset.split(',');
					let largestSetArry = getLargestImage(srcsetArray);
					imgSrc = largestSetArry[0];
					imgW = parseInt(largestSetArry[1].replace('w',''));;
				}
				let item = [
					{
						"src": imgSrc,//wpImg.src,
						"w": imgW,//wpImg.width,
						"h": wpImg.getAttribute('height'),
						"title": wpImg.nextElementSibling.innerText
					}
				];
				const options = {
					mainClass: 'brx',
					dataSource: item,
				};

				(new PhotoSwipe5(options)).init();
			}

			const wpImages = document.querySelectorAll('.wp-block-image img');

			if( wpImages ) {
				wpImages.forEach( wpImg => {
					wpImg.addEventListener( 'click', openLightbox.bind(event), false );
				})
			}
		
		}
	})

})()

Conclusion

From the example above, you may do some more enhance like:

  • Only load the javascript on single post, so it will be more optimized.
  • Show the other images from the same page in the lightbox instead of clicking on each single image. This can be adjusted on the item variable in above example.

If you wish to do some other similar stuffs in Bricks Builder but no idea how to start, just drop me message. I will be glad to show you if it’s within my ability.

WordPress hooks used in this tutorial:

  • wp_enqueue_script
  • wp_enqueue_style

Reference: PhotoSwipe documentation

  • About Author

    Jenn@Itchycode
    I like to solve problems by coding. I like websites, web applications and everything viewable from browser. Knowledge sharing can grows my confidence. A simple "thank you" will make my day :)
    More about me

Subscribe For Notification

Get notification whenever new article published.
Subscription Form

Discussion

COMMENT

Thank you for the code, I was able to use it in Bricks 1.8b2 for single image or for a gallery, but I cannot find a way to reuse the lightbox when in the article I have single images and also a gallery. Do you have any suggestions on how I can implement it?

Reply
By Sandro (11 months ago)

Hi Sandro,

Kindly follow the code at https://itchycode.com/how-to-reuse-bricks-builder-themes-image-lightbox-library-photoswipe-if-the-post-or-page-is-not-built-by-bricks/#1.8
This should work.
My current blog is using the same code as well.

By Jenn@Itchycode (11 months ago)

Thanks Jenn, yes it is working but for single images, the images on the gallery are handled as single without the navigation. The old code where you target the .my-gallery img does not work with Bricks 1.8b2 :(

By Sandro (11 months ago)
New comment
Comment Form