Improve `do_enclose()` logic on post publish.
Removing the direct SQL query in `do_all_pings()` improves filterability. As part of this change, the signature of `do_enclose()` is changed so that a null `$content` parameter can be passed, with the `$content` then inferred from the `$post` passed in the second parameter. In addition, the second parameter was modified so that a post ID or a `WP_Post` object can be provided. These changes make it possible to trigger enclosure checks with a post ID alone (as in `do_all_pings()`) and also brings the function signature in line with `do_trackbacks()` and `pingback()`. Props dshanske, spacedmonkey, janw.oostendorp, mrmadhat, birgire. See #36824. git-svn-id: https://develop.svn.wordpress.org/trunk@46175 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
20a17438d0
commit
48e280db32
|
@ -2639,10 +2639,20 @@ function do_all_pings() {
|
||||||
pingback( $ping->post_content, $ping->ID );
|
pingback( $ping->post_content, $ping->ID );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do Enclosures
|
// Do enclosures.
|
||||||
while ( $enclosure = $wpdb->get_row( "SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_encloseme' LIMIT 1" ) ) {
|
$enclosures = get_posts(
|
||||||
delete_metadata_by_mid( 'post', $enclosure->meta_id );
|
array(
|
||||||
do_enclose( $enclosure->post_content, $enclosure->ID );
|
'post_type' => get_post_types(),
|
||||||
|
'suppress_filters' => false,
|
||||||
|
'nopaging' => true,
|
||||||
|
'meta_key' => '_encloseme',
|
||||||
|
'fields' => 'ids',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ( $enclosure as $enclosure ) {
|
||||||
|
delete_post_meta( $enclosure, '_encloseme' );
|
||||||
|
do_enclose( null, $enclosure->ID );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do Trackbacks
|
// Do Trackbacks
|
||||||
|
|
|
@ -799,27 +799,39 @@ function wp_extract_urls( $content ) {
|
||||||
* pingbacks and trackbacks.
|
* pingbacks and trackbacks.
|
||||||
*
|
*
|
||||||
* @since 1.5.0
|
* @since 1.5.0
|
||||||
|
* @since 5.3.0 The `$content` parameter was made optional, and the `$post` parameter was
|
||||||
|
* updated to accept a post ID or a WP_Post object.
|
||||||
*
|
*
|
||||||
* @global wpdb $wpdb WordPress database abstraction object.
|
* @global wpdb $wpdb WordPress database abstraction object.
|
||||||
*
|
*
|
||||||
* @param string $content Post Content.
|
* @param string $content Post content. If `null`, the `post_content` field from `$post` is used.
|
||||||
* @param int $post_ID Post ID.
|
* @param int|WP_Post $post Post ID or post object.
|
||||||
|
* @return null|bool Returns false if post is not found.
|
||||||
*/
|
*/
|
||||||
function do_enclose( $content, $post_ID ) {
|
function do_enclose( $content = null, $post ) {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
//TODO: Tidy this ghetto code up and make the debug code optional
|
//TODO: Tidy this ghetto code up and make the debug code optional
|
||||||
include_once( ABSPATH . WPINC . '/class-IXR.php' );
|
include_once( ABSPATH . WPINC . '/class-IXR.php' );
|
||||||
|
|
||||||
|
$post = get_post( $post );
|
||||||
|
if ( ! $post ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( null === $content ) {
|
||||||
|
$content = $post->post_content;
|
||||||
|
}
|
||||||
|
|
||||||
$post_links = array();
|
$post_links = array();
|
||||||
|
|
||||||
$pung = get_enclosed( $post_ID );
|
$pung = get_enclosed( $post->ID );
|
||||||
|
|
||||||
$post_links_temp = wp_extract_urls( $content );
|
$post_links_temp = wp_extract_urls( $content );
|
||||||
|
|
||||||
foreach ( $pung as $link_test ) {
|
foreach ( $pung as $link_test ) {
|
||||||
if ( ! in_array( $link_test, $post_links_temp ) ) { // link no longer in post
|
if ( ! in_array( $link_test, $post_links_temp ) ) { // link no longer in post
|
||||||
$mids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post_ID, $wpdb->esc_like( $link_test ) . '%' ) );
|
$mids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post->ID, $wpdb->esc_like( $link_test ) . '%' ) );
|
||||||
foreach ( $mids as $mid ) {
|
foreach ( $mids as $mid ) {
|
||||||
delete_metadata_by_mid( 'post', $mid );
|
delete_metadata_by_mid( 'post', $mid );
|
||||||
}
|
}
|
||||||
|
@ -851,10 +863,10 @@ function do_enclose( $content, $post_ID ) {
|
||||||
* @param array $post_links An array of enclosure links.
|
* @param array $post_links An array of enclosure links.
|
||||||
* @param int $post_ID Post ID.
|
* @param int $post_ID Post ID.
|
||||||
*/
|
*/
|
||||||
$post_links = apply_filters( 'enclosure_links', $post_links, $post_ID );
|
$post_links = apply_filters( 'enclosure_links', $post_links, $post->ID );
|
||||||
|
|
||||||
foreach ( (array) $post_links as $url ) {
|
foreach ( (array) $post_links as $url ) {
|
||||||
if ( $url != '' && ! $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post_ID, $wpdb->esc_like( $url ) . '%' ) ) ) {
|
if ( $url != '' && ! $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post->ID, $wpdb->esc_like( $url ) . '%' ) ) ) {
|
||||||
|
|
||||||
$headers = wp_get_http_headers( $url );
|
$headers = wp_get_http_headers( $url );
|
||||||
if ( $headers ) {
|
if ( $headers ) {
|
||||||
|
@ -878,7 +890,7 @@ function do_enclose( $content, $post_ID ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( in_array( substr( $type, 0, strpos( $type, '/' ) ), $allowed_types ) ) {
|
if ( in_array( substr( $type, 0, strpos( $type, '/' ) ), $allowed_types ) ) {
|
||||||
add_post_meta( $post_ID, 'enclosure', "$url\n$len\n$mime\n" );
|
add_post_meta( $post->ID, 'enclosure', "$url\n$len\n$mime\n" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,305 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Test cases for the `do_enclose()` function.
|
||||||
|
*
|
||||||
|
* @package WordPress\UnitTests
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests_Functions_DoEnclose class.
|
||||||
|
*
|
||||||
|
* @group functions.php
|
||||||
|
* @group post
|
||||||
|
* @covers do_enclose
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*/
|
||||||
|
class Tests_Functions_DoEnclose extends WP_UnitTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup before each test method.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*/
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
add_filter( 'pre_http_request', array( $this, 'fake_http_request' ), 10, 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup after each test method.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*/
|
||||||
|
public function tearDown() {
|
||||||
|
parent::tearDown();
|
||||||
|
remove_filter( 'pre_http_request', array( $this, 'fake_http_request' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the function with an explicit content input.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*
|
||||||
|
* @dataProvider data_test_do_enclose
|
||||||
|
*/
|
||||||
|
public function test_function_with_explicit_content_input( $content, $expected ) {
|
||||||
|
$post_id = self::factory()->post->create();
|
||||||
|
|
||||||
|
do_enclose( $content, $post_id );
|
||||||
|
|
||||||
|
$actual = $this->get_enclosed_by_post_id( $post_id );
|
||||||
|
$this->assertSame( $expected, $actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the function with an implicit content input.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*
|
||||||
|
* @dataProvider data_test_do_enclose
|
||||||
|
*/
|
||||||
|
public function test_function_with_implicit_content_input( $content, $expected ) {
|
||||||
|
$post_id = self::factory()->post->create(
|
||||||
|
array(
|
||||||
|
'post_content' => $content,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
do_enclose( null, $post_id );
|
||||||
|
|
||||||
|
$actual = $this->get_enclosed_by_post_id( $post_id );
|
||||||
|
$this->assertSame( $expected, $actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dataprovider for `test_function_with_explicit_content_input()`
|
||||||
|
* and `test_function_with_implicit_content_input()`.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*
|
||||||
|
* @return array {
|
||||||
|
* @type array {
|
||||||
|
* @type string Post content.
|
||||||
|
* @type string Expected values.
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
public function data_test_do_enclose() {
|
||||||
|
return array(
|
||||||
|
'null' => array(
|
||||||
|
'content' => null,
|
||||||
|
'expected' => '',
|
||||||
|
),
|
||||||
|
'empty' => array(
|
||||||
|
'content' => '',
|
||||||
|
'expected' => '',
|
||||||
|
),
|
||||||
|
'single-bare-movie' => array(
|
||||||
|
'content' => 'movie.mp4',
|
||||||
|
'expected' => '',
|
||||||
|
),
|
||||||
|
'single-bare-audio' => array(
|
||||||
|
'content' => 'audio.ogg',
|
||||||
|
'expected' => '',
|
||||||
|
),
|
||||||
|
'single-relative-movie' => array(
|
||||||
|
'content' => '/movie.mp4',
|
||||||
|
'expected' => "/movie.mp4\n123\nvideo/mp4\n",
|
||||||
|
),
|
||||||
|
'single-relative-audio' => array(
|
||||||
|
'content' => '/audio.ogg',
|
||||||
|
'expected' => "/audio.ogg\n321\naudio/ogg\n",
|
||||||
|
),
|
||||||
|
'single-unknown' => array(
|
||||||
|
'content' => 'https://example.com/wp-content/uploads/2018/06/file.unknown',
|
||||||
|
'expected' => '',
|
||||||
|
),
|
||||||
|
'single-movie' => array(
|
||||||
|
'content' => 'https://example.com/wp-content/uploads/2018/06/movie.mp4',
|
||||||
|
'expected' => "https://example.com/wp-content/uploads/2018/06/movie.mp4\n123\nvideo/mp4\n",
|
||||||
|
),
|
||||||
|
'single-audio' => array(
|
||||||
|
'content' => 'https://example.com/wp-content/uploads/2018/06/audio.ogg',
|
||||||
|
'expected' => "https://example.com/wp-content/uploads/2018/06/audio.ogg\n321\naudio/ogg\n",
|
||||||
|
),
|
||||||
|
'single-movie-query' => array(
|
||||||
|
'content' => 'https://example.com/wp-content/uploads/2018/06/movie.mp4?test=1',
|
||||||
|
'expected' => "https://example.com/wp-content/uploads/2018/06/movie.mp4?test=1\n123\nvideo/mp4\n",
|
||||||
|
),
|
||||||
|
'multi' => array(
|
||||||
|
'content' => "https://example.com/wp-content/uploads/2018/06/audio.ogg\n" .
|
||||||
|
'https://example.com/wp-content/uploads/2018/06/movie.mp4',
|
||||||
|
'expected' => "https://example.com/wp-content/uploads/2018/06/audio.ogg\n321\naudio/ogg\n" .
|
||||||
|
"https://example.com/wp-content/uploads/2018/06/movie.mp4\n123\nvideo/mp4\n",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should return false when the post ID input is invalid.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*/
|
||||||
|
public function test_function_should_return_false_when_invalid_post_id() {
|
||||||
|
$post_id = null;
|
||||||
|
$result = do_enclose( null, $post_id );
|
||||||
|
$this->assertFalse( $result );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should delete an enclosed link when it's no longer in the post content.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*/
|
||||||
|
public function test_function_should_delete_enclosed_link_when_no_longer_in_post_content() {
|
||||||
|
$data = $this->data_test_do_enclose();
|
||||||
|
|
||||||
|
// Create a post with a single movie link.
|
||||||
|
$post_id = self::factory()->post->create(
|
||||||
|
array(
|
||||||
|
'post_content' => $data['single-movie']['content'],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
do_enclose( null, $post_id );
|
||||||
|
|
||||||
|
$actual = $this->get_enclosed_by_post_id( $post_id );
|
||||||
|
$this->assertSame( $data['single-movie']['expected'], $actual );
|
||||||
|
|
||||||
|
// Replace the movie link with an audio link.
|
||||||
|
wp_update_post(
|
||||||
|
array(
|
||||||
|
'ID' => $post_id,
|
||||||
|
'post_content' => $data['single-audio']['content'],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
do_enclose( null, $post_id );
|
||||||
|
|
||||||
|
$actual = $this->get_enclosed_by_post_id( $post_id );
|
||||||
|
$this->assertSame( $data['single-audio']['expected'], $actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function should support a post object input.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*/
|
||||||
|
public function test_function_should_support_post_object_input() {
|
||||||
|
$data = $this->data_test_do_enclose();
|
||||||
|
|
||||||
|
$post_object = self::factory()->post->create_and_get(
|
||||||
|
array(
|
||||||
|
'post_content' => $data['multi']['content'],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
do_enclose( null, $post_object );
|
||||||
|
|
||||||
|
$actual = $this->get_enclosed_by_post_id( $post_object->ID );
|
||||||
|
$this->assertSame( $data['multi']['expected'], $actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The enclosure links should be filterable with the `enclosure_links` filter.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*/
|
||||||
|
public function test_function_enclosure_links_should_be_filterable() {
|
||||||
|
$data = $this->data_test_do_enclose();
|
||||||
|
|
||||||
|
$post_id = self::factory()->post->create(
|
||||||
|
array(
|
||||||
|
'post_content' => $data['multi']['content'],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
add_filter( 'enclosure_links', array( $this, 'filter_enclosure_links' ), 10, 2 );
|
||||||
|
do_enclose( null, $post_id );
|
||||||
|
remove_filter( 'enclosure_links', array( $this, 'filter_enclosure_links' ) );
|
||||||
|
|
||||||
|
$actual = $this->get_enclosed_by_post_id( $post_id );
|
||||||
|
$expected = str_replace( 'example.org', sprintf( 'example-%d.org', $post_id ), $data['multi']['expected'] );
|
||||||
|
$this->assertSame( $expected, $actual );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback to filter the list of enclosure links.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*
|
||||||
|
* @param array $post_links An array of enclosure links.
|
||||||
|
* @param int $post_id Post ID.
|
||||||
|
* @return array $post_links An array of enclosure links.
|
||||||
|
*/
|
||||||
|
public function filter_enclosure_links( $enclosure_links, $post_id ) {
|
||||||
|
// Replace the link host to contain the post ID, to test both filter input arguments.
|
||||||
|
foreach ( $enclosure_links as &$link ) {
|
||||||
|
$link = str_replace( 'example.org', sprintf( 'example-%d.org', $post_id ), $link );
|
||||||
|
}
|
||||||
|
return $enclosure_links;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to get all enclosure data for a given post.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*
|
||||||
|
* @param int $post_id Post ID.
|
||||||
|
* @return string All enclosure data for the given post.
|
||||||
|
*/
|
||||||
|
protected function get_enclosed_by_post_id( $post_id ) {
|
||||||
|
return join( (array) get_post_meta( $post_id, 'enclosure', false ), '' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fake the HTTP request response.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
*
|
||||||
|
* @param bool $false False.
|
||||||
|
* @param array $arguments Request arguments.
|
||||||
|
* @param string $url Request URL.
|
||||||
|
*
|
||||||
|
* @return array Header.
|
||||||
|
*/
|
||||||
|
public function fake_http_request( $false, $arguments, $url ) {
|
||||||
|
|
||||||
|
// Video and audio headers.
|
||||||
|
$fake_headers = array(
|
||||||
|
'mp4' => array(
|
||||||
|
'headers' => array(
|
||||||
|
'content-length' => 123,
|
||||||
|
'content-type' => 'video/mp4',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'ogg' => array(
|
||||||
|
'headers' => array(
|
||||||
|
'content-length' => 321,
|
||||||
|
'content-type' => 'audio/ogg',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$path = parse_url( $url, PHP_URL_PATH );
|
||||||
|
|
||||||
|
if ( false !== $path ) {
|
||||||
|
$extension = pathinfo( $path, PATHINFO_EXTENSION );
|
||||||
|
if ( isset( $fake_headers[ $extension ] ) ) {
|
||||||
|
return $fake_headers[ $extension ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback header.
|
||||||
|
return array(
|
||||||
|
'headers' => array(
|
||||||
|
'content-length' => 0,
|
||||||
|
'content-type' => '',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue