Skip to content
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

Add caching for uploaded header images #7154

Open
wants to merge 12 commits into
base: trunk
Choose a base branch
from
36 changes: 34 additions & 2 deletions src/wp-includes/theme.php
Original file line number Diff line number Diff line change
Expand Up @@ -1498,14 +1498,21 @@ function header_image() {
* @return array
*/
function get_uploaded_header_images() {
$stylesheet = get_option( 'stylesheet' );
$transient_key = "uploaded_header_images_{$stylesheet}";
$header_images = get_transient( $transient_key );

if ( false !== $header_images ) {
return $header_images;
}

$header_images = array();

// @todo Caching.
$headers = get_posts(
array(
'post_type' => 'attachment',
'meta_key' => '_wp_attachment_is_custom_header',
'meta_value' => get_option( 'stylesheet' ),
'meta_value' => $stylesheet,
'orderby' => 'none',
'nopaging' => true,
)
Expand Down Expand Up @@ -1540,9 +1547,34 @@ function get_uploaded_header_images() {
}
}

set_transient( $transient_key, $header_images, DAY_IN_SECONDS );

return $header_images;
}

/**
* Invalidates the cache for header images when a custom header image is changed or deleted.
*
* @since 6.7.0
*
* @param int $meta_id The meta ID of the attachment meta data.
* @param int $post_id The post ID of the attachment.
* @param string $meta_key The meta key of the attachment meta data.
* @param mixed $meta_value The new value of the attachment meta data.
*
* @return void
*/
function invalidate_header_images_cache( $meta_id, $post_id, $meta_key, $meta_value ) {
if ( '_wp_attachment_is_custom_header' === $meta_key ) {
$stylesheet = $meta_value ? $meta_value : get_option( 'stylesheet' );
$transient_key = "uploaded_header_images_{$stylesheet}";
delete_transient( $transient_key );
}
}
add_action( 'added_post_meta', 'invalidate_header_images_cache', 10, 4 );
add_action( 'updated_post_meta', 'invalidate_header_images_cache', 10, 4 );
add_action( 'deleted_post_meta', 'invalidate_header_images_cache', 10, 4 );

/**
* Gets the header image data.
*
Expand Down
62 changes: 62 additions & 0 deletions tests/phpunit/tests/theme/getUploadedHeaderImages.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php
/**
* @group themes
*
* @coversDefaultClass ::get_uploaded_header_images
*/
class Tests_Theme_GetUploadedHeaderImages extends WP_UnitTestCase {
public $custom_image_header;

public function set_up() {
parent::set_up();
$this->custom_image_header = new Custom_Image_Header( '__return_null' );
}

/**
* @ticket 49446
*/
public function test_get_uploaded_header_images_caches() {
$id = wp_insert_attachment(
array(
'post_status' => 'publish',
'post_title' => 'foo.png',
'post_type' => 'post',
'guid' => 'http://localhost/foo.png',
)
);

// Create initial crop object.
$cropped_1 = 'foo-cropped-1.png';
$object = wp_copy_parent_attachment_properties( $cropped_1, $id, 'custom-header' );

// Ensure no previous crop exists.
$previous = $this->custom_image_header->get_previous_crop( $object );
$this->assertFalse( $previous );

// Create the initial crop attachment and set it as the header.
$cropped_1_id = $this->custom_image_header->insert_attachment( $object, $cropped_1 );
$key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
update_post_meta( $cropped_1_id, $key, time() );
update_post_meta( $cropped_1_id, '_wp_attachment_is_custom_header', get_stylesheet() );

$expected = array(
$cropped_1_id => array(
'attachment_id' => $cropped_1_id,
'url' => 'http://example.org/wp-content/uploads/foo-cropped-1.png',
'thumbnail_url' => 'http://example.org/wp-content/uploads/foo-cropped-1.png',
'alt_text' => '',
'attachment_parent' => $id,
),
);

$num_queries = get_num_queries() + 4;

$this->assertSame( $expected, get_uploaded_header_images() );

$this->assertSame( $num_queries, get_num_queries() );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


$this->assertSame( $expected, get_uploaded_header_images() );

$this->assertSame( $num_queries, get_num_queries() );
}
}
112 changes: 112 additions & 0 deletions tests/phpunit/tests/theme/invalidateHeaderImagesCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php
/**
* @group themes
*
* @covers ::invalidate_header_images_cache
*/
class Tests_Theme_invalidateHeaderImagesCache extends WP_UnitTestCase {
public $custom_image_header;

public function set_up() {
parent::set_up();
$this->custom_image_header = new Custom_Image_Header( '__return_null' );
}

/**
* @ticket 49446
*/
public function test_invalidate_header_images_cache_meta_updated() {
$id = wp_insert_attachment(
array(
'post_status' => 'publish',
'post_title' => 'foo.png',
'post_type' => 'post',
'guid' => 'http://localhost/foo.png',
)
);

// Create initial crop object.
$cropped_1 = 'foo-cropped-1.png';
$object = wp_copy_parent_attachment_properties( $cropped_1, $id, 'custom-header' );

// Ensure no previous crop exists.
$previous = $this->custom_image_header->get_previous_crop( $object );
$this->assertFalse( $previous );

// Create the initial crop attachment and set it as the header.
$cropped_1_id = $this->custom_image_header->insert_attachment( $object, $cropped_1 );
$key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
update_post_meta( $cropped_1_id, $key, time() );
update_post_meta( $cropped_1_id, '_wp_attachment_is_custom_header', get_stylesheet() );

$expected = array(
$cropped_1_id => array(
'attachment_id' => $cropped_1_id,
'url' => 'http://example.org/wp-content/uploads/foo-cropped-1.png',
'thumbnail_url' => 'http://example.org/wp-content/uploads/foo-cropped-1.png',
'alt_text' => '',
'attachment_parent' => $id,
),
);

$num_queries = get_num_queries() + 4;

$this->assertSame( $expected, get_uploaded_header_images() );

$this->assertSame( $num_queries, get_num_queries() );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update_post_meta( $cropped_1_id, '_wp_attachment_is_custom_header', 'updated' );

$stylesheet = get_option( 'stylesheet' );
$transient_key = 'uploaded_header_images' . $stylesheet;
$this->assertFalse( get_transient( $transient_key ), 'cache cleared' );
}

/**
* @ticket 49446
*/
public function test_invalidate_header_images_cache_meta_deleted() {
$id = wp_insert_attachment(
array(
'post_status' => 'publish',
'post_title' => 'foo.png',
'post_type' => 'post',
'guid' => 'http://localhost/foo.png',
)
);

// Create initial crop object.
$cropped_1 = 'foo-cropped-1.png';
$object = wp_copy_parent_attachment_properties( $cropped_1, $id, 'custom-header' );

// Ensure no previous crop exists.
$previous = $this->custom_image_header->get_previous_crop( $object );
$this->assertFalse( $previous );

// Create the initial crop attachment and set it as the header.
$cropped_1_id = $this->custom_image_header->insert_attachment( $object, $cropped_1 );
$key = '_wp_attachment_custom_header_last_used_' . get_stylesheet();
update_post_meta( $cropped_1_id, $key, time() );
update_post_meta( $cropped_1_id, '_wp_attachment_is_custom_header', get_stylesheet() );

$expected = array(
$cropped_1_id => array(
'attachment_id' => $cropped_1_id,
'url' => 'http://example.org/wp-content/uploads/foo-cropped-1.png',
'thumbnail_url' => 'http://example.org/wp-content/uploads/foo-cropped-1.png',
'alt_text' => '',
'attachment_parent' => $id,
),
);

$num_queries = get_num_queries() + 4;

$this->assertSame( $expected, get_uploaded_header_images() );

$this->assertSame( $num_queries, get_num_queries() );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete_post_meta( $cropped_1_id, '_wp_attachment_is_custom_header' );

$stylesheet = get_option( 'stylesheet' );
$transient_key = 'uploaded_header_images' . $stylesheet;
$this->assertFalse( get_transient( $transient_key ), 'cache cleared' );
}
}
Loading