0

I need to change src to data-src for iframes inside Wordpress content and add class lazy. I was trying this:

function iframe_image_lazy_load($the_content) {
    $thecontent = get_the_content();
        if(!empty($thecontent)) {
            libxml_use_internal_errors(true);
            $post = new DOMDocument();
            $post->loadHTML(mb_convert_encoding($the_content, 'HTML-ENTITIES', 'UTF-8'));
            $iframes = $post->getElementsByTagName('iframe');
            foreach( $iframes as $iframe ) {
                if( $iframe->hasAttribute('data-src') ) continue;
                $clone = $iframe->cloneNode();
                $src = $iframe->getAttribute('src');
                $iframe->removeAttribute('src');
                $iframe->setAttribute('data-src', $src);
                $srcset = $iframe->getAttribute('srcset');
                $iframe->removeAttribute('srcset');
                if( ! empty($srcset)) {
                    $iframe->setAttribute('data-srcset', $srcset);
                }
                $iframeClass = $iframe->getAttribute('class');
                $iframe->setAttribute('class', $iframeClass . ' lazy');
            };
            return $post->saveHTML();
        }
    }
add_filter('the_content', 'iframe_image_lazy_load', 15);

It's based on other working snippet, but for images. Should this be working?

3
  • Are you trying to modify the iframes in OEmbeds? Or is this coming from somewhere else such as an iframe shortcode? Is this classic editor or something else? I notice you're given the content as a parameter, yet you ignore it and call get_the_content anyway? There's also no return value at the end, filters must always return but this filter only returns if $thecontent is not empty – Tom J Nowell Feb 2 '20 at 16:53
  • Yes, the iframes in oEmbed, in classic editor. – Damian P. Feb 2 '20 at 17:07
  • I see, that it's using the classic editor is of no consequence, but it does rule out you working with iframes generated by more exotic means. OEmbed works the same in both, and has its own sets of filters that can be used. In the meantime, I believe a great deal of insight and help can be sought be looking up how filters and PHP functions work – Tom J Nowell Feb 2 '20 at 21:08
0

The code snippet in your question is a filter, but it isn't built properly:

  • A filter needs a function that takes in the thing to be filtered as the first parameter, and returns the new version
  • Your function ignores the first parameter, breaking any changes that have already been made
  • Your function doesn't always return a value

So, lets start with the function:

function iframe_image_lazy_load($the_content) {
    $thecontent = get_the_content();
        if(!empty($thecontent)) {
            ... do modifications to iframes
            return $post->saveHTML();
        }
    }
add_filter('the_content', 'iframe_image_lazy_load', 15);

First, there are no iframes to modify, those happened on the_content filter, and got passed in as the parameter, but you ignored that and got the original.

As a result, the string you're working with just contains OEmbed URLs, no iframes. Lets fix that:

function iframe_image_lazy_load($content) {
    if(!empty($content)) {
        ... do modifications to iframes
        return $post->saveHTML();
    }
}
add_filter('the_content', 'iframe_image_lazy_load', 15);

Notice I used variable passed to the function, instead of ignoring it and retrieving the original content. I also fixed the indentation levels, bad indentation is a great way to get bugs.

Next, the if statement is unnecessary, lets turn it into a guard and exit early:

function iframe_image_lazy_load($content) {
    if(empty($content)) {
        return $content;
    }
    ... do modifications to iframes
    return $post->saveHTML();
}
add_filter('the_content', 'iframe_image_lazy_load', 15);

OEmbed Filters

Thinking about these things in terms of HTML strings with iframes in them is a limiting and narrow way to view things. These are OEmbeds! So why not filter OEmbeds 🤔, we can even use browser native lazy loading! Why simulate lazy loading by undoing all the savings with JS to implement it?

Something like this:

function lazy_loaded_iframes( $code ) {
    return str_replace ( '<iframe ' , '<iframe loading="lazy"' , $code ); 
}
add_filter( 'embed_oembed_html', 'lazy_loaded_iframes' );
3
  • You're right :) I can use native lazy load. Firefox and Safari should be improved for that ;) But what with background images? – Damian P. Feb 15 '20 at 23:08
  • Lazy loading background images applied via CSS will need an entirely different approach, I don't believe any of the approaches or code in this question or answer will be applicable since they're defined in CSS, modifying the markup with str_replace or regex wouldn't be appropriate – Tom J Nowell Feb 16 '20 at 1:28
  • I was talking about lazy loading background images in thought of using native lazy loading instead of js script, I didn't speak clearly :) Not exactly in this case. – Damian P. Feb 16 '20 at 15:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.