ZIP up all images displayed in a [gallery] and offer as download link

First you have to get the images. How to get all images of a gallery is described here.

WordPress uses two classes for unzipping files. The PHP bilt in ZipArchive() (usage see David Walsh). And PclZip, you can found this class in wp-admin/includes/class-pclzip.php. If you got problems with ZipArchive() try the PclZip class.

Now you just to have to glue both together. Maybe I can post some sample code later, currently I am not at my desk.

Update

Your question can be splitted into two parts. The first one is getting all images from a gallery. The second one is zipping the images and send the zip file.
I will only explain the first part, getting all images of a gallery, because zipping the files is slightly offtopic.

Maybe there are other solutions, but in this example I replace the original gallery shortcode with a custom one to get the images. The reason is, WordPress changed the galleries in v3.5 a bit.
Before 3.5, the images for a gallery are attachments of the post. After 3.5, the images are passed to the shortcode as an attribute. Since WP3.5 we can not longer get the attached images of a post, we have to fetch the list from the shortcode attributes. My strategy is to replace the original shortcode with a custom shortcode, grab the attributes and call the original shortcode to get the gallery output.

All gallery related things are within a class. To create a zip file, we can use another class that takes as input the output of the gallery class. Let’s start with a class and a simple constructor.

class GalleryZip
{
    private static $instance = null;

    public static $images = array();

    public static function get_instance() {
        if ( ! session_id() )
          session_start();

        if ( null === self::$instance )
            self::$instance = new self();

        return self::$instance;
    }

    private final function __construct() {
        remove_shortcode( 'gallery' );
        add_shortcode( 'gallery', array( __CLASS__, 'gallery_zip_shortcode' ) );
    }
}

We will call the method get_instance() later in the plugin with the hook plugins_loaded. In the constructor, we remove the original shortcode and replace it with our custom shortcode gallery_zip_shortcode(). Now we need the shortcode callback

public static function gallery_zip_shortcode( $atts ) {

    $post = get_post();

    if ( ! function_exists( 'gallery_shortcode' ) )
      require_once ABSPATH . 'wp-includes/media.php';

    self::get_gallery_images_from_shortcode( $post->ID, $atts );
    $output = gallery_shortcode( $atts );

    $gallery_id = count( self::$images[$post->ID] ) - 1;

    $link = sprintf( '<div><a href="#" gallery-id="%d" post-id="%d" class="gallery-zip">%s</a></div>', $gallery_id, $post->ID, __( 'Get as Zip' ) );
    $output .= $link;

    return $output;

}

The first thing in this method is to get the post because we need the post ID. Than we include wp-includes/media.php, this file contains the callback function for the original gallery shortcode. Now we call a method to get an array with all images, create the gallery output by calling the original gallery callback, create a link and append the link to the gallery output. The images itself, respectively the pathes to the images, are stored in the class variable $images, we need this array later.
The class variable $image holds an entry for each post with an gallery, so we can use the function either on frontpage or in single view. Each entry contains an array for each gallery, because there can be more than one gallery in each post.

The core of the plugin is the method to get the images from the shortcode.

protected static function get_gallery_images_from_shortcode( $id, $atts ) {

    // use the post ID if the attribute 'ids' is not set or empty
    $id = ( ! isset( $atts['ids'] ) || empty( $atts['ids'] ) ) ?
        (int) $id : $atts['ids'];

    $exclude = ( isset( $atts['exclude'] ) && ! empty( $atts['exclude'] ) ) ?
        $atts['exclude'] : '';

    if ( ! isset( self::$images[$id] ) || ! is_array( self::$images[$id] ) )
        self::$images[$id] = array();

    $images = self::get_gallery_images( $id, $exclude );

    array_push( self::$images[$id], $images );

    return $images;

}

At first we decide if it is a single post or a list of post IDs. If it is a list of post IDs, we handle a gallery from WP3.5+. After that, we have to handle the exclude attribute. After setup all varibles, we can finally get the images from the gallery. The retrived images will be pushed into the class var $images for later use.

protected static function get_gallery_images( $id, $exclude ) {
    $images     = array();
    $query_args = array(
            'post_status'    => 'inherit',
            'post_type'      => 'attachment',
            'post_mime_type' => 'image',
    );

    // handle gallery WP3.5+
    // if $id contains an comma, it is a list of post IDs
    if ( false !== strpos( $id, ',' ) ) {
        $query_args['include'] = $id;
    } elseif ( ! empty( $exclude ) ) {
        // handle excluding posts
        $query_args['post_parent'] = $id;
        $query_args['exclude']     = $exclude;
    } else {
        // handle gallery before WP3.5
        $query_args['post_parent'] = $id;
    }

    $attachments = get_posts( $query_args );

    $img_sizes = array_merge( array( 'full' ), get_intermediate_image_sizes() );

    $img_size = ( in_array( self::IMAGE_SIZE, $img_sizes ) ) ?
            self::IMAGE_SIZE : 'full';

    foreach ( $attachments as $key => $post ) {
        $img = wp_get_attachment_image_src( $post->ID, $img_size, false, false );
        $images[] = sprintf( '%s/%s', dirname( get_attached_file( $post->ID ) ), basename( $img[0] ) );
    }

    return $images;
}

This is the gold of the plugin. Simply setup an array with query arguments, get the attachments with get_posts() and walk over the retrieved attachments. To handle different sizes, we get the attachment image and strip of the url. From the attached file, we take the path and put it together with the filename. In the array $images are now all images and their pathes from the gallery.

Basically your question is answered at this point. But you also want to createa zip file from the images. You could create a zip file from the array $images in the last method. But this method is called everytime a gallery is displayed and creating a zip file could take a while. Maybe noone would request the zip file you created here, this is a waste of resources.

How can we do it better? Do you remember that I put all images in the class variable $images? We can use this class var for an ajax request. But an ajax request is just another page load and we can access the images only when the output of the gallery is created. We have to save our images in a place where we can access them even after a another page request.
In this example I use a session variable to store the array with images. A session variable can be accessed even after another page reload. To store the images, I register a method with the shutdownhook. After WordPress finished rendering the page, the shutdown hook will be called. At this point, we should have collected all images from all displayed galleries. We simply store the images and can access them in an ajax request.

When the ajax request is triggered, we recall the session var and create a zip file from the data. But this is a bit off topic for this question.

I created a repository on GitHub with the complete plugin code. I hope it points you in the right direction.

Leave a Comment