Posted on August 23, 2012 by Curtis McHale

Create a Simple WordPress Photo Gallery Popup with Ajax

Quite often I end up building custom functionality in to plugins for clients. Recently I had a client that need a photo gallery that allowed them to also add captions to photos. While there are a few solutions out there, they have so many options that my client didn’t need and they had some not so nice code. So I built my own.

Today we’ll rebuild the plugin for you to use.

You can view the plugin on Github and download it here

Don’t forget to subscribe to the as well.

Setting up our Plugin

Of course we want to put this in a plugin so lets get the basic plugin header set up. Create a folder in wp-content/plugins called wpthemetutorial-simple-photo-popup. Then create a file in that folder called wpthemetutorial-simple-photo-popup.php and paste the code below in.

Plugin Name: WP Theme Tutorial - Simple Photo Popup
Plugin URI:
Description: Adds a Photo post type and provides as shortcode to display all photo thumbs. Clicking a photo thumb links to the large version defined in your WordPress settings.
Version: 1.0
Author: WP Theme Tutorial, Curis McHale
Author URI:
License: GPLv2 or later

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

This simply registers the plugin with WordPress then provides GPL license information.

Register our Post Type

Now we need to register the post type we want to store all the photos in.

 * Builds out the custom post types for the site
 * @uses    register_post_type
 * @since   1.0
 * @author  WP Theme Tutorial, Curtis McHale
