GT ACF Blocks Image Localizer

  • JNext lesson
  • KPrevious lesson
  • FSearch lessons
  • EscClear search

Purpose

The image localizer automatically downloads external images referenced in ACF block fields and stores them locally. This improves privacy (no third-party image requests from visitors), reliability (images survive if the external source goes down), and performance (images are served from your own domain or CDN).

The image localizer downloads external images referenced in ACF block fields and rehosts them in your media library automatically. Hotlinked images break, leak visitor data to third parties, and miss your CDN; this module quietly fixes all three in the background after you save.

How It Works

Pipeline diagram of the GT ACF Blocks image localizer: save_post queues the post and schedules a WP-Cron event, then the background worker parses ACF blocks, skips local URLs, downloads and validates external images, and writes replaced URLs back

Since 2.9.0, downloads no longer happen during the save request. The localizer hooks save_post (priority 20), where it only queues the post ID and schedules a single WP-Cron event (acf_blocks_process_image_queue). The queue worker then does the heavy lifting in the background, in bounded batches, so saving an image-heavy post stays fast.

The process, per queued post:

  1. Check if the post content contains any ACF blocks (wp:acf/ in the content).
  2. Parse the block tree from the content.
  3. Walk all ACF blocks recursively (including inner blocks).
  4. For each block’s attrs.data values, scan for image URLs matching common extensions (jpg, jpeg, png, gif, webp, avif, bmp, svg).
  5. For each external URL found, download the image and replace the URL with the local path.
  6. If any URLs were replaced, write the re-serialized blocks back to the post.

A re-entrance guard prevents infinite loops when the worker updates a post, and a processing flag stops overlapping queue runs. If work remains after a batch, the worker reschedules itself. You can also trigger a run manually with the “Process Image Queue Now” button on the Performance & Block Manager card (Settings > ACF Blocks License).

Local URL Detection

The function acf_blocks_is_local_url() determines whether an image URL is already local. The following are treated as local:

  • Exact host match – The URL’s hostname matches the site’s hostname (with or without www.).
  • Subdomain match – The URL’s hostname ends with .{site-domain} (e.g. cdn.example.com when your site is example.com).
  • Bunny CDN – Any URL on *.b-cdn.net is treated as local, since this is a common CDN provider.
  • Custom hosts – Additional hosts can be declared local via the acf_blocks_is_local_image_url filter.

Storage Location

Downloaded images are saved to wp-content/uploads/acf-blocks-plugin/images/. The directory is created on first use with two security measures:

  • An .htaccess file that disables directory listing and blocks PHP execution.
  • A blank index.php file as a fallback directory listing protection.

Filename Strategy

Each downloaded image is named using an MD5 hash of the source URL plus the original file extension: {md5(url)}.{ext}. This provides:

  • Idempotency – The same URL always produces the same filename, so images are never re-downloaded.
  • No collisions – Different URLs produce different filenames even if the original filenames were identical.

If the file extension cannot be determined from the URL, it defaults to jpg. Only allowed extensions are accepted: jpg, jpeg, png, gif, webp, avif, svg, bmp.

Image Validation

After downloading, the image is validated:

  1. wp_get_image_mime() checks that the file is a recognized image type.
  2. For SVG files (which wp_get_image_mime() does not recognize), mime_content_type() is used as a fallback.
  3. If validation fails, the temporary file is deleted and the original URL is kept.

The acf_blocks_is_local_image_url Filter

This filter lets you declare additional hostnames as “local” so their images are not downloaded:

add_filter( 'acf_blocks_is_local_image_url', function( $is_local, $url_host, $site_bare ) {
    if ( $url_host === 'my-cdn.example.com' ) {
        return true;
    }
    return $is_local;
}, 10, 3 );

Parameters:

  • $is_local (bool) – Whether the URL is currently considered local (always false when this filter runs, since built-in checks already passed).
  • $url_host (string) – The full hostname of the image URL.
  • $site_bare (string) – Your site’s hostname with www. stripped.

Quick answers to common questions:

Why localize external images at all?

Privacy, reliability, and performance: no third-party requests from your readers, no images that vanish when the remote site changes, and everything served through your own media pipeline with proper sizes and CDN caching.

Does the localizer re-download images on every save?

No, it tracks already-localized URLs and skips them. Only new external references trigger a download, so saves stay fast even on image-heavy posts.