Skip to content

Commit 5db3125

Browse files
committed
Media: Introduce wp_get_attachment_image_context filter.
Since WordPress 5.9, a "context" value of "wp_get_attachment_image" has been used in the `wp_get_attachment_image()` function to provide context to underlying functions where that is relevant, e.g. `wp_get_loading_attr_default()`. Since that value used to be not customizable, it required a workaround in `get_the_post_thumbnail()` to avoid calling those functions in `wp_get_attachment_image()`, which resulted in unnecessary complexity and was prone to errors. This changeset introduces a `wp_get_attachment_image_context` filter and leverages it with private filter callback functions that are leveraged by default when `get_the_post_thumbnail()` is called. This avoids the need for the previous workaround and furthermore provides flexibility for other callers of `wp_get_attachment_image()` to provide their own contexts. Props flixos90, costdev, thekt12, westonruter, spacedmonkey. Fixes #58212. git-svn-id: https://develop.svn.wordpress.org/trunk@55821 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 261ab3f commit 5db3125

5 files changed

Lines changed: 240 additions & 19 deletions

File tree

‎src/wp-includes/default-filters.php‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,9 +444,11 @@
444444
add_action( 'transition_post_status', '_wp_auto_add_pages_to_menu', 10, 3 );
445445
add_action( 'delete_post', '_wp_delete_customize_changeset_dependent_auto_drafts' );
446446

447-
// Post Thumbnail CSS class filtering.
447+
// Post Thumbnail specific image filtering.
448448
add_action( 'begin_fetch_post_thumbnail_html', '_wp_post_thumbnail_class_filter_add' );
449449
add_action( 'end_fetch_post_thumbnail_html', '_wp_post_thumbnail_class_filter_remove' );
450+
add_action( 'begin_fetch_post_thumbnail_html', '_wp_post_thumbnail_context_filter_add' );
451+
add_action( 'end_fetch_post_thumbnail_html', '_wp_post_thumbnail_context_filter_remove' );
450452

451453
// Redirect old slugs.
452454
add_action( 'template_redirect', 'wp_old_slug_redirect' );

‎src/wp-includes/media.php‎

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,9 +1050,18 @@ function wp_get_attachment_image( $attachment_id, $size = 'thumbnail', $icon = f
10501050
'decoding' => 'async',
10511051
);
10521052

