Skip to content

Commit 6b7e35b

Browse files
Embeds: Add oEmbed meta cleanup on post save
1 parent 7170a0b commit 6b7e35b

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

src/wp-includes/class-wp-embed.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,72 @@ public function __construct() {
4545
// After a post is saved, cache oEmbed items via Ajax.
4646
add_action( 'edit_form_advanced', array( $this, 'maybe_run_ajax_cache' ) );
4747
add_action( 'edit_page_form', array( $this, 'maybe_run_ajax_cache' ) );
48+
49+
// Register oEmbed meta cleanup on post save.
50+
add_action( 'save_post', array( $this, 'maybe_delete_orphaned_oembed_meta' ), 10, 3 );
51+
}
52+
53+
/**
54+
* Deletes orphaned oEmbed post meta when a post is saved.
55+
*
56+
* Removes any oEmbed cache post meta entries that no longer correspond to
57+
* an embed block or auto-embed URL in the post content. This helps prevent
58+
* orphaned oEmbed cache data from accumulating when embeds are removed.
59+
*
60+
* @since 6.6.0
61+
*
62+
* @param int $post_id Post ID.
63+
* @param WP_Post $post Post object.
64+
*/
65+
public function maybe_delete_orphaned_oembed_meta( $post_id, $post ) {
66+
// Only run for posts, not revisions or autosaves.
67+
if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
68+
return;
69+
}
70+
71+
$content = $post->post_content;
72+
$embed_urls = array();
73+
74+
// Collect embed URLs from Gutenberg embed blocks.
75+
if ( function_exists( 'has_blocks' ) && has_blocks( $content ) ) {
76+
$blocks = parse_blocks( $content );
77+
foreach ( $blocks as $block ) {
78+
if ( isset( $block['blockName'] ) && 'core/embed' === $block['blockName'] && ! empty( $block['attrs']['url'] ) ) {
79+
$embed_urls[] = $block['attrs']['url'];
80+
}
81+
}
82+
}
83+
84+
// Collect classic auto-embed URLs.
85+
$lines = preg_split( '/\r\n|\r|\n/', $content );
86+
foreach ( $lines as $line ) {
87+
$line = trim( $line );
88+
if ( filter_var( $line, FILTER_VALIDATE_URL ) ) {
89+
$embed_urls[] = $line;
90+
}
91+
}
92+
$embed_urls = array_unique( $embed_urls );
93+
94+
// Remove orphaned oEmbed meta.
95+
$meta = get_post_meta( $post_id );
96+
foreach ( $meta as $meta_key => $values ) {
97+
if ( 0 === strpos( $meta_key, '_oembed_' ) ) {
98+
$key_suffix = substr( $meta_key, 8 );
99+
$found = false;
100+
foreach ( $embed_urls as $url ) {
101+
$expected_suffix = md5( $url . serialize( wp_embed_defaults( $url ) ) );
102+
if ( $key_suffix === $expected_suffix ) {
103+
$found = true;
104+
break;
105+
}
106+
}
107+
if ( ! $found ) {
108+
delete_post_meta( $post_id, $meta_key );
109+
$time_key = '_oembed_time_' . $key_suffix;
110+
delete_post_meta( $post_id, $time_key );
111+
}
112+
}
113+
}
48114
}
49115

50116
/**
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
/**
3+
* @group oembed
4+
*/
5+
class Tests_oEmbed_DeleteOrphanedOembedMeta extends WP_UnitTestCase {
6+
public function test_oembed_meta_deleted_when_embed_removed() {
7+
$url = 'https://www.youtube.com/watch?v=Ok6JKHMAkH8';
8+
$post_id = self::factory()->post->create(
9+
array(
10+
'post_content' => $url . "\nSome text.",
11+
)
12+
);
13+
14+
// Trigger oEmbed caching as core does
15+
global $wp_embed;
16+
$wp_embed->cache_oembed( $post_id );
17+
18+
$key_suffix = md5( $url . serialize( wp_embed_defaults( $url ) ) );
19+
$cachekey = '_oembed_' . $key_suffix;
20+
$cachekey_time = '_oembed_time_' . $key_suffix;
21+
22+
// Ensure the oEmbed meta is present after caching
23+
$this->assertNotEmpty( get_post_meta( $post_id, $cachekey, true ), 'oEmbed cache meta should exist after caching.' );
24+
$this->assertNotEmpty( get_post_meta( $post_id, $cachekey_time, true ), 'oEmbed time meta should exist after caching.' );
25+
26+
// Remove the embed from content and update the post.
27+
wp_update_post(
28+
array(
29+
'ID' => $post_id,
30+
'post_content' => 'Some text.',
31+
)
32+
);
33+
34+
// Re-trigger oEmbed cache
35+
$wp_embed->cache_oembed( $post_id );
36+
37+
// The oEmbed meta should be deleted after update.
38+
$this->assertEmpty( get_post_meta( $post_id, $cachekey, true ), 'oEmbed cache meta should be deleted when embed is removed.' );
39+
$this->assertEmpty( get_post_meta( $post_id, $cachekey_time, true ), 'oEmbed time meta should be deleted when embed is removed.' );
40+
}
41+
}

0 commit comments

Comments
 (0)