0

Is there a way of writing a function that will replace the standard markup of an inline image within the_content, with a way that moves the size class to a parent container, and a series of data attributes for different sizes of the image?

I've tried using a preg_match function, originally written to remove the autop around the image, but unable to extrapolate the ID of the image and write a new output from that (when I do, it works, but only does so for the first image - all other content from the_content vanishes).

I want this:

<p>
  <img class="alignnone size-medium wp-image-2093" src="http://website.com/wp-content/uploads/image-600x400.jpg" alt="image" width="600" height="400" />
</p>

To become:

<figure id="image-2093" class="size-medium">
  <img src="http://website.com/wp-content/uploads/image-300x200.jpg"
       data-medium="http://website.com/wp-content/uploads/image-600x400.jpg"
       data-large="http://website.com/wp-content/uploads/image-1200x800.jpg"
  />
</figure>

I want to avoid anything using image_send_to_editor, and just use something that will work across the board rather than only on new image embeds.

Thanks in advance.

Edit:

This wass the mangled version of the remove autop preg_match function I had. It generates the output, but without any of the variables (so no value for the id, src or data attributes), and it only does it for the first image while removing all other content. A whole bunch of failure really.

function s7g_img_unautop($img) {

    $img = preg_replace('/<p>\\s*?(<a .*?><img.*?><\\/a>|<img.*?>)?\\s*<\\/p>/s', '<figure><div class="media-wrap">$1</div></figure>', $img);

    preg_match('~wp-image-(.*?)"~', $img, $output);
    $imgID = $output[1];
    $imgL = wp_get_attachment_image_src($imgID, 'thumbnail');
    $imgM = wp_get_attachment_image_src($imgID, 'medium');
    $imgH = wp_get_attachment_image_src($imgID, 'large');

    $image = '<figure id="image-'.$imgID.'"><img src="'.$imgL[0].'"  data-medium="'.$imgM[0].'" data-large="'.$imgL[0].'" /></figure>';     

    return $image;

}
add_filter( 'the_content', 's7g_img_unautop', 30 );
  • preg_match should be perfectly adequate to tackle what you're trying to do, how are you using it and what regex are you using? – totels Mar 15 '16 at 13:04
  • Hi @totels, I edited the original question to include the code I was using. – Nathan Mar 16 '16 at 7:52
3

Most of the code is taken from Core files, also you might have to modify it a bit as per your own requirement.

Here is the core file link, where I got the idea from: https://developer.wordpress.org/reference/functions/wp_make_content_images_responsive/

You need to take care of the open p tag just before the image.

Was in hurry, so instead of waiting to check what you've tried, and modifying that, I ended up creating this snippet quickly.

add_filter( 'the_content', 'wpse_220739_modify_images', 100 );

/**
 * Get all the image tags from content and modify them
 *
 * @param $content
 *
 * @return mixed
 */
function wpse_220739_modify_images( $content ) {
    if ( ! preg_match_all( '/<img [^>]+>/', $content, $matches ) ) {
        return $content;
    }

    $selected_images = $attachment_ids = array();

    foreach ( $matches[0] as $image ) {
        if ( preg_match( '/size-([a-z]+)/i', $image, $class_size ) && preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) && $image_size = $class_size[1] && $attachment_id = absint( $class_id[1] ) ) {
            /*
             * If exactly the same image tag is used more than once, overwrite it.
             * All identical tags will be replaced later with 'str_replace()'.
             */
            $selected_images[ $image ] = $attachment_id;
            // Overwrite the ID when the same image is included more than once.
            $attachment_ids[ $attachment_id ] = true;
        }
    }
    foreach ( $selected_images as $image => $attachment_id ) {
        $content = str_replace( $image, wpse_220739_modify_image_tag( $image, $attachment_id, $image_size ), $content );
    }

    return $content;
}

/**
 * Modifies the image tag, by prepending a figure tag and adding necessary classes
 *
 * @param $image
 * @param $attachment_id
 * @param $image_size
 *
 * @return mixed|string
 */
function wpse_220739_modify_image_tag( $image, $attachment_id, $image_size ) {
    $image_src = preg_match( '/src="([^"]+)"/', $image, $match_src ) ? $match_src[1] : '';
    list( $image_src ) = explode( '?', $image_src );

    // Return early if we couldn't get the image source.
    if ( ! $image_src ) {
        return $image;
    }
    //Get attachment meta for sizes
    $size_large  = wp_get_attachment_image_src( $attachment_id, 'large' );
    $size_medium = wp_get_attachment_image_src( $attachment_id, 'medium' );

    $size_large  = $size_large ? $size_large[0] : '';
    $size_medium = $size_medium ? $size_medium[0] : '';

    //Check if the image already have a respective attribute
    if ( ! strpos( $image, 'data-large' ) && ! empty( $size_large ) ) {
        $attr = sprintf( ' data-large="%s"', esc_attr( $size_large ) );
    }

    if ( ! strpos( $image, 'data-medium' ) && ! empty( $size_medium ) ) {
        $attr .= sprintf( ' data-medium="%s"', esc_attr( $size_medium ) );
    }

    // Add 'data' attributes
    $image = preg_replace( '/<img ([^>]+?)[\/ ]*>/', '<img $1' . $attr . ' />', $image );
    //Append figure tag
    $r_image = sprintf( '<figure id="image-%d" class="size-%s">', $image_size, $attachment_id );
    $r_image .= $image . '</figure>';

    return $r_image;

}

You'd need to add another check, if a Image tag already have a surrounding <figure> tag or not, but your main issue of not being able to modify all the images in content should be fixed by this.

Updated: The second foreach loop needs to be outside (Of course, silly me for not noticing that), that should help.

  • Thanks Sven. I gave this a shot, but it doesn't seem to be having any effect. I tried to change that first preg_match_all regex to /<img [^>]+>/ as well, as per the original reference from the core, but that throws up the error preg_replace() compilation failed: unmatched parentheses at offset 3 in blah.php on line 67 – Nathan Mar 16 '16 at 7:34
  • Yeah, it seems the code got bit messed up while adding it as answer on WPSE, I've updated the code, see if it works for you. – sven Mar 16 '16 at 9:07
  • Getting close, but there's still two issues. 1) $image_size always returns a value of "1", rather than "medium", "large", etc. 2) It's only working on the first image - or any immediately following images that have 100% identical output. As soon as one image has anything different (different source, or even just a different order of classes), it doesn't apply and stops applying to anything after. – Nathan Mar 16 '16 at 12:30
  • That must be incorrect regex, will update it. – sven Mar 18 '16 at 5:29
  • Just coming back to this, I don't think the first regex is the issue. If I print out the array of $matches, then it's picking up on all of them, so the issue must be somewhere within the foreach argument. I'm guessing something to do with $attachment_id. – Nathan Mar 28 '16 at 12:41

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.