1053+
/**
1054+
* Filters the context in which wp_get_attachment_image() is used.
1055+
*
1056+
* @since 6.3.0
1057+
*
1058+
* @param string $context The context. Default 'wp_get_attachment_image'.
1059+
*/
1060+
$context = apply_filters( 'wp_get_attachment_image_context', 'wp_get_attachment_image' );
1061+
10531062
// Add `loading` attribute.
1054-
if ( wp_lazy_loading_enabled( 'img', 'wp_get_attachment_image' ) ) {
1055-
$default_attr['loading'] = wp_get_loading_attr_default( 'wp_get_attachment_image' );
1063+
if ( wp_lazy_loading_enabled( 'img', $context ) ) {
1064+
$default_attr['loading'] = wp_get_loading_attr_default( $context );
10561065
}
10571066

10581067
$attr = wp_parse_args( $attr, $default_attr );
@@ -2170,6 +2179,47 @@ function _wp_post_thumbnail_class_filter_remove( $attr ) {
21702179
remove_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' );
21712180
}
21722181

2182+
/**
2183+
* Overrides the context used in {@see wp_get_attachment_image()}. Internal use only.
2184+
*
2185+
* Uses the {@see 'begin_fetch_post_thumbnail_html'} and {@see 'end_fetch_post_thumbnail_html'}
2186+
* action hooks to dynamically add/remove itself so as to only filter post thumbnails.
2187+
*
2188+
* @ignore
2189+
* @since 6.3.0
2190+
* @access private
2191+
*
2192+
* @param string $context The context for rendering an attachment image.
2193+
* @return string Modified context set to 'the_post_thumbnail'.
2194+
*/
2195+
function _wp_post_thumbnail_context_filter( $context ) {
2196+
return 'the_post_thumbnail';
2197+
}
2198+
2199+
/**
2200+
* Adds the '_wp_post_thumbnail_context_filter' callback to the 'wp_get_attachment_image_context'
2201+
* filter hook. Internal use only.
2202+
*
2203+
* @ignore
2204+
* @since 6.3.0
2205+
* @access private
2206+
*/
2207+
function _wp_post_thumbnail_context_filter_add() {
2208+
add_filter( 'wp_get_attachment_image_context', '_wp_post_thumbnail_context_filter' );
2209+
}
2210+
2211+
/**
2212+
* Removes the '_wp_post_thumbnail_context_filter' callback from the 'wp_get_attachment_image_context'
2213+
* filter hook. Internal use only.
2214+
*
2215+
* @ignore
2216+
* @since 6.3.0
2217+
* @access private
2218+
*/
2219+
function _wp_post_thumbnail_context_filter_remove() {
2220+
remove_filter( 'wp_get_attachment_image_context', '_wp_post_thumbnail_context_filter' );
2221+
}
2222+
21732223
add_shortcode( 'wp_caption', 'img_caption_shortcode' );
21742224
add_shortcode( 'caption', 'img_caption_shortcode' );
21752225

‎src/wp-includes/post-thumbnail-template.php‎

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -186,22 +186,6 @@ function get_the_post_thumbnail( $post = null, $size = 'post-thumbnail', $attr =
186186
update_post_thumbnail_cache();
187187
}
188188

189-
// Add `loading` attribute.
190-
if ( wp_lazy_loading_enabled( 'img', 'the_post_thumbnail' ) ) {
191-
// Get the 'loading' attribute value to use as default, taking precedence over the default from
192-
// `wp_get_attachment_image()`.
193-
$loading = wp_get_loading_attr_default( 'the_post_thumbnail' );
194-
195-
// Add the default to the given attributes unless they already include a 'loading' directive.
196-
if ( empty( $attr ) ) {
197-
$attr = array( 'loading' => $loading );
198-
} elseif ( is_array( $attr ) && ! array_key_exists( 'loading', $attr ) ) {
199-
$attr['loading'] = $loading;
200-
} elseif ( is_string( $attr ) && ! preg_match( '/(^|&)loading=/', $attr ) ) {
201-
$attr .= '&loading=' . $loading;
202-
}
203-
}
204-
205189
$html = wp_get_attachment_image( $post_thumbnail_id, $size, false, $attr );
206190

207191
/**

‎tests/phpunit/tests/media.php‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3963,6 +3963,62 @@ public function test_wp_generate_attachment_metadata_doesnt_generate_sizes_for_1
39633963
);
39643964
}
39653965

3966+
/**
3967+
* Tests that `wp_get_attachment_image()` uses the correct default context.
3968+
*
3969+
* @ticket 58212
3970+
*
3971+
* @covers ::wp_get_attachment_image()
3972+
*/
3973+
public function test_wp_get_attachment_image_context_filter_default() {
3974+
$last_context = '';
3975+
$this->track_last_attachment_image_context( $last_context );
3976+
3977+
wp_get_attachment_image( self::$large_id );
3978+
$this->assertSame( 'wp_get_attachment_image', $last_context );
3979+
}
3980+
3981+
/**
3982+
* Tests that `wp_get_attachment_image()` allows overriding the context via filter.
3983+
*
3984+
* @ticket 58212
3985+
*
3986+
* @covers ::wp_get_attachment_image()
3987+
*/
3988+
public function test_wp_get_attachment_image_context_filter_value_is_passed_correctly() {
3989+
$last_context = '';
3990+
$this->track_last_attachment_image_context( $last_context );
3991+
3992+
// Add a filter that modifies the context.
3993+
add_filter(
3994+
'wp_get_attachment_image_context',
3995+
static function() {
3996+
return 'my_custom_context';
3997+
}
3998+
);
3999+
4000+
wp_get_attachment_image( self::$large_id );
4001+
$this->assertSame( 'my_custom_context', $last_context );
4002+
}
4003+
4004+
/**
4005+
* Helper method to keep track of the last context returned by the 'wp_get_attachment_image_context' filter.
4006+
*
4007+
* The method parameter is passed by reference and therefore will always contain the last context value.
4008+
*
4009+
* @param mixed $last_context Variable to track last context. Passed by reference.
4010+
*/
4011+
private function track_last_attachment_image_context( &$last_context ) {
4012+
add_filter(
4013+
'wp_get_attachment_image_context',
4014+
static function( $context ) use ( &$last_context ) {
4015+
$last_context = $context;
4016+
return $context;
4017+
},
4018+
11
4019+
);
4020+
}
4021+
39664022
/**
39674023
* Add threshold to create a `-scaled` output image for testing.
39684024
*/

‎tests/phpunit/tests/post/thumbnails.php‎

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,135 @@ public function data_post_thumbnail_size_filter_complex() {
450450
);
451451
}
452452

