WordPress Gallery with Automated Zip File Download

A recent client project for a photographer involved creating protected pages where their clients could download an entire gallery of images as a zip folder. The galleries are dynamic, so I wanted to make the download links dynamic as well, so that every time they added an image to the gallery it would get added to the download without any extra work.

Here’s a quick mockup, since the functionality isn’t public:

mockup of gallery with download link

I ended up building out the functionality using a bunch of custom PHP along with an Advanced Custom Fields gallery field to make it happen. As it turned out, we went a different direction for the final build (they wanted granular control over the resolution and a few other things that ended up making it more reasonable to lose the dynamic link).

I thought it’d still be fun to share the code since it seems like a pretty useful utility, so here goes!

Full Code

Let’s just start off with the full code so you can see it all in context. I’ve put a lot of comments throughout to narrate what’s going on and then I’ll point out a few key pieces and features in the breakdown below.

This whole operation can be broken down into three chunks:

  1. Checking the custom field for images
  2. Generating the zip and download link
  3. Displaying the gallery grid

Let’s take them piece by piece:

Breaking it Down

The custom field check wraps around the rest of the code, since we don’t want to show any of the rest of it if there aren’t images in the gallery, so let’s look at that first.

1. Checking the custom field for images

I started out by creating an ACF gallery field (part of Advanced Custom Fields PRO) called “Images.” The outer frame of the code snippet involves getting the field data and using a conditional to check if the field contains images:

$images = get_field('images');
if( $images ) : ?>
    <!-- download link and gallery display -->
<?php else : ?>
    <p>No images found.</p>
<?php endif; ?>

All the code for the download link and gallery itself goes in the commented area (the “yes, field has images” section) and there’s a message to display if no images are found.

2. Generating the zip and download link

The bulk of the code that goes in that comment area is for the zip file generation and the download link.

To start out, I created a variable to hold the download link for the file that will be generated. This is a little tricky – it needs to be a place on the server that is accessible/ writable, so it may take some trial and error to get it right. I used a special /downloads/ directory relative to the root.

$destination = 'downloads/' . sanitize_title( get_the_title() ) . '.zip';

The sanitize_title( get_the_title() ) bit uses the gallery page title as the file name, which is a nice little feature to make the file easy to identify after it is downloaded.

Now I can use that variable of $destination to create my file and links throughout the rest of the zip file code.

Next up, there’s a conditional to check if there’s already a zip file in that location. If the file does exist already, we just display the download link, but if not we have to create the file before displaying the link.

if ( file_exists( $destination ) ) {

    echo '<a href="' . esc_url( home_url( '/' ) ) . $destination . '" class="download-link" download>DOWNLOAD ALL</a>';

} else {

    // Code to generate and then display the link

} ?>

Caution: One thing I didn’t get around to testing before we went in a different direction was whether this check causes problems if the gallery is updated. I imagine it would since the file would already exist but with the old set of images.

You may find that you need to add some kind of dynamic text to the file name to make sure it gets updated regularly. The date could work, although you may not want to generate a new zip every day, so maybe use the week number or month or something. Or, potentially something using a cron job to regularly clear out the folder, as discussed in this Stack Overflow thread.

I’m not going to go line by line through generating the zip file since it’s commented in the gist, but the general flow is that you create an array of the gallery files, and then create the zip file from that array of files.

Remember that we’re tying into that ACF gallery field, so if you do this with a different method for inputting your files, you’ll have to change the beginning loop:

foreach( $images as $singlefile ) {
    $files[] = get_attached_file( $singlefile['ID'] );

In this little snippet, $images is our array from the gallery field, the same variable we used in the very first line of the code where we got the data from that field and checked to be sure there were images in the gallery.

There are a few checks throughout the sequence, making sure that there are files in the array, that each file exists, etc., and then when all is said and done the zip file is created and a download link generated.

3. Displaying the gallery grid

Finally, there’s the on-page gallery display. We’re looping through the gallery field again and spitting out the data into a grid view where the thumbnails are linked to full size images for a lightbox display.

That’s this part:

<div class="gallery-grid">
    <?php foreach( $images as $image ) : ?>
        <a href="<?php echo $image['url']; ?>" title="<?php echo $image['title']; ?>" rel="gallery">
            <img src="<?php echo $image['sizes']['thumbnail']; ?>" alt="<?php echo $image['alt']; ?>" />
    <?php endforeach; ?>
</div><!-- / .gallery-grid -->

This is all ACF syntax for gallery fields, nothing really customized in this bit.

As I mentioned, we unfortunately didn’t end up using this model, and there’s at least one modification I’d make to it (something to ensure the file is up to date), but I think it’s an interesting concept at least!

Different Paragraph and Image Widths in WordPress (for Readability)

I was talking with a client recently about blog post readability and line length, and how those things are hard to balance with wider column widths and nice large images.

Here are some good articles on line length, if you’re interested:

Once you’ve decided that you do indeed want to be careful about your line length, but you still want nice big images, things get a little tricky, particularly with a content management system like WordPress in the mix.

In theory, you’d just make your paragraphs narrower than your images by a small amount. This would keep the line lengths reasonable without having to adjust the font size too large or the image/ column size too narrow.

The problem is, WordPress wraps images in paragraph tags, so anything you do to the paragraph width will also impact your images.

If you don’t mind a little jQuery or javascript, you can fix this! Here’s what to do if you want your WP blog paragraphs narrower than your images:

I’ve done it recently in this site, as illustrated in this screenshot:

paragraph that is narrower than an image

You can even see it with this very paragraph compared to that screenshot (so meta)!

This took a little bit of jQuery and some CSS. Rather than take away the paragraph around the images (which seemed less reliable once you start to consider how the markup might change for captions, for example), I decided to add a class to those paragraphs.

This snippet went into my general theme.js file in my theme:

function imgParagraphs() {
    jQuery(document).ready(function($) {
        $('.post-body img.aligncenter, .post-body img.alignnone').each(function(){

It finds every image that is center aligned or has alignment set to “none” and gives their parent paragraphs the class img-parent.

I did not do this with right- and left-aligned images. The left-aligned images don’t need any modification, and I’m still messing with right-aligned images in this model, especially across various devices. (My general plan is that they are adjusted to the right via positioning for larger screens, then they become full width at smaller screens.)

Anyway, with that script in the main theme scripts file (which is loaded on each page, more on this centralized file method here), I added this to the blog template files:


This causes the relevant script to actually run on those pages (otherwise it just hangs out in the theme.js file not doing anything).

From there, I used CSS to alter the styling to add padding to the right of the paragraphs, and to take it away again on the image parent paragraphs:

// this is SCSS-formatted
.post .entry-content p {
    padding-right: 40px;
    &.img-parent {
        padding-right: 0;

Maybe it’d be better to have that be a relative value (ems or percent) than a pixel value, that’s something I’d encourage you to explore if you try something similar!

Is line length something you consider on your site? How do you handle it?

Three Quick Links: Responsive Images

three quick links for responsive images graphic

I’ve been generally following along with the conversations out there on responsive images but haven’t really felt it necessary to deep dive and actually do things with code yet.

Ok, that’s not entirely true – I’ve made big shifts in how I work with layout graphics such that I use almost all CSS and SVG/ scalable graphics. But for content graphics, I’ve mostly just been keepin’ on and waiting for some of the early back and forth to resolve itself.

I think we’re there, just about, so I’ve finally committed to some reading on responsive content images – here are three great resources. While there are tons of great articles out there, these stand out as particularly useful on this topic:


Responsive Images in Practice, from A List Apart, is extremely long and in-depth. It’s everything you need to know to implement responsive content images using all the major, forward-looking techniques. Start here.


It’s basically impossible to learn about newer techniques without referencing CSS Tricks, so I won’t try. There’s a great article there that talks about how srcset is the thing to use if you’re just changing resolutions. It also links to a bunch of other interesting resources.


Finally, one of the big barriers to responsive content images is that most of us aren’t actually coding all our content images. Never fear, there’s a WordPress plugin that seems to be the standard for handling responsive content images. You can also use it for themes, although I’m not sure I’m convinced you should (instead probably work on not using bitmap graphics in themes, I think).

I think I’ll probably start tackling some of this code in my Shopify starter theme – that seems like a place where optimizing graphics like this could go a long way, and since Shopify generates a ton of image sizes it seems like it should work pretty well.

What are you thinking and reading about responsive images these days?

Inline Click to Tweet Functionality

Warning! While I try to write a lot of my tutorials for people with varying degrees of coding experience, this particular tutorial is more for intermediate/ advanced readers. I wanted to explain the functionality but my implementation is pretty rough.

If you’re comfortable modifying your theme but work in WYSIWYG mode, you might want to try the WP Tweetable Text code this is based on.

Awhile back I noticed a really nice, unobtrusive “click to tweet” functionality on the InVision blog. While I’ve played around with click to tweet functionality before, this implementation felt much more smooth than having super huge callouts so I put it on my list to experiment with and forgot about it until recently.

I finally had time to mess around with getting this working on this site, and I’ve used it on a few recent posts to good feedback (if not much more in the way of shares so far). Here’s a screenshot of what this looks like in action:

My code was heavily based on this WP Tweetable Text plugin, which is not a WordPress plugin the way you usually would think of one (you add it to your theme, not via the Plugins area). I did try that code, but it only works with WYSIWYG editing mode, which I don’t use. If you’re working in WYSIWYG mode, I’d probably go with the original.

How It Works

I’m going to go a little backwards here and show you how this works once you’ve got the code in place first, then show you the code I used.

As a result of the code in this post, you end up with a “tweet” button in your post and page editor while in text mode:

tweet button in text mode

You can select text in your post, then click the button to be presented with a little modal asking you for the URL to share in the tweet:


I’ve been using Bit.ly for my URLs to shorten them and leave more room for the text, so I installed a WP Bit.ly plugin to let me generate those URLs using the built in shortlink button on the page. I copy that URL, and then paste it into the modal.

If you wanted to get really fancy, you could try modifying to code to tie into the Bit.ly API or the built in shortlinks automatically, but so far I’m good with copying and pasting.

After you accept your URL (which you can leave blank if you want), you get markup like this on the page:

<span class="twitterHighlight" data-tweet="Here's my tweetable text" data-shorturl="http://bit.ly.com/">Here's my tweetable text</span>

Your selected text is wrapped in span tags and a few data attributes are in place with the tweet text (same as whatever you had selected) and the URL. From there you can edit the markup if you want to change the URL or modify the tweet text at all.

You’ll want to keep an eye on the text length as you choose what to make tweetable, especially if you are including your handle in the Tweet plus the post or page URL. I generally just test it in preview view to make sure it’s right, adjusting as necessary.

You’ll also have to keep an eye on the characters you’re using, as using quotes will break your markup. You’ll catch this if you give the links a quick test in preview as well.

The beauty of this method is that you can totally customize the way it looks, it fails cleanly if there are javascript issues, and you can use it within your regular paragraphs and lists without breaking them up visually.

The Code

On to the implementation! There are two main parts to this, plus whatever CSS styling you want to use.

Part 1: Creating the Quicktag Button in the Admin

First up, you’ve got to create the button in the admin that generates the markup for you.

My code for this is heavily based on this StackOverflow thread, and looks like this:

This goes into your theme’s functions.php file. Hopefully the comments throughout that code block make it pretty clear what’s going on. This block generates the required markup in your post for the link. So far, this markup won’t do anything visible on the front end, which is where the next block comes in.

Part 2: Creating the Front-End Functionality

At this point, you’ve got the new span in your markup but that’s it. Based on that original WP Tweetable Text plugin, I’ve used javascript to find those spans and create the links, and then I used jQuery to trigger the link click to open in a nice little Tweet pop up window.

Here’s that code:

I like that this creates the link markup and adds the icon using javascript because that way it just doesn’t show up at all if there’s a problem with javascript (no broken link with an icon that doesn’t do what it should).

Part 3: Styling the Links

Finally, you’ll probably want to style your links to make them noticeable (and for fun). As mentioned, I used Font Awesome (which I already had integrated into my site) for the Twitter icon. Here are the styles I have active (in SCSS format):

.twitterHighlight a {
    text-decoration: none;
    background: #f2f0f0;
    color: #333;
    padding: 1px 4px;
    i {
        color: #777;
    &:focus {
        color: #000;
        background: #fff;
        i {
            color: #55acee;

I’ve got light highlighting on the text by way of the background color, and that gets brighter on hover. I’ve also got the Twitter icon going from gray to the Twitter brand blue.

So to recap, you add the PHP code to your theme’s functions.php and the scripts wherever you put those things in your theme (I have a theme.js file in mine). Then, you can add your inline tweets right in the post text editor as you write via the quicktag button!

Two “Where Have You Been All My Life” WordPress Plugins

There’s a type of WordPress plugin that provides functionality that is simple and targeted but so useful that once you’ve got it you wonder how on earth you functioned previously.

Here are two such plugins that I’ve started using recently and now install on almost all of the sites I work on:

1. Schedule Posts Calendar

schedule post calendar screenshotIf you ever need to schedule blog posts to publish in the future (which I think is probably everybody who blogs), you’re familiar with selecting a post date and time.

The problem with the “normal” way of doing this is that you’re just looking at numbers. For me, that means I have to reference a calendar to figure out the day of the week for each date.

Yes, it’s a total first world problem but it’s annoying and it’s unnecessary given that there’s a handy little plugin called Schedule Posts Calendar that adds a calendar picker to that area, letting you click to select a date (and time).

A calendar picker for scheduling WordPress posts? Yes please! It also has a “Today” button in case you want to jump to present.

2. Admin Collapse Subpages

Some sites end up with a lot of pages and subpages, which the admin “All Pages” screen is really not well set up to handle. At a certain point a humongous list of page titles with hyphens indicating hierarchy is basically unusable.

Don’t worry! The Admin Collapse Subpages plugin does exactly what the name implies:

pages with subpage collapse screenshot

It gives you that nice little +/- next to each parent page so that you can collapse all the subpages. So easy, so functional.

What are your must-use utility plugins for WordPress?