Repository navigation
fix: hook wp_get_attachment_image_src to keep Cloudinary URLs as the last word #1303
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
ab6e239
df197d1
da113bf
58c164e
6bfc2a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1187,9 +1187,7 @@ public function attachment_url( $url, $attachment_id ) { | |
| } | ||
|
|
||
| if ( | ||
| false === $this->in_downsize | ||
| && ! doing_filter( 'content_save_pre' ) | ||
| && ! Utils::is_saving_metadata() | ||
| $this->is_replacement_paused( $attachment_id, false ) // false: videos still need their own URL corrected here. | ||
| /** | ||
| * Filter doing upload. | ||
| * If so, return the default attachment URL. | ||
|
|
@@ -1198,11 +1196,13 @@ public function attachment_url( $url, $attachment_id ) { | |
| * | ||
| * @return bool | ||
| */ | ||
| && ! apply_filters( 'cloudinary_doing_upload', false ) | ||
| || apply_filters( 'cloudinary_doing_upload', false ) | ||
| ) { | ||
| if ( ! $this->is_cloudinary_url( $url ) && $this->cloudinary_id( $attachment_id ) ) { | ||
| $url = $this->cloudinary_url( $attachment_id ); | ||
| } | ||
| return $url; | ||
| } | ||
|
|
||
| if ( ! $this->is_cloudinary_url( $url ) && $this->cloudinary_id( $attachment_id ) ) { | ||
| $url = $this->cloudinary_url( $attachment_id ); | ||
| } | ||
|
|
||
| return $url; | ||
|
|
@@ -1802,7 +1802,7 @@ public function filter_downsize( $image, $attachment_id, $size ) { | |
| } | ||
|
|
||
| // Don't do this while saving. | ||
| if ( true === $this->in_downsize || doing_filter( 'content_save_pre' ) || wp_attachment_is( 'video', $attachment_id ) || Utils::is_saving_metadata() ) { | ||
| if ( $this->is_replacement_paused( $attachment_id ) ) { | ||
| return $image; | ||
| } | ||
|
|
||
|
|
@@ -1836,6 +1836,81 @@ public function filter_downsize( $image, $attachment_id, $size ) { | |
| return $image; | ||
| } | ||
|
|
||
| /** | ||
| * Whether URL replacement should be paused for this attachment right now: while a | ||
| * downsize is already in progress (re-entrancy guard), while content or metadata is being | ||
| * saved, or -- unless explicitly included -- for a video attachment, since there is no | ||
| * "image size" to downsize a video to. | ||
| * | ||
| * Shared by filter_downsize(), filter_attachment_image_src(), and attachment_url(), so the | ||
| * save-state/re-entrancy logic lives in one place. | ||
| * | ||
| * @param int $attachment_id The attachment ID. | ||
| * @param bool $exclude_videos Whether a video attachment should also count as paused. | ||
| * | ||
| * @return bool | ||
| */ | ||
| private function is_replacement_paused( $attachment_id, $exclude_videos = true ) { | ||
| if ( true === $this->in_downsize || doing_filter( 'content_save_pre' ) || Utils::is_saving_metadata() ) { | ||
| return true; | ||
| } | ||
|
|
||
| return $exclude_videos && wp_attachment_is( 'video', $attachment_id ); | ||
| } | ||
|
|
||
| /** | ||
| * Correct wp_get_attachment_image_src() results that image_downsize() missed, or that a | ||
| * later-priority plugin overwrote, so Cloudinary keeps the last word on this specific, | ||
| * commonly-targeted core hook. | ||
| * | ||
| * @param array|false $image The image src array, or false. | ||
| * @param int $attachment_id The ID of the attachment. | ||
| * @param string|array $size The requested size of the image. | ||
| * @param bool $icon Whether the image should be treated as an icon. | ||
| * | ||
| * @return array|false The image array of size and url. | ||
| * @uses filter:wp_get_attachment_image_src | ||
| */ | ||
| public function filter_attachment_image_src( $image, $attachment_id, $size, $icon ) { | ||
| if ( empty( $image ) ) { | ||
| return $image; | ||
| } | ||
|
|
||
| // Fast bow-out: already a Cloudinary URL, nothing to do. | ||
| if ( $this->is_cloudinary_url( $image[0] ) ) { | ||
| return $image; | ||
| } | ||
|
|
||
| // Only images and preview-capable formats (PDF, PSD) have a real image representation to | ||
| // correct to. is_deliverable() treats every other attachment type as deliverable too, so | ||
| // without this, a synced non-image (audio, zip, docx, ...) requested with icon=true would | ||
| // have its generic mime icon replaced with the raw asset's Cloudinary URL, breaking the | ||
| // resulting <img> tag. | ||
| if ( ! wp_attachment_is_image( $attachment_id ) && ! $this->is_preview_only( $attachment_id ) ) { | ||
| return $image; | ||
| } | ||
|
|
||
| if ( $this->is_replacement_paused( $attachment_id ) ) { | ||
| return $image; | ||
| } | ||
|
|
||
| if ( ! $this->plugin->get_component( 'delivery' )->is_deliverable( $attachment_id ) ) { | ||
| return $image; | ||
| } | ||
|
|
||
| $cloudinary_id = $this->cloudinary_id( $attachment_id ); | ||
| if ( ! $cloudinary_id ) { | ||
| return $image; | ||
| } | ||
|
|
||
| $url = $this->cloudinary_url( $attachment_id, $size, array(), $cloudinary_id ); | ||
| if ( $url ) { | ||
| $image[0] = $url; | ||
| } | ||
|
|
||
| return $image; | ||
| } | ||
|
|
||
| /** | ||
| * At the point of running wp_get_attachment_image_srcset, the $image_src Should be a Cloudinary URL, unless not synced. | ||
| * This will fix the $image_meta so that the there's a match $src_matched on wp_calculate_image_srcset. | ||
|
|
@@ -3149,7 +3224,6 @@ public function add_live_url_filters() { | |
| add_filter( 'wp_calculate_image_srcset', array( $this, 'image_srcset' ), 10, 5 ); | ||
| add_filter( 'wp_get_attachment_url', array( $this, 'attachment_url' ), 10, 2 ); | ||
| add_filter( 'wp_get_original_image_url', array( $this, 'original_attachment_url' ), 10, 2 ); | ||
| add_filter( 'image_downsize', array( $this, 'filter_downsize' ), 10, 3 ); | ||
| add_filter( 'wp_calculate_image_srcset_meta', array( $this, 'calculate_image_srcset_meta' ), 10, 3 ); | ||
|
|
||
| // Hook into Featured Image cycle. | ||
|
|
@@ -3191,6 +3265,14 @@ public function setup() { | |
| if ( Utils::is_admin() ) { | ||
| $this->add_live_url_filters(); | ||
| } | ||
|
|
||
| // image_downsize() and wp_get_attachment_image_src() are exercised by ordinary | ||
| // front-end theme code (e.g. the_post_thumbnail()), not just wp-admin screens, so | ||
| // these run everywhere rather than being scoped to add_live_url_filters()'s | ||
| // admin-only set. | ||
| add_filter( 'image_downsize', array( $this, 'filter_downsize' ), 10, 3 ); | ||
|
Comment on lines
+3272
to
+3273
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. blocker: These filters now run on the front end, but both bail out through The new test file has to clear The guard should detect a metadata write that is running now (for example
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! This should be fixed now 6bfc2a5 |
||
| add_filter( 'wp_get_attachment_image_src', array( $this, 'filter_attachment_image_src' ), PHP_INT_MAX, 4 ); | ||
|
|
||
| // Filter default image Quality and Format transformations. | ||
| add_filter( 'cloudinary_default_qf_transformations_image', array( $this, 'default_image_transformations' ), 10 ); | ||
| add_filter( 'cloudinary_default_freeform_transformations_image', array( $this, 'default_image_freeform_transformations' ), 10 ); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: When
$iconistruefor a synced non-image attachment (audio, zip, docx, ...), WordPress gives a MIME icon array here.Delivery::is_deliverable()returnstruefor every non-image, non-video type, so this replaces the icon with the raw Cloudinary asset URL, and the result is a broken<img>(for example in the media list view).Please limit this correction to images and supported preview formats (
wp_attachment_is_image()||is_preview_only()). Please also add a test for a synced non-image attachment withicon=true.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense, thanks. Fixed as part of 6bfc2a5