Replace image attributes for lazyload plugin on image elements with a specific class
I am using WordPress and I want to lazy load certain images only. I found a way to create the data-src attributes here and replace the src attribute with the correct image https://wordpress.stackexchange.com/questions/60792/replace-image-attributes-for-lazyload-plugin-data-src . Right now my code is applying lazy loading to all images, and I just want to apply them to images with lazy loading class.
This is how my code looks like
// Lazyload Converter
function add_lazyload($content) {
$content = mb_convert_encoding($content, 'HTML-ENTITIES', "UTF-8");
$dom = new DOMDocument();
@$dom->loadHTML($content);
$images = [];
foreach ($dom->getElementsByTagName('img') as $node) {
$images[] = $node;
}
foreach ($images as $node) {
$fallback = $node->cloneNode(true);
$oldsrc = $node->getAttribute('src');
$node->setAttribute('data-src', $oldsrc );
$newsrc = get_template_directory_uri() . '/assets/placeholders/squares.svg';
$node->setAttribute('src', $newsrc);
$oldsrcset = $node->getAttribute('srcset');
$node->setAttribute('data-srcset', $oldsrcset );
$newsrcset = '';
$node->setAttribute('srcset', $newsrcset);
$noscript = $dom->createElement('noscript', '');
$node->parentNode->insertBefore($noscript, $node);
$noscript->appendChild($fallback);
}
$newHtml = preg_replace('/^<!DOCTYPE.+?>/', '', str_replace( array('<html>', '</html>', '<body>', '</body>'), array('', '', '', ''), $dom->saveHTML()));
return $newHtml;
}
add_filter('the_content', 'add_lazyload');
add_filter('post_thumbnail_html', 'add_lazyload');
how can I get an element by class instead of using a tag?
source to share
you can use xpath (from domxpath); xpath is a query language for selecting nodes from XML / HTML documents.
Unfortunately, the selection of elements that have a class that is a separate phrase lazy-load
is slightly collapsed with xpath; it is not as concise as you might be used tocss-selectors; xpath has no shorthand attribute selectors like @attr~="lazy-load"
etc.
Here's an example of how you would select all elements <img>
that have a class lazy-load
:
// create a DOMXPath instance that operates on your DOMDocument instance $dom
$xpath = new DOMXPath( $dom );
// select nodes by some criteria (returns a non-liveΒΉ DOMNodeList)
$images = $xpath->query( '//img[contains(concat(" ", normalize-space(@class), " "), " lazy-load ")]' );
// then apply the same operations to the nodes again as in your last foreach loop
foreach ($images as $node) {
$fallback = $node->cloneNode(true);
// etc.
}
1) Even though it is not officially documented anywhere (as far as I know) DOMNodeList
, the returned DOMXPath
one is not "live", and not DOMNodeList
returned DOMDocument
, I believe. So, your first one foreach()
should be unnecessary. But you should try to try.
I would suggest doing any of the following, but if you are sure that the only class those elements will have <img>
will be lazy-load
, that is, the attribute class
will always be exactly lazy-load
, without any spaces and / or other classes, you can also use this , a much simpler query:
$images = $xpath->query( '//img[@class="lazy-load"]' );
or, if elements <img>
can have multiple classes, but will never have other classes containing the phrase lazy-load
(for example class="thumbnail lazy-loading"
, for example), you can use:
$images = $xpath->query( '//img[contains(@class,"lazy-load")]' );
source to share