Custom-Post-Powered Lightbox in 3 Easy Steps

Recently I was tasked with adding pop-up contact forms to a website that wanted more efficient use of available real estate.  Being a huge fan open-source tools , once I discovered the fancyBox jquery library – “easy to implement and a snap to customize” – I wanted to keep working with it.

What immediately came to mind was the lightbox galleries I’d enjoyed creating where the images looked great, but the display of the metadata – title, alt text, description, etc. – seemed arbitrary.  The native WordPress gallery editor – and plugins built on it – don’t provide a fine degree of control over the image’s accompanying text.

In a broader sense, WordPress works best when posts comprise the main granularity of content. It’s a chance to create semantically rich content consistently and efficiently. This tutorial outlines how a custom post-type archive page in WordPress can structure a lightbox gallery that allows full control over the accompanying html elements. Check out my example to see one in action.

1. Download fancyBox and load ‘er up

Download version 2.1.5 or the latest stable version from fancyapps. Enqueue the stylesheet and .js library file in your child theme’s functions.php. I installed a nice WordPress plugin ‘jquery updater’ as my site utilizes scripts that don’t work with the jquery library shipped with WordPress.

add_action( 'wp_enqueue_scripts', 'theme_enqueue_styles' );
function theme_enqueue_styles() {
 wp_enqueue_style( 'fancy-css', get_stylesheet_directory_uri() . '/fancybox/jquery.fancybox.css', false, '2.1.5', 'screen' );
 wp_enqueue_script( 'fancybox', get_stylesheet_directory_uri() . '/fancybox/jquery.fancybox.pack.js', array('jquery'), '2.1.5');
 wp_enqueue_script( 'fancies-her', get_stylesheet_directory_uri() . '/js/fancies.js', array('fancybox'), '2.1.5')

Create a new file called fancies.js in your theme’s root and paste in the following code block. We’ll be using an html element in place of a title attribute to populate the lightbox gallery with post data. It’s much easier to style when the ‘type’ property’s value is inside or over. The ‘launcher’ handler allows for a manual lightbox opening, as opposed to having a grid of thumbnails, any of which serve as trigger. This latter is slightly easier to implement, refer to the fancyBox docs.

$(window).load(function() {

.attr('rel', 'gallery')
afterShow: function() {
').show(); $(".fancybox-wrap").hover(function() { $(".fancybox-title").show(); }, function() { $(".fancybox-title").hide(); }); }, helpers : { title : { type : 'inside' } }, beforeLoad: function() { var el, id = $(this.element).data('title-id'); if (id) { el = $('#' + id); if (el.length) { this.title = el.html(); } } } }); $("#launcher").on("click", function(){ $(".fancybox").eq(0).trigger("click"); }); });

2. Create a Custom Post Type for Photography

We can spend a few minutes to set this up now so that in the future, adding a new photography entry and having it show up in the right place is a breeze. We won’t have to deal with  custom WordPress queries and the photography will have its own place in the site architecture and url structure.

function photograph_init() {
  $labels = array(
    'name' => 'Photographs',
    'singular_name' => 'Photograph',
    'edit_item' => 'Edit Post',
    'view_item' => 'View Post'
  $args = array(
    'labels' => $labels,
    'public' => true,
    'show_ui' => true,
    'capability_type' => 'post',
    'hierarchical' => false,
    'rewrite' => array('with_front' => false,'slug' => 'photos'),
    'query_var' => true,
    'menu_position' => 5,
    'menu_icon' => 'dashicons-camera',
    'supports' => array(
      'has_archive' => true
register_post_type( 'photos', $args );
add_action( 'init', 'photograph_init' );

Now we need to create a custom taxonomy so we can categorize our photos and have a straightforward way to organize multiple lightboxes.

function photo_cats_init() {
  $labels = array(
    'name' => _x( 'Photo Categories', 'taxonomy general name' ),
    'singular_name' => _x( 'Photo Category', 'taxonomy singular name' ),
    'search_items' => __( 'Search Photo Categories' ),
    'all_items' => __( 'All Photo Categories' ),
    'parent_item' => __( 'Parent Photo Category' ),
    'parent_item_colon' => __( 'Parent Photo Category:' ),
    'edit_item' => __( 'Edit Photo Category' ),
    'update_item' => __( 'Update Photo Category' ),
    'add_new_item' => __( 'Add New Photo Category' ),
    'new_item_name' => __( 'New Photo Category' ),
    'menu_name' => __( 'Photo Categories' ),
  $args = array(
    'labels' => $labels,
    'rewrite' => array( 'with_front' => false, 'slug' => 'photos'),
    'hierarchical' => true,
    'show_admin_column' => true,
register_taxonomy( 'photo_cats', 'photos', $args );
add_action( 'init', 'photo_cats_init' );

If all went well, you should see ‘Photographs’ in your admin sidebar navigation, with the adorable camera icon to go with it.  You should also see a submenu item allowing you to add photograph categories. At this point you can create a batch of photo posts with each having a unique featured image. Write a description of each photo in the post editor, and setup any custom fields you’d like to use (more on this in step 3).

If you have pretty permalinks enabled, Photograph posts will live at and photo category archives at First you must visit the ‘permalinks settings’ admin page; this alone should actuate the url rewrite rules on the Apache server. We’ll setup the proper files in the WordPress template hierarchy next.

3. Edit the Template Files

Copy your archive.php and rename it archive-photos.php or taxonomy-photo_cats-$slug.php, depending if you plan to use the custom post type or taxonomy archive respectively. The main content of the page will be a description of your gallery that entices your visitors to enter the lightbox to view your lovely creations. If you choose the taxonomy archive, insert this snippet into the template file’s <header> tag:

 // Show the term description.
 $term_description = term_description();
 if ( ! empty( $term_description ) ) :
 printf( '<div class="taxonomy-description">%s</div>', $term_description );
 endif; ?>

You’ll need to be sure to write a description for this gallery in the ‘Photo Categories’ admin screen. Immediately below the description we’ll add the link that launches the lightbox. (Alternatively you can output a gallery on page load, and each of the thumbnails is a link that opens the lightbox.)

<a href="javascript:;" id="launcher" rel="gallery">open gallery</a>

We’ll swap in a custom WordPress loop that spits out a series of img tags alternating with divs that contain the photo post content. Each img tag must include the html5 data-* attribute to match up with its div. Take a look at the jsfiddle demo – this is the technique we’ll use but with dynamic content. To get the data-title attributes to match, we can use the php incrementing operator.

<?php /* Start the Loop */ ?>
<?php $x = 1; 
while ( have_posts() ) : the_post(); ?>
  <div class="hidden">
  <?php the_fancy_thumbnail($post_id, $x); 
  echo '<div id="title-' . $x . '"><h2>' . get_the_title() . '</h2><h3>' . get_post_meta($post->ID, 'GPS', true) . '</h3>' . get_the_content() . '</div>'; ?>
<?php $x++;
endwhile; ?>

Note here that the better approach is to make a call like get_template_part( ‘content’, ‘archive-photos’ ); and put the above snippet in content-archive-photos.php. The get_post_meta call could be for any post metadata, this example would display the GPS coordinates where the shot was taken. I highly recommend this plugin to very easily setup custom fields for all of your WordPress posts.

Lastly, put the following snippet in your functions.php.

function the_fancy_thumbnail ($post_id,$x) {
echo '<a class="fancybox" data-title-id="title-' . $x . '">' . get_the_post_thumbnail( $post_id, 'full' ) . '</a>';

The fancyBox should now be all ready to go. Have fun making adjustments via their friendly and well-documented API. And please comment with any and all comments and questions!


Charlie's passion for graphic and web design is, quite remarkably, an exact 50-50 split. He otherwise enjoys long walks and documentary films. Connect with him on Linkedin.

Leave a Reply

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