mirror of
https://github.com/gosticks/wordpress-develop.git
synced 2025-10-16 12:05:38 +00:00
Export: Include featured image for posts or pages.
This bugfix resolves an issue in `export_wp()` with featured images. When using Tools > Export and selecting either Posts or Pages (with or without a specific author), the resulting XML file now includes a XML item for each post|page's featured image attachment and its metadata. Uses same chunking (for performance) and code patterns from existing code in the same file. Adds a new test class for `export_wp()` with code coverage specific to this bugfix. Follow-up to [34326], [14444], [6375], [6335]. Props billseymour, nateallen, petitphp, hellofromTonya, duck_, jane, rcain, jghazally, jghazally, smub, batmoo, axwax, creativeslice, dlocc, nacin, wonderboymusic, ganon, SergeyBiryukov, hlashbrooke, chriscct7, fischfood, hifidesign, ankit-k-gupta, 5um17, shailu25, huzaifaalmesbah, mukesh27. Fixes #17379. git-svn-id: https://develop.svn.wordpress.org/trunk@57681 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
3a196ba354
commit
6c2ed039cb
@ -144,6 +144,52 @@ function export_wp( $args = array() ) {
|
||||
// Grab a snapshot of post IDs, just in case it changes during the export.
|
||||
$post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where" );
|
||||
|
||||
// Get IDs for the attachments of each post, unless all content is already being exported.
|
||||
if ( ! in_array( $args['content'], array( 'all', 'attachment' ), true ) ) {
|
||||
// Array to hold all additional IDs (attachments and thumbnails).
|
||||
$additional_ids = array();
|
||||
|
||||
// Create a copy of the post IDs array to avoid modifying the original array.
|
||||
$processing_ids = $post_ids;
|
||||
|
||||
while ( $next_posts = array_splice( $processing_ids, 0, 20 ) ) {
|
||||
$posts_in = array_map( 'absint', $next_posts );
|
||||
$placeholders = array_fill( 0, count( $posts_in ), '%d' );
|
||||
|
||||
// Create a string for the placeholders.
|
||||
$in_placeholder = implode( ',', $placeholders );
|
||||
|
||||
// Prepare the SQL statement for attachment ids.
|
||||
$attachment_ids = $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT ID
|
||||
FROM $wpdb->posts
|
||||
WHERE post_parent IN ($in_placeholder) AND post_type = 'attachment'
|
||||
",
|
||||
$posts_in
|
||||
)
|
||||
);
|
||||
|
||||
$thumbnails_ids = $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT meta_value
|
||||
FROM $wpdb->postmeta
|
||||
WHERE $wpdb->postmeta.post_id IN ($in_placeholder)
|
||||
AND $wpdb->postmeta.meta_key = '_thumbnail_id'
|
||||
",
|
||||
$posts_in
|
||||
)
|
||||
);
|
||||
|
||||
$additional_ids = array_merge( $additional_ids, $attachment_ids, $thumbnails_ids );
|
||||
}
|
||||
|
||||
// Merge the additional IDs back with the original post IDs after processing all posts
|
||||
$post_ids = array_unique( array_merge( $post_ids, $additional_ids ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the requested terms ready, empty unless posts filtered by category
|
||||
* or all content.
|
||||
|
||||
293
tests/phpunit/tests/admin/exportWp.php
Normal file
293
tests/phpunit/tests/admin/exportWp.php
Normal file
@ -0,0 +1,293 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @group admin
|
||||
* @group export
|
||||
*
|
||||
* @covers ::export_wp
|
||||
*
|
||||
* Tests run in a separate process to prevent "headers already sent" error.
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
*/
|
||||
class Tests_Admin_ExportWp extends WP_UnitTestCase {
|
||||
/**
|
||||
* Post IDs for posts, pages, and attachments.
|
||||
*
|
||||
* The structure is shown for understanding how to
|
||||
* lookup / reference the information within it.
|
||||
*
|
||||
* IDs will be created in this order.
|
||||
*
|
||||
* @var array {
|
||||
* @type array $data {
|
||||
* Data for each post, page, or attachment.
|
||||
*
|
||||
* @type int $post_id The ID for the post, page, or attachment.
|
||||
* @type int $post_author The author's ID.
|
||||
* @type int $xml_item_index The XML item index for this post, page, or attachment.
|
||||
* This number is based upon all of the posts, pages, and attachments
|
||||
* in the self::$post_ids static property.
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
private static $post_ids = array(
|
||||
'post 1' => array(),
|
||||
'attachment for post 1' => array(),
|
||||
'post 2' => array(),
|
||||
'attachment for post 2' => array(),
|
||||
'page 1' => array(),
|
||||
'attachment for page 1' => array(),
|
||||
'page 2' => array(),
|
||||
'attachment for page 2' => array(),
|
||||
);
|
||||
|
||||
public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/export.php';
|
||||
$file = DIR_TESTDATA . '/images/test-image.jpg';
|
||||
|
||||
$dataset = array(
|
||||
'post 1' => array(
|
||||
'post_title' => 'Test Post 1',
|
||||
'post_type' => 'post',
|
||||
),
|
||||
'post 2' => array(
|
||||
'post_title' => 'Test Post 2',
|
||||
'post_type' => 'post',
|
||||
),
|
||||
'page 1' => array(
|
||||
'post_title' => 'Test Page 1',
|
||||
'post_type' => 'page',
|
||||
),
|
||||
'page 2' => array(
|
||||
'post_title' => 'Test Page 2',
|
||||
'post_type' => 'page',
|
||||
),
|
||||
);
|
||||
|
||||
$xml_item_index = -1;
|
||||
|
||||
foreach ( $dataset as $post_key => $post_data ) {
|
||||
$attachment_key = "attachment for $post_key";
|
||||
$post_data['post_author'] = $factory->user->create( array( 'role' => 'editor' ) );
|
||||
|
||||
$post_id = $factory->post->create( $post_data );
|
||||
$attachment_id = $factory->attachment->create_upload_object( $file, $post_id );
|
||||
set_post_thumbnail( $post_id, $attachment_id );
|
||||
|
||||
self::$post_ids[ $post_key ] = array(
|
||||
'post_id' => $post_id,
|
||||
'post_author' => $post_data['post_author'],
|
||||
'xml_item_index' => ++$xml_item_index,
|
||||
);
|
||||
self::$post_ids[ $attachment_key ] = array(
|
||||
'post_id' => $attachment_id,
|
||||
'post_author' => $post_data['post_author'],
|
||||
'xml_item_index' => ++$xml_item_index,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_should_include_attachments
|
||||
*
|
||||
* @ticket 17379
|
||||
*
|
||||
* @param array $args Arguments to pass to export_wp().
|
||||
* @param array $expected {
|
||||
* The expected data.
|
||||
*
|
||||
* @type array $items {
|
||||
* The expected XML items count assertion arguments.
|
||||
*
|
||||
* @type int $number_of_items The expected number of XML items.
|
||||
* @type string $message The assertion failure message.
|
||||
* }
|
||||
* @type array $ids A list of self::$post_ids keys.
|
||||
*/
|
||||
public function test_should_include_attachments( array $args, array $expected ) {
|
||||
$this->populate_args_post_authors( $args, $expected['ids'] );
|
||||
|
||||
$xml = $this->get_the_export( $args );
|
||||
|
||||
$expected_number_of_items = $expected['items']['number_of_items'];
|
||||
$this->assertCount( $expected_number_of_items, $xml->channel->item, $expected['items']['message'] );
|
||||
|
||||
// Test each XML item's post ID to valid the post, page, and attachment (when appropriate) were exported.
|
||||
foreach ( $expected['ids'] as $post_ids_key ) {
|
||||
$xml_item = $this->get_xml_item( $xml, $post_ids_key, $expected_number_of_items );
|
||||
|
||||
$this->assertSame(
|
||||
$this->get_expected_id( $post_ids_key ),
|
||||
(int) $xml_item->post_id,
|
||||
"In the XML, the {$post_ids_key}'s ID should match the expected content"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data_should_include_attachments() {
|
||||
return array(
|
||||
'for all content' => array(
|
||||
'args' => array(
|
||||
'content' => 'all',
|
||||
),
|
||||
'expected' => array(
|
||||
'items' => array(
|
||||
'number_of_items' => 8,
|
||||
'message' => 'The number of items should be 8 = 2 pages, 2 posts and 4 attachments',
|
||||
),
|
||||
'ids' => array(
|
||||
'post 1',
|
||||
'post 2',
|
||||
'page 1',
|
||||
'page 2',
|
||||
'attachment for page 1',
|
||||
'attachment for post 2',
|
||||
'attachment for page 1',
|
||||
'attachment for page 2',
|
||||
),
|
||||
),
|
||||
),
|
||||
'for all posts' => array(
|
||||
'args' => array(
|
||||
'content' => 'post',
|
||||
),
|
||||
'expected' => array(
|
||||
'items' => array(
|
||||
'number_of_items' => 4,
|
||||
'message' => 'The number of items should be 4 = 2 posts and 2 attachments',
|
||||
),
|
||||
'ids' => array(
|
||||
'post 1',
|
||||
'post 2',
|
||||
'attachment for post 1',
|
||||
'attachment for post 2',
|
||||
),
|
||||
),
|
||||
),
|
||||
'for all pages' => array(
|
||||
'args' => array(
|
||||
'content' => 'page',
|
||||
),
|
||||
'expected' => array(
|
||||
'items' => array(
|
||||
'number_of_items' => 4,
|
||||
'message' => 'The number of items should be 4 = 2 pages and 2 attachments',
|
||||
),
|
||||
'ids' => array(
|
||||
'page 1',
|
||||
'attachment for page 1',
|
||||
'page 2',
|
||||
'attachment for page 2',
|
||||
),
|
||||
),
|
||||
),
|
||||
'for specific author posts' => array(
|
||||
'args' => array(
|
||||
'content' => 'post',
|
||||
'author' => '', // The test will populate the author's ID.
|
||||
),
|
||||
'expected' => array(
|
||||
'items' => array(
|
||||
'number_of_items' => 2,
|
||||
'message' => 'The number of items should be 2 = 1 post and 1 attachment',
|
||||
),
|
||||
'ids' => array(
|
||||
'post 1',
|
||||
'attachment for post 1',
|
||||
),
|
||||
),
|
||||
),
|
||||
'for specific author pages' => array(
|
||||
'args' => array(
|
||||
'content' => 'page',
|
||||
'author' => '', // The test will populate the author's ID.
|
||||
),
|
||||
'expected' => array(
|
||||
'items' => array(
|
||||
'number_of_items' => 2,
|
||||
'message' => 'The number of items should be 2 = 1 page and 1 attachment',
|
||||
),
|
||||
'ids' => array(
|
||||
'page 2',
|
||||
'attachment for page 2',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the export results.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param array $args Arguments to pass to export_wp().
|
||||
* @return SimpleXMLElement|false Returns the XML object on success, otherwise false is returned.
|
||||
*/
|
||||
private function get_the_export( $args ) {
|
||||
ob_start();
|
||||
export_wp( $args );
|
||||
$results = ob_get_clean();
|
||||
|
||||
return simplexml_load_string( $results );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expected ID.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param string $post_ids_key The key to lookup in the $post_ids static property.
|
||||
* @return int Expected ID.
|
||||
*/
|
||||
private function get_expected_id( $post_ids_key ) {
|
||||
$post_info = self::$post_ids[ $post_ids_key ];
|
||||
|
||||
return $post_info['post_id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the XML item for the given post or attachment in the self::$post_ids.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param SimpleXMLElement $xml XML object.
|
||||
* @param string $post_ids_key The key to lookup in the $post_ids static property.
|
||||
* @param int $number_of_items The number of expected XML items.
|
||||
* @return SimpleXMLElement The XML item.
|
||||
*/
|
||||
private function get_xml_item( $xml, $post_ids_key, $number_of_items ) {
|
||||
$post_info = self::$post_ids[ $post_ids_key ];
|
||||
|
||||
if ( $post_info['xml_item_index'] < $number_of_items ) {
|
||||
$xml_item_index = $post_info['xml_item_index'];
|
||||
} elseif ( 2 === $number_of_items ) {
|
||||
$xml_item_index = 0 === $post_info['xml_item_index'] % 2 ? 0 : 1;
|
||||
} else {
|
||||
$xml_item_index = $post_info['xml_item_index'] - $number_of_items;
|
||||
}
|
||||
|
||||
return $xml->channel->item[ $xml_item_index ]->children( 'wp', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the post author in the given args.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param array $args Passed by reference. export_wp() arguments to process.
|
||||
*/
|
||||
private function populate_args_post_authors( array &$args, $expected_ids ) {
|
||||
if ( ! isset( $args['author'] ) ) {
|
||||
return;
|
||||
}
|
||||
$post_ids_key = $expected_ids[0];
|
||||
$args['author'] = self::$post_ids[ $post_ids_key ]['post_author'];
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user