New feature gone bad
Just before launch we came up with a simple feature which would hopefully improve the user experience, and wouldn’t take long to build at all. It was a simple carousel which would give users easy access to our different print collections. While the other guys in the studio added new images for each product, I built the new carousel an ACF Repeater, as I have many times before.
The carousel was built, with a little thumbnail for each collection. Any page containing the carousel promptly went into meltdown.
Coming back to the problem
Looking at the Network tab in Chrome’s inspector or Firefox developer tools, there was suddenly a staggering 34 second TTFB (time to first byte)! What the hell would be causing that?
The new feature was considered a “nice to have”, so we removed it temporarily to get the shop live. But it kept niggling away at me. A few days later, with the shop live and running smoothly, I found myself with a bit of down-time and went back to the strange, site-stalling carousel.
I patiently re-wrote the thing, which didn’t take long. Exactly the same result.
The initial code
The code in question was simple enough, and I’d used some variation of it dozens of times. Here’s a stripped down version of what I was using:
<?php // Collection carousel if ( have_rows('collections_carousel', 'options') ) : ?> <div class="carousel-wrapper"> <?php while ( have_rows('collections_carousel', 'options') ) : the_row(); $name = get_sub_field('name'); $link = get_sub_field('link'); $icon = get_sub_field('icon'); $size = 'thumbnail'; ?> <div class="item"> <a href="<?php echo $link; ?>" title="<?php echo $name; ?>"> <img src="<?php echo $icon['sizes'][$size]; ?> alt="<?php echo $image['alt']; ?>" /> </a> </div><!-- .item --> <?php endwhile; ?> </div><!-- .carousel-wrapper --> <?php endif; ?>
Stripping it back even to these bare bones (and removing the carousel functionality) made no difference, so I chopped out chunks of code bit by bit to see where I got some variations in performance.
As soon as I removed the image the page loaded immediately, each and every time. I put the kettle on and took a moment to ponder.
Looking at my functions.php file and the WordPress media library, I had a huge amount of images and image sizes. Most of the images I was displaying in the page via ACF were being returned as arrays, and the more image sizes you have defined, the slower that will be. Even as I’d been building this ACF repeater, dozens more large images were being added to the site.
To test this out I changed the image field in the repeater to return an ID instead of an array and adjusted the code.
The change to the both the custom field and the code was minor, but now the TTFB had dropped down to a fraction of a second.
Changing the image fields to return an ID instead required only a tiny tweak, and I did the same thing wherever possible to give performance a little boost. Here’s the While loop with the updated image:
<?php while ( have_rows('collections_carousel', 'options') ) : the_row(); $name = get_sub_field('name'); $link = get_sub_field('link'); $icon = get_sub_field('icon'); ?> <div class="item"> <a href="<?php echo $link; ?>" title="<?php echo $name; ?>"> <?php echo wp_get_attachment_image( $icon, $size ); ?> </a> </div> <?php endwhile; ?>
This small change means a lot less information is being dealt with – image arrays come with a lot of excess information that I’ve probably never used.
If you’re running an image-heavy site with Advanced Custom Fields then it’s definitely worth switching to image IDs instead of arrays wherever possible!