Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 67 additions & 3 deletions php/class-delivery.php
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,38 @@ public function get_media_tags( $content, $tags = 'img|video' ) {
return $media;
}

/**
* Get the image size dimensions from the tags if available.
*
* @param array $tags The media tags found in the content.
* @param array $relation The relation data for the media item.
*
* @return array An array with width and height, or empty if not found.
*/
private function get_image_size_within_tags( $tags, $relation ) {
// If we don't have a post ID, we can't find a size, so return empty.
if ( empty( $relation['post_id'] ) ) {
return array();
}
$post_id = intval( $relation['post_id'] );

// Look through the tags to find one that matches our post ID and has a size slug, then get the size from that slug.
foreach ( $tags as $set ) {
// If this set doesn't have a size slug, skip.
if ( empty( $set['atts']['data-size-slug'] ) ) {
continue;
}

// If this tag's post ID matches our relation's post ID, get the size from the slug and return it.
if ( $post_id === $set['id'] ) {
$size = $this->media->get_size_from_slug( $set['atts']['data-size-slug'] );
return ( empty( $size ) ) ? array() : $size; // Return the size if found, otherwise return empty array.
}
}

return array();
}

/**
* Convert media tags from Local to Cloudinary, and register with String_Replace.
*
Expand All @@ -1025,7 +1057,12 @@ public function convert_tags( $content, $context = 'view' ) {
}

$tags = $this->get_media_tags( $content, 'img|video|article|source' );
$tags = array_map( array( $this, 'parse_element' ), $tags );
$tags = array_map(
function ( $tag ) use ( $content ) {
return $this->parse_element( $tag, $content );
},
$tags
);
$tags = array_filter( $tags );

$replacements = array();
Expand Down Expand Up @@ -1082,7 +1119,9 @@ public function convert_tags( $content, $context = 'view' ) {
$public_id = ! is_admin() ? $relation['public_id'] . '.' . $relation['format'] : null;
// Get merged transformations including overlays.
$merged_transformations = Relate::get_transformations( $relation['post_id'], true );
$cloudinary_url = $this->media->cloudinary_url( $relation['post_id'], array(), $merged_transformations, $public_id );

$size = $this->get_image_size_within_tags( $tags, $relation );
$cloudinary_url = $this->media->cloudinary_url( $relation['post_id'], $size, $merged_transformations, $public_id );
if ( empty( $cloudinary_url ) ) {
continue;
}
Expand Down Expand Up @@ -1220,6 +1259,15 @@ protected function standardize_tag( $tag_element ) {
$size = $has_wp_size;
}
}

// Retrieve size from the parent figure class of the image if it exists.
if ( ! empty( $tag_element['atts']['data-size-slug'] ) && 'img' === $tag_element['tag'] ) {
$slug_size = $this->media->get_size_from_slug( $tag_element['atts']['data-size-slug'] );
if ( ! empty( $slug_size ) ) {
$size = $slug_size;
}
}

// Unset srcset and sizes.
unset( $tag_element['atts']['srcset'], $tag_element['atts']['sizes'] );

Expand Down Expand Up @@ -1437,10 +1485,11 @@ public function rebuild_tag( $tag_element ) {
* Parse an html element into tag, and attributes.
*
* @param string $element The HTML element.
* @param string $content Optional full HTML content for parent context.
*
* @return array|null
*/
public function parse_element( $element ) {
public function parse_element( $element, $content = '' ) {
/**
* Filter to skip parsing an element.
*
Expand Down Expand Up @@ -1551,6 +1600,21 @@ public function parse_element( $element ) {
if ( in_array( $tag_element['tag'], array( 'img', 'source' ), true ) ) {
// Check if this is a crop or a scale.
$has_size = $this->media->get_size_from_url( $this->sanitize_url( $raw_url ) );

// If no size found in URL, try to extract from parent figure element so we can apply cropping if needed.
if ( empty( $has_size ) && $has_sized_transformation ) {
$size_slug = $this->media->get_size_slug_from_parent_figure_class( $tag_element['original'], $content );

if ( ! empty( $size_slug ) ) {
$has_size = $this->media->get_size_from_slug( $size_slug );
if ( ! empty( $has_size ) ) {
$attributes['data-size-slug'] = $size_slug;
$tag_element['width'] = $has_size[0];
$tag_element['height'] = $has_size[1];
}
}
}

if ( ! empty( $has_size ) && ! empty( $item['height'] ) ) {
$file_ratio = round( $has_size[0] / $has_size[1], 2 );
$original_ratio = round( $item['width'] / $item['height'], 2 );
Expand Down
59 changes: 59 additions & 0 deletions php/class-media.php
Original file line number Diff line number Diff line change
Expand Up @@ -3267,4 +3267,63 @@ public function upgrade_settings( $previous_version, $new_version ) {
$setting->save_value();
}
}


/**
* Get the size dimensions based on the size slug.
*
* Uses WordPress core API to retrieve registered image subsizes, which handles both
* built-in sizes (thumbnail, medium, large, etc.) and custom registered sizes.
*
* @param string $size_slug The WordPress size slug (e.g., 'thumbnail', 'medium', 'large').
*
* @return array|null An array with width and height, or null if not found.
*/
public function get_size_from_slug( $size_slug ) {
// Use WordPress core API to get all registered image subsizes.
$image_subsizes = wp_get_registered_image_subsizes();

// Check if the requested size exists in registered subsizes.
if ( ! isset( $image_subsizes[ $size_slug ] ) ) {
return null;
}

$size_data = $image_subsizes[ $size_slug ];

// Return width and height if both are present and valid.
if ( ! empty( $size_data['width'] ) && ! empty( $size_data['height'] ) ) {
return array( (int) $size_data['width'], (int) $size_data['height'] );
}

return null;
}


/**
* Extract WordPress image size from parent figure element.
*
* @param string $element The img tag element.
* @param string $content The full HTML content.
*
* @return string|null The WordPress size slug (e.g., 'thumbnail', 'medium'), or null if not found.
*/
public function get_size_slug_from_parent_figure_class( $element, $content ) {
// If content is empty, we can't find a parent figure, so return null.
if ( empty( $content ) ) {
return null;
}

// Escape the element for use in regex.
$escaped_element = preg_quote( $element, '#' );

// Pattern: <figure class="...size-{size}...">...img element...[optional figcaption]</figure> .
$pattern = '#<figure\s+[^>]*class="[^"]*\bsize-(\w+)\b[^"]*"[^>]*>.*?' . $escaped_element . '.*?</figure>#is';

// Look for the parent figure tag that contains this img element.
if ( preg_match( $pattern, $content, $matches ) ) {
return $matches[1];
}

return null;
}
}