Lightbox for WordPress, Sans Plugin

While I absolutely appreciate Jetpack and its myriad of features—Jetpack’s Protect, Publicize and Contact Form modules get used on nearly all projects of mine, and I use very few plugins—sometimes it’s just too much.

Even if a project doesn’t actually need any of the WordPress.com goodies, I’ll often still keep Jetpack around but in Development Mode, and use only the custom post types that come with it (Testimonials and Portfolio Projects).

The Age-Old Lightbox for jQuery

This time, though, the only Jetpack module still active was the Carousel, a Lightbox-like image viewer. Also, I’d already modified its default look but still didn’t quite like a few things about the way it behaved—like how a mouse click in between random images would open up the very first image in a gallery.

Long story short, I decided to try and create my own ‘Lightbox for WordPress’ implementation. After all, how hard can it be to load a few scripts and make sure everything’s properly initialized?

Well … It did take me a little while to found out I wasn’t going to get Lightbox2 to properly run without somehow filtering nearly all image tags on the site. Fancybox, however, I found can be initialized from a simply jQuery call! (Its docs could’ve been a bit clearer, though. And so much examples online do not at all apply to version 3!)

The Result

Anyhoo, here’s what I came up with. Note that this specific project required I disable zoom. I also had little need for back and forward buttons, and I needed a caption based off the image alt tag—that last bit sure took me a while!

Into a JavaScript file (one I named fancybox-init.js and placed in assets/js within my main child theme folder) goes the following:

jQuery( function( $ ) {
  /**
   * Automatically enables Fancybox for image thumbnails linking to an image.
   */
  $( '.entry-content a[href$="jpg"]:has(img), .entry-content a[href$="jpeg"]:has(img)' ).fancybox( {
    // Hide buttons other than 'close'.
    buttons: [
      "close"
    ],
    // Disable 'zoom on click'.
    clickContent : false,
    // Set caption based on image alt text.
    caption : function( instance, current ) {
      return $( this ).find( 'img' ).attr( 'alt' ); // Inside caption, $( this ) refers to the clicked element (i.e. a).
    }
  } );
} );

My child theme’s functions.php calls above script and the actual Fancybox CSS and JavaScript files (hosted on CloudFlare’s CDN):

add_action( 'wp_enqueue_scripts', function() {
  wp_enqueue_style( 'fancybox-style', 'https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.3.5/jquery.fancybox.min.css', array(), '3.3.5' );
  wp_enqueue_script( 'fancybox', 'https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.3.5/jquery.fancybox.min.js', array( 'jquery' ), '3.3.5', true );
  wp_enqueue_script( 'fancybox-init', get_stylesheet_directory_uri() . '/assets/js/fancybox-init.js', array( 'jquery', 'fancybox' ), false, true );
} );

I could even add a theme option and leave it up to the administrator to enable Fancybox on their site. Or drop everything in a plugin. (I still might.)

Note: I often use closures (i.e., anonymous functions) rather than named callback functions. The latter, while a bit less concise, may be preferred in some projects. (E.g., if others’ plugins need to be able to again dequeue any of your callbacks, they need a function name to refer to!)