I am developing my custom theme and trying to figure out how to modify the default code for WordPress image inserted into the post content, so I could add support for webP format and have it within <picture> element.

I generate .webp images using cwebp library on my server and PHP exec() while image upload to the Media in WordPress Admin.

The code is:

function my_image_webp($meta, $id){

    if(!isset($meta['sizes'])) {
        return $meta['full'];

    $upload_path = wp_upload_dir();
    $path = $upload_path['basedir'];

    // media upload direktorij
        $file = trailingslashit($upload_path['basedir'].'/').$meta['file'];
        $file = trailingslashit($upload_path['path']).$meta['file'];

    list($orig_type) = @getimagesize($file);
    switch ($orig_type) {
            case IMAGETYPE_PNG:
            $png_image = preg_replace('/\\.[^.\\s]{3,4}$/', '', $file);
            exec("cwebp ".$file." -o ".$png_image.".webp");
            case IMAGETYPE_JPEG:
            $jpg_image = preg_replace('/\\.[^.\\s]{3,4}$/', '', $file);
            exec("cwebp ".$file." -o ".$jpg_image.".webp");

        // return
        wp_update_attachment_metadata($id, $meta);
        return $meta;

add_filter('wp_generate_attachment_metadata','my_image_webp', 10, 2);

Currently, my post content has got <img> element to display the thumbnail within <p> tag, but the <img> tag is a link <a> which points to the full-size image.

Currently I have got this for full-size image in the post content:

    <a href="http://www.example.com/wp-content/uploads/2018/11/image-full.jpg" itemprop="url" title="Some title">
        <img alt="Alt tag of the image" class="alignnone size-full" src="http://www.example.com/wp-content/uploads/2018/11/image-thumb.jpg" width="940" height="529">

I am trying to modify it to get this as result:

    <a href="http://www.example.com/wp-content/uploads/2018/11/image-full.jpg" itemprop="url" title="Some title">
            <source srcset="http://www.example.com/wp-content/uploads/2018/11/image-thumb.webp" type="image/webp" />
            <img alt="Alt tag of the image" class="alignnone size-full" src="http://www.example.com/wp-content/uploads/2018/11/image-thumb.jpg" width="940" height="529">

I have one or more images inserted like this. So, would need to check the whole post content and somehow modify/replace this?

Should I use some preg_replace() or WordPress image_send_to_editor() function?

Maybe using some filter?

Do you have any ideas how to change it?

I have found some solutions for <figure> element, but cannot get it working with <picture>.

  • 1
    I think there are several questions to unpack from this, 1) how do I make WP use picture elements instead of img elements. 2) How do I make WP generate webp versions of images on upload, both of which should be separate questions, not the same questions. Case in point, the first question of picture elements is much easier than the second, but you won't get those answers because people will need to answer the whole question ( and it must be a single whole answer ) – Tom J Nowell Nov 26 '18 at 18:38
  • 1
    I'd recommend editing out the webp part of your question, then opening a second new question once you have the answer to "How do I use picture elements instead of img tags" – Tom J Nowell Nov 26 '18 at 18:38
  • 1
    @TomJNowell - Just added the code for .webp image generation on image upload. – Kiki FIstrek Novi Nov 26 '18 at 18:45

You have to loop through all images inside $post the_content() using foreach().

Which gives us, regex for group matching of <img> tag. Put all images into array().

Start counting from -1 since 0 has the 1st image already in array().

Loop through array() with images, find image with "size-full" with group match 3, if yes, get it's src value with group match 7.

After, replace src="value" extenstion - .png, .jpg ..., assign the replaced string to new variable. Use the new variable and add extension ".webp" to the it.

Replace existing <img> tags with <picture> element and call the function on $content.

function webp_picture_fix($content){
    global $post;
    preg_match_all("/<img(.*?)class=('|\")(.*?)('|\")(.*?)src=('|\")(.*?)('|\")(.*?)>/i", $content, $images);

        $i = -1;
        foreach ($images as $key) {
            //echo $key[$i];
            if(strpos($images[3][$i], 'size-full') !== false){
                //echo "hi";
                $slika_ekstenzija = $images[7][$i];
                $sewebp = preg_replace('/\\.[^.\\s]{3,4}$/', '', $slika_ekstenzija);
                $webp_slika_src = $sewebp.".webp";
                $replacement = '<picture><source srcset="'.$webp_slika_src.'" type="image/webp" /><img'.$images[1][$i].'class='.$images[2][$i].$images[3][$i].$images[4][$i].$images[5][$i].'src='.$images[6][$i].$images[7][$i].$images[8][$i].$images[9][$i].'></picture>';
                $content = str_replace($images[0][$i], $replacement, $content);

    return $content;
add_filter('the_content', 'webp_picture_fix', 9999);
| improve this answer | |
  • Will try this one out. – Kiki FIstrek Novi Nov 26 '18 at 18:56
  • But, as stated "full-size", you need an regex for class attribute with value "size-full" within the <img> tag, so only match thoose <img> with this class "size-full" and replace <img> with <picture>. – Ho Thanh Cyberdelia Nhan Nov 26 '18 at 19:03
  • Exactly! The regex "size-full" for <img> and replace thoose with <picture> insite post content. – Kiki FIstrek Novi Nov 26 '18 at 19:05
  • Maybe somehow to filter and change the output code of add_image_size('full')? – Kiki FIstrek Novi Nov 26 '18 at 19:16

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.