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="https://wordpress.stackexchange.com/questions/220739/([^"]+)"https://wordpress.stackexchange.com/", $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.