453+
/**
454+
* Tests that `_wp_post_thumbnail_context_filter()` returns 'the_post_thumbnail'.
455+
*
456+
* @ticket 58212
457+
*
458+
* @covers::_wp_post_thumbnail_context_filter
459+
*/
460+
public function test_wp_post_thumbnail_context_filter_should_return_the_post_thumbnail() {
461+
$this->assertSame( 'the_post_thumbnail', _wp_post_thumbnail_context_filter( 'wp_get_attachment_image' ) );
462+
}
463+
464+
/**
465+
* Tests that `::_wp_post_thumbnail_context_filter_add` adds a filter to override the context
466+
* used in `wp_get_attachment_image()`.
467+
*
468+
* @ticket 58212
469+
*
470+
* @covers ::_wp_post_thumbnail_context_filter_add
471+
*/
472+
public function test_wp_post_thumbnail_context_filter_add_should_add_the_filter() {
473+
$last_context = '';
474+
$this->track_last_attachment_image_context( $last_context );
475+
476+
_wp_post_thumbnail_context_filter_add();
477+
wp_get_attachment_image( self::$attachment_id );
478+
479+
$this->assertSame( 'the_post_thumbnail', $last_context );
480+
}
481+
482+
/**
483+
* Tests that `_wp_post_thumbnail_context_filter_remove()` removes a filter to override the context
484+
* used in `wp_get_attachment_image()`.
485+
*
486+
* @ticket 58212
487+
*
488+
* @covers ::_wp_post_thumbnail_context_filter_remove
489+
*/
490+
public function test_wp_post_thumbnail_context_filter_remove_should_remove_the_filter() {
491+
$last_context = '';
492+
$this->track_last_attachment_image_context( $last_context );
493+
494+
_wp_post_thumbnail_context_filter_add();
495+
wp_get_attachment_image( self::$attachment_id );
496+
497+
// Verify that the filter has been added before testing that it has been removed.
498+
$this->assertSame(
499+
'the_post_thumbnail',
500+
$last_context,
501+
'The filter was not added.'
502+
);
503+
504+
_wp_post_thumbnail_context_filter_remove();
505+
506+
// The context should no longer be modified by the filter.
507+
wp_get_attachment_image( self::$attachment_id );
508+
509+
$this->assertSame(
510+
'wp_get_attachment_image',
511+
$last_context,
512+
'The filter was not removed.'
513+
);
514+
}
515+
516+
/**
517+
* Tests that `get_the_post_thumbnail()` uses the 'the_post_thumbnail' context.
518+
*
519+
* @ticket 58212
520+
*
521+
* @covers ::get_the_post_thumbnail
522+
*/
523+
public function test_get_the_post_thumbnail_should_use_the_post_thumbnail_context() {
524+
$last_context = '';
525+
$this->track_last_attachment_image_context( $last_context );
526+
527+
set_post_thumbnail( self::$post, self::$attachment_id );
528+
get_the_post_thumbnail( self::$post );
529+
530+
$this->assertSame( 'the_post_thumbnail', $last_context );
531+
}
532+
533+
/**
534+
* Tests that `get_the_post_thumbnail()` restores the context afterwards.
535+
*
536+
* @ticket 58212
537+
*
538+
* @covers ::get_the_post_thumbnail
539+
*/
540+
public function test_get_the_post_thumbnail_should_remove_the_post_thumbnail_context_afterwards() {
541+
$last_context = '';
542+
$this->track_last_attachment_image_context( $last_context );
543+
544+
set_post_thumbnail( self::$post, self::$attachment_id );
545+
get_the_post_thumbnail( self::$post );
546+
547+
// Verify that the context was overridden before testing that it has been restored.
548+
$this->assertSame(
549+
'the_post_thumbnail',
550+
$last_context,
551+
'The context was not overridden.'
552+
);
553+
554+
// The context should no longer be overridden.
555+
wp_get_attachment_image( self::$attachment_id );
556+
557+
$this->assertSame(
558+
'wp_get_attachment_image',
559+
$last_context,
560+
'The context was not restored.'
561+
);
562+
}
563+
564+
/**
565+
* Helper method to keep track of the last context returned by the 'wp_get_attachment_image_context' filter.
566+
*
567+
* The method parameter is passed by reference and therefore will always contain the last context value.
568+
*
569+
* @param mixed $last_context Variable to track last context. Passed by reference.
570+
*/
571+
private function track_last_attachment_image_context( &$last_context ) {
572+
add_filter(
573+
'wp_get_attachment_image_context',
574+
static function( $context ) use ( &$last_context ) {
575+
$last_context = $context;
576+
return $context;
577+
},
578+
11
579+
);
580+
}
581+
453582
public function filter_post_thumbnail_size( $size, $post_id ) {
454583
if ( is_array( $this->current_size_filter_data ) && isset( $this->current_size_filter_data[ $post_id ] ) ) {
455584
return $this->current_size_filter_data[ $post_id ];

0 commit comments

Comments
 (0)