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).

How It Works

The localizer hooks into wp_insert_post_data, which fires before the post is saved to the database. This means URL rewriting happens in a single pass without needing a recursive wp_update_post call.

The process:

  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, re-serialize the blocks back into post content.

A re-entrance guard prevents infinite loops if the filter triggers another save.

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.