Serving Images From Multiple CDNs In WordPress

Thanks for WordPress flexibility and it’s hundreds of filters and action, it is possible to serve images from Multiple CDNs with completely different URL structures. If you are wondering why would anyone do this think about the following scenario.

You were a customer of CDN A and you moved your Website to WP Engine (Very smart move, I highly recommend them). Now that you are on WP Engine, you want to take advantage of their CDN service but you have so many images and files on CDN A that it would be impossible to migrate it over to WP Engine over night. What if you have a contract that expires a few months in the future but want to start uploading to the new CDN right away so when the time comes you have less files to transfer.

WordPress’ Filters To The Rescue

It is possible to dynamically change the image source dynamically using WordPress’ filters. Two filters to be exact. Since you have been uploading all your images and files to CDN A, WordPress is generating a guid for every image at the time a new image gets uploaded. This field will allows to compare old CDN urls to new CDN URLs and rewrite the URLs on the fly, but only when needed.

Rewriting the Main Image Source

// Rewrite image source url to handle multiple CDNs
add_filter( 'wp_get_attachment_image_src', 'multiple_cdn_img_src_rewriting', 100, 4 );
function img_src_rewriting( $image, $attachment_id, $size, $icon ) {
    // Old CDN URL
    $needle = '//';
    // Get the GUID field for this image
    $guid = get_post_field( 'guid', $attachment_id );
    // Try finding the old CDN in GUID
    $is_old_cdn = strpos( $guid, $needle );

    // Is it the old CDN?
    if( $is_old_cdn !== false ) {
        // Set the image src url to whatever the GUID field was
        $image[0] = $guid;

    // Return the array
    return $image;

You may be wondering why is necessary to rewrite the URL since the GUID says it’s somewhere else. The reason is because WordPress doesn’t actually use the GUID field to generate the URL to the image. It uses the default settings from your environment. You can take a look at your current settings by printing the contents of wp_upload_dir().

// Array of key => value pairs
$upload_dir = wp_upload_dir();
print_r( upload_dir );

$upload_dir now contains something like the following (if successful)

Array (
    [path] => C:\path\to\wordpress\wp-content\uploads\2017\01
    [url] =>
    [subdir] => /2017/01
    [basedir] => C:\path\to\wordpress\wp-content\uploads
    [baseurl] =>
    [error] =>

wp_upload_dir() Key => Value Descriptions

  • [path] – base directory and sub directory or full path to upload directory.
  • [url] – base url and sub directory or absolute URL to upload directory.
  • [subdir] – sub directory if uploads use year/month folders option is on.
  • [basedir] – path without subdir.
  • [baseurl] – URL path without subdir.
  • [error] – set to false.

Rewriting Image Srcset

Next do the same for responsive images and their different srcset(s). The approach is almost identical but we of course we use a different filter for that.

// Rewrite image srcset url to handle multiple CDNs
add_filter( 'wp_calculate_image_srcset', 'multiple_cdn_img_srcset_rewriting', 1, 5 );
function multiple_cdn_img_srcset_rewriting( $sources, $size_array, $image_src, $image_meta, $attachment_id ) {
    $upload_dir = wp_upload_dir();
    $cdn_url = '//';
    foreach( $sources as $key => $other ) {
        if( strpos( $image_src, $cdn_url ) !== false ) {
            $sources[$key]['url'] = str_replace( $upload_dir['baseurl'], $cdn_url, $sources[$key]['url'] );
    // Return the new sources
    return $sources;

There you have it. Now you can serve images from different CDNs and URLs. Your situation is probably unique but the filters and approach to solving this problem might follow similar steps. Please do comment below if you have any questions or found these snippets useful to you.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s