function theme_t_wp_photo_gallery(){

    register_post_type( 'thwp_photo_gallery', //
            'labels'                => array(
                'name'                  => __('Photos'),
                'singular_name'         => __('Photo'),
                'add_new'               => __('Add New'),
                'add_new_item'          => __('Add New Photo'),
                'edit'                  => __('Edit'),
                'edit_item'             => __('Edit Photo'),
                'new_item'              => __('New Photo'),
                'view'                  => __('View Photo'),
                'view_item'             => __('View Photo'),
                'search_items'          => __('Search Photo'),
                'not_found'             => __('No Photos Found'),
                'not_found_in_trash'    => __('No Photos found in Trash')
                ), // end array for labels
            'public'                => true,
            'menu_position'         => 5, // sets admin menu position
            'menu_icon'             => plugins_url( 'wpthemetutorial-simple-photo-popup/photo-icon.png' ),
            'hierarchical'          => false, // functions like posts
            'supports'              => array('title', 'editor', 'revisions', 'thumbnail'),
            'rewrite'               => array('slug' => 'photo', 'with_front' => true,), // permalinks format
            'can_export'            => true,

add_action( 'init', 'theme_t_wp_photo_gallery' );

Here we hook the init action and add our function. The function uses [register_post_type'][register] to, register our post type. This is the same function core WordPress uses to register all of the default post types (pages, posts, attachments...). We register our post type with the name ofthwp_photo_gallery` so when we call it later with WP_Query we will need to use that name to make sure we get the post type we want.

If we go to the WordPress Admin now we will see a new menu item called Photo. To add a photo click on the menu item and click add new. The thumbnails and popup are generated from the featured image while the caption is generated from the normal post content. Go ahead and add a few photos to your site so that you have some for testing.

Adding a Shortcode to Display the Photos

So far we have a post type and some photos added to it. But we currently don’t have any way to display the photos on the frontend of the site. This is where the WordPress Shortcode API comes in to play. Shortcodes allow end users to put a specially formatted string of text in the WordPress post/page editor which will then display whatever we choose. In our case the shortcode will be [thwp_photo_gallery].

 * Creates a shortcode that shows the photo gallery information
 * @since   1.0
 * @author  SFNdesign, Curtis McHale
function theme_t_wp_display_photo_gallery(){ ?>

    <section class="thwp-photo-gallery-wrapper">


        // defining the arguements for the custom loop
        $photoGallery = new WP_Query( array(
            'post_type'                 => 'thwp_photo_gallery',
        )); // end query

        if ( $photoGallery->have_posts() ) : while ( $photoGallery->have_posts() ) : $photoGallery->the_post();


          <article <?php post_class(); ?> id="photo-<?php the_ID(); ?>">
              <a href="<?php the_permalink(); ?>" id="<?php the_ID(); ?>" title="<?php the_title_attribute(); ?>"><?php the_post_thumbnail( 'thwp-photo-thumb' ); ?></a>

      <?php endwhile; else: ?>

          <h3>Oops!! Looks like something went wrong. Please get in touch with the site <a href="mailto:<?php echo get_bloginfo('admin_email'); ?>">administrator</a> and we'll get this sorted out</h3>

      <?php endif; ?>

      <?php wp_reset_query(); ?>


add_shortcode( 'thwp_photo_gallery', 'theme_t_wp_display_photo_gallery' );

add_shortcode takes 2 arguments. The first is the text of the shortcode we want to replace and the second is the function that we want to use for the shortcode display. In our case above we are using the thwp_photo_gallery as the shortcode in the content and replacing it with the function theme_t_wp_display_photo_gallery. That function is a simple loop that gets photos from our custom post type and displays them.

Getting our Scripts and Styles Ready

We can now show our photo posts on the front end of the site, but it’s not displaying the larger versions in a popup when you click on the thumbnails and the styles will simply match whatever the theme defaults come up with. Lets add our scripts and styles to finish off the plugin.

 * Adds any extra theme styles
 * @uses    wp_enqueue_style
 * @since   1.0
 * @author  SFNdesign, Curtis McHale
function theme_t_wp_photo_gallery_theme_styles_scripts(){

    // enqueue our styles
    wp_enqueue_style( 'fancyboxcss', plugins_url( '/wpthemetutorial-simple-photo-popup/jquery.fancybox.css' ), '', '1.0', 'all' );
    wp_enqueue_style( 'thwpstyles', plugins_url( '/wpthemetutorial-simple-photo-popup/styles.css' ), '', '1.0', 'all' );

    // setting up fancybox and our theme scripts
    wp_enqueue_script('fancybox', plugins_url( '/wpthemetutorial-simple-photo-popup/jquery.fancybox.pack.js' ), array('jquery'), '1.0', true);
    wp_enqueue_script('thwpphotoscript', plugins_url( '/wpthemetutorial-simple-photo-popup/photo-gallery-scripts.js' ), array('jquery', 'fancybox' ), '1.0', true);

    // getting Ajax ready for the plugin
    wp_localize_script( 'thwpphotoscript', 'THWPPhotoAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );

add_action( 'wp_enqueue_scripts', 'theme_t_wp_photo_gallery_theme_styles_scripts' );

Here we hook the wp_enqueue_scripts action and get it to run our function for the themes called theme_t_wp_photo_gallery_theme_styles_scripts. Inside that function we start by using the wp_enqueue_style. wp_enqueue_style takes 5 arguments.

wp_enqueue_style Arguments

The the name you are going to call the stylesheet.
The path to the stylesheet. Only required if WordPress hasn’t called the stylesheet defined by `$handle` before.
An array of handles for any other stylesheets that this one depends on. So in a theme if you need to have the main theme stylesheet called first you’d put it’s handle here.
The version of the stylesheet. Used to make sure that the correct version is served to browsers regardless of caching.
What media types is this stylesheet for? If it’s just for print then you’d put ‘print’ as the string.

For our plugin we enqueue two stylesheets. The first is for fancybox and the second is the styles to help our plugin look right in the theme.

Next we add our javascript for the popup effect with wp_enqueue_script. wp_enqueue_script is very similar to wp_enqueue_style but changes the final argument from media type to footer, letting you try to put your javascript in the footer of the site.

wp_enqueue_script Arguments

The the name you are going to call the script file.
The path to the script file. Only required if WordPress hasn’t called the stylesheet defined by `$handle` before.
An array of handles for any other script files that this one depends on. In our plugin we need jQuery loaded before fancybox and fancybox (and jquery) before the plugin scripts.
The version of the script file. Used to make sure that the correct version is served to browsers regardless of caching.
Try to place the file in the footer. If any files that depend on it are in the header then the script file will show up in the header.

We call 2 script files. The first is fancyBox (which powers all the popup) and the second is our plugin javascript file that will make the Ajax call for the popup content.

Finally we set up our plugin script for Ajax. As a short primer on WordPress and Ajax, all Ajax calls need to go through WordPress. wp_localize_script allows us to do that by allowing us to define the path to WordPress Ajax. Really wp_localize_script is built to translate strings for internationalization support, but if we can use it to define the path to WordPress Ajax as well.

Now copy the fancyBox scripts, styles and images out of the demo plugin and in to your plugin directory.

Adding our CSS

Our styles are pretty basic. All we want to do is provide a base. You will have to add some CSS to you theme to get the photos to match just right. Paste the code below in to the styles.css file we defined above with wp_enqueue_style.

.thwp-photo-gallery-wrapper{width:100%; margin:20px 0; overflow:hidden;}

.thwp-photo-gallery-wrapper .thwp_photo_gallery{width:200px; height:200px; float:left; margin:5px 5px;}

.thwp-photo-gallery-wrapper a:hover{text-decoration:none;}

/* === fancybox overrides === */
.fancybox-wrap .wp-post-image{display:block; clear:both;}
.fancybox-wrap .popup-caption{margin:10px 0; font-size:14px;}

Adding the jQuery

So we have included the files we need. You’ve moved the fancy box scripts, styles and images in to the plugin directory and added our basic styles. Now lets see about adding some jQuery to make the whole thing work.

jQuery( document ).ready( function( $ ){

    $( '.thwp_photo_gallery a' ).click(function (e){

        // stop the link from doing anything

        // get the ID of the post we want to get the video for
        var id = $( this ).attr('id');

        // Ajax goodness
        $.post( THWPPhotoAjax.ajaxurl, { action: 'get_photo', ID: id }, function ( response ){

            // call fancybox with the ajax content
                content: response

        } );



Here we get in to the real meat of the tutorial. Our first line makes sure that the document is ready and also makes sure that we can use the $ symbol for jQuery without hitting conflicts with other scripts that may be used in other plugins or the theme. Next we select the link through the class of the photo post. This class will be applied automatically since we used post_class on the article HTML element. With the link selected we attach to the click event and use e to prevent the default link action. Next we get the id for our post in to the javascript id var by getting it off the id of our link.

Now we step in to some ajax. You can see that we are using the jQuery .post method. This means that we will be posting the content, kind of like submitting a form and getting information from $_POST. We need to define the path to ajax using the values we set with wp_localize_script and then call an action, and pass the variable to the action. We then get our response to the action and call fancyBox.

Wait, we haven’t actually defined the action yet have we? No we haven’t currently this wouldn’t do anything since there would be no data returned to our Ajax function.

Getting our data to Ajax

The key piece to note in our Ajax call is the action. Above we called get_photo. WordPress provides a 2 actions to call so that our function runs on the defined action. The first wp_ajax_$var runs for a logged in user. That means that it won’t work with users that aren’t logged in, so we use the second one as well wp_ajax_nopriv_$var. Paste the code below in to the main PHP file for your plugin.

 * Gets our content for the photo popup
 * @since   1.0
 * @author  WP Theme Tutorial, Curtis McHale
function theme_t_wp_get_photo_popup(){

    // extract the post id
    $id = $_POST['ID'];

    // get our post object
    $post = get_post( $id );

    echo get_the_post_thumbnail( $id, 'medium' );

    echo '<div class="popup-caption">';
    echo wp_kses_post( wpautop( $post->post_content ) );
    echo '</div>';

    // we die or Ajax gets a 0

add_action( 'wp_ajax_get_photo', 'theme_t_wp_get_photo_popup' );
add_action( 'wp_ajax_nopriv_get_photo', 'theme_t_wp_get_photo_popup' );

Remember with Ajax function we passed the ID of the post as a variable. In our function we get it by accessing $_POST['ID']. Then we get our post object and echo the post thumbnail for the post. Finally we add a div to wrap the caption for styling, and then get the content out of the post object. WordPress doesn’t currently have a way to get the post content by post ID so we have to get it out of the post object. Since we’re no using a template tag, we also need to make sure we sanitize the data with wp_kses_post and make sure that paragraphs show up properly with [wpautop'][wpautop]. Finallly wedie` or we will also return a 0 to the Ajax function, and that’s just messy.

That’s it, our simple Ajax photo popup is done.

: “WP Theme Tutorial Screencasts in iTunes”

[@todo actions – init, wp_enqueue_scripts, wp_ajax_$var, wp_ajax_nopriv_$var]