2

In a nutshell, this is what I'm trying to do:

  1. Get all <img> tags from a document
  2. Set a data-src attribute (for lazy loading)
  3. Empty their sources (for lazy loading)
  4. Inject a <noscript> tag after this image

1-3 are fine. I just can't get the created <noscript> tag to be beside the image correctly.

I'm trying with insertBefore but I'm open for suggestions:

// Create a DOMDocument instance
$dom = new DOMDocument;

$dom->formatOutput = true;
$dom->preserveWhiteSpace = false;

// Loads our content as HTML
$dom->loadHTML($content);

// Get all of our img tags
$images = $dom->getElementsByTagName('img');

// How many of them
$len = count($images);

// Loop through all the images in this content
for ($i = 0; $i < $len; $i++) {

    // Reference this current image
    $image = $images->item($i);

    // Create our fallback image before changing this node
    $fallback_image = $image->cloneNode();

    // Add the src as a data-src attribute instead
    $image->setAttribute('data-src', $src);

    // Empty the src of this img
    $image->setAttribute('src', '');

    // Now prepare our <noscript> markup
    // E.g <noscript><img src="foobar.jpg" /></noscript>
    $noscript = $dom->createElement("noscript");
    $noscript->appendChild( $fallback_image );

    $image->parentNode->insertBefore( $noscript, $image );
}

return $dom->saveHTML();

Having two images in the page, this is the result (abbreviated for clarity's sake):

Before:

<div>
    <img />
    <p />
</div>
<p>
    <img />
</p>

After:

<div>
    <img /> <!-- this should be the fallback wrapped in <noscript> that is missing -->
    <p>
        <img />
    </p>
</div>
<p>
    <img /> <!-- nothing happened here -->
</p>

Using $dom->appendChild works but the <noscript> tag should be beside the image and not at the end of the document.

My PHP skills are very rusty so I'd appreciate any clarification or suggestions.

UPDATE

Just realised saveHTML() was also adding <DOCTYPE><html><body> tags, so I've added a preg_replace (until I find a better solution) to take care of removing that.

Also, the output I have pasted before was based on the inspector of Chrome's Developer Tools.

I checked the viewsoure to see what was really going on (and thus found out about the tag).

This is what's really happening: https://eval.in/114620

<div>
    <img /> </noscript> <!-- wha? just a closing noscript tag -->
    <p />
</div>
<p>
    <img /> <!-- nothing happened here -->
</p>
7
  • Why you don't use simplehtmldom class to parse dom?????? Commented Feb 27, 2014 at 10:30
  • @yonessafari Using third party libraries would be the last resort Commented Feb 27, 2014 at 14:23
  • 1
    If you want to wrap the <img /> in a <noscript>, why would you use insertBefore. This answer might help: stackoverflow.com/a/873166/979455 Commented Mar 6, 2014 at 15:08
  • 1
    Couple of concerns: You never define your $src (is this intentional?), and running your reduced test case with your example ensures that both of your images are wrapped in <noscript> tags. See eval.in/114591. I realise this isn't the intended behaviour either, but can you think of any reason for why your output would deviate this much from the highly simplified test case you've provided here? Commented Mar 6, 2014 at 15:21
  • 1
    I also figured out that the count is not implemented correctly—count() always returns one, ensuring there's always just going to be one iteration. To get the length of the array, use $images->length. Commented Mar 6, 2014 at 15:32

1 Answer 1

2

SOLVED

So this is how I fixed it: https://eval.in/117959

I think it's a good idea to work with new nodes after they have being inserted into the DOM:

$noscript = $dom->createElement("noscript");
$noscriptnode = $image->parentNode->insertBefore( $noscript, $image );

// Only now work with noscript by adding it's contents etc...

Also when it's inserted with "insertBefore" - it's a good idea to save it's reference.

$noscriptnode = $image->parentNode->insertBefore( $noscript, $image );

And another thing: I wasrunning this code within Wordpress. Some hooks were being run afterwards which was messing up my markup.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.