I have a WordPress blog and am trying to implement the foresight.js image script. In short, I need to target all post images, swap out the src, width, & height attributes with data-src, data-width, & data-height attributes. I then need to duplicate the image line and wrap it in <noscript> tags. This is the structure I’m trying to have WordPress generate/create:

<img data-src="https://wordpress.stackexchange.com/questions/71164/wordpress/image/url/pic.jpg" data-width="{get width of image with PHP & pass-in that value here} data-height="{get height of image with PHP and pass-in that value here}" class="fs-img">
<noscript>
    <img src="https://wordpress.stackexchange.com/questions/71164/wordpress/image/url/pic.jpg">
</noscript>

I have searched the WordPress codex and the best possible route I can find are to use filters (ie. ‘get_image_tag’ & ‘image_tag’) for modifying the html that WordPress outputs for each image. I’m thinking that one of these options should work, or that I can do some pattern matching with regex (I know, not ideal), throw in a preg_replace and then inject this back into the_content filter.

I have tried some of these options but cannot get any to work. Could someone please offer some help? Found one suggestion here, but can’t even get it to work!

‘get_image_tag’ attempt:

Found this particular one on the web, but it would need modified to fit my logic (see above structure)…can’t make sense of what the preg_replace array is doing on my own.

<?php function image_tag($html, $id, $alt, $title) {
    return preg_replace(array(
        "https://wordpress.stackexchange.com/".str_replace('//','\/\/',get_bloginfo('url')).'/i',
        '/\s+width="\d+"/i',
        '/\s+height="\d+"/i',
        '/alt=""/i'
    ),
    array(
        '',
        '',
        '',
        alt=""" . $title . '"'
    ),
    $html);
}
add_filter('get_image_tag', 'image_tag', 0, 4);
?>

Another ‘get_image_tag’ attempt:

<?php function get_image_tag($id, $alt, $title, $align, $size="full") {
    list($width, $height, $type, $attr) = getimagesize($img_src);
    $hwstring = image_hwstring($width, $height);

    $class="align" . esc_attr($align) . ' size-' . esc_attr($size) . ' wp-image-' . $id;
    $class = apply_filters('get_image_tag_class', $class, $id, $align, $size);

    $html="<img src="" . esc_attr($img_src) . '" alt="' . esc_attr($alt) . '" title="' . esc_attr($title).'" data-width="' . $width . '" data-height="' . $height . '" class="' . $class . ' fs-img" />';
    $html = apply_filters( 'get_image_tag', $html, $id, $alt, $title, $align, $size);

    return $html;
}
?>

Pattern-matching attempt:

Tried creating my own regex on this one, but not sure if it’s correct.

<?php function restructure_imgs($content) {
    global $post;
    $pattern = "/<img(.*?)src=('|\")(.*?).(bmp|gif|jpeg|jpg|png)(|\")(.*?)>/i";

    list($width, $height, $type, $attr) = getimagesize($2$3.$4$5);
    $hwstring = image_hwstring($width, $height);

    $replacement="<img$1data-src=$2$3.$4$5 title="".$post->post_title.'" data-width="'.$width.'" data-height="'.$height.'" class="fs-img"$6>';
    $content = preg_replace($pattern, $replacement, $content);
    return $content;
}
add_filter('the_content', 'restructure_imgs');
?>

Unfortunately can’t get any of these examples to work. Any help or sharing your pre-written scripts/functions would be much appreciated! Thanks for helping a student learn!!

2 Answers
2

The filters you are trying to use run on image insertion, so it is not possible to swap all the images already present in your posts using these filters. It should work, however, if you intend to change to img tags from now on.

The filter the_content, however, is applied to the post after it is retrieved from the database and before displaying it to screen. I believe that, in order to make a change to your existing posts without reinserting the images, you could use this filter.

You can parse the_content using the PHP DOMDocument class. When it comes to HTML parsing in PHP, do not use regex.

I wrote a sample function for what you want to do, it’s a bit verbose in order to explain the passages. Feel free to tweak it at will.

<?php
function foresight_hires_img_replace($the_content) {
    // Create a new istance of DOMDocument
    $post = new DOMDocument();
    // Load $the_content as HTML
    $post->loadHTML($the_content);
    // Look up for all the <img> tags.
    $imgs = $post->getElementsByTagName('img');

    // Iteration time
    foreach( $imgs as $img ) {
        // Let's make sure the img has not been already manipulated by us
        // by checking if it has a data-src attribute (we could also check
        // if it has the fs-img class, or whatever check you might feel is
        // the most appropriate.
        if( $img->hasAttribute('data-src') ) continue;

        // Also, let's check that the <img> we found is not child of a <noscript>
        // tag, we want to leave those alone as well.
        if( $img->parentNode->tagName == 'noscript' ) continue;

        // Let's clone the node for later usage.
        $clone = $img->cloneNode();

        // Get the src attribute, remove it from the element, swap it with
        // data-src
        $src = $img->getAttribute('src');
        $img->removeAttribute('src');   
        $img->setAttribute('data-src', $src);

        // Same goes for width...
        $width = $img->getAttribute('width');
        $img->removeAttribute('width');
        $img->setAttribute('data-width', $width);

        // And height... (and whatever other attribute your js may need
        $height = $img->getAttribute('height');
        $img->removeAttribute('height');
        $img->setAttribute('data-height', $height);

    // Get the class and add fs-img to the existing classes
        $imgClass = $img->getAttribute('class');
        $img->setAttribute('class', $imgClass . ' fs-img');

        // Let's create the <noscript> element and append our original
        // tag, which we cloned earlier, as its child. Then, let's insert
        // it before our manipulated element
        $no_script = $post->createElement('noscript');
        $no_script->appendChild($clone);
        $img->parentNode->insertBefore($no_script, $img);
    };

     return $post->saveHTML();
 }

 add_filter('the_content', 'foresight_hires_img_replace');
 ?>

I didn’t test it specifically with WordPress, but I tested it with a sample post output and it should work.

Leave a Reply

Your email address will not be published. Required fields are marked *