wp/wp-admin/includes/export.php
changeset 21 48c4eec2b7e6
parent 18 be944660c56a
--- a/wp/wp-admin/includes/export.php	Thu Sep 29 08:06:27 2022 +0200
+++ b/wp/wp-admin/includes/export.php	Fri Sep 05 18:40:08 2025 +0200
@@ -31,27 +31,27 @@
  * @param array $args {
  *     Optional. Arguments for generating the WXR export file for download. Default empty array.
  *
- *     @type string $content        Type of content to export. If set, only the post content of this post type
- *                                  will be exported. Accepts 'all', 'post', 'page', 'attachment', or a defined
- *                                  custom post. If an invalid custom post type is supplied, every post type for
- *                                  which `can_export` is enabled will be exported instead. If a valid custom post
- *                                  type is supplied but `can_export` is disabled, then 'posts' will be exported
- *                                  instead. When 'all' is supplied, only post types with `can_export` enabled will
- *                                  be exported. Default 'all'.
- *     @type string $author         Author to export content for. Only used when `$content` is 'post', 'page', or
- *                                  'attachment'. Accepts false (all) or a specific author ID. Default false (all).
- *     @type string $category       Category (slug) to export content for. Used only when `$content` is 'post'. If
- *                                  set, only post content assigned to `$category` will be exported. Accepts false
- *                                  or a specific category slug. Default is false (all categories).
- *     @type string $start_date     Start date to export content from. Expected date format is 'Y-m-d'. Used only
- *                                  when `$content` is 'post', 'page' or 'attachment'. Default false (since the
- *                                  beginning of time).
- *     @type string $end_date       End date to export content to. Expected date format is 'Y-m-d'. Used only when
- *                                  `$content` is 'post', 'page' or 'attachment'. Default false (latest publish date).
- *     @type string $status         Post status to export posts for. Used only when `$content` is 'post' or 'page'.
- *                                  Accepts false (all statuses except 'auto-draft'), or a specific status, i.e.
- *                                  'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', or
- *                                  'trash'. Default false (all statuses except 'auto-draft').
+ *     @type string $content    Type of content to export. If set, only the post content of this post type
+ *                              will be exported. Accepts 'all', 'post', 'page', 'attachment', or a defined
+ *                              custom post. If an invalid custom post type is supplied, every post type for
+ *                              which `can_export` is enabled will be exported instead. If a valid custom post
+ *                              type is supplied but `can_export` is disabled, then 'posts' will be exported
+ *                              instead. When 'all' is supplied, only post types with `can_export` enabled will
+ *                              be exported. Default 'all'.
+ *     @type string $author     Author to export content for. Only used when `$content` is 'post', 'page', or
+ *                              'attachment'. Accepts false (all) or a specific author ID. Default false (all).
+ *     @type string $category   Category (slug) to export content for. Used only when `$content` is 'post'. If
+ *                              set, only post content assigned to `$category` will be exported. Accepts false
+ *                              or a specific category slug. Default is false (all categories).
+ *     @type string $start_date Start date to export content from. Expected date format is 'Y-m-d'. Used only
+ *                              when `$content` is 'post', 'page' or 'attachment'. Default false (since the
+ *                              beginning of time).
+ *     @type string $end_date   End date to export content to. Expected date format is 'Y-m-d'. Used only when
+ *                              `$content` is 'post', 'page' or 'attachment'. Default false (latest publish date).
+ *     @type string $status     Post status to export posts for. Used only when `$content` is 'post' or 'page'.
+ *                              Accepts false (all statuses except 'auto-draft'), or a specific status, i.e.
+ *                              'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', or
+ *                              'trash'. Default false (all statuses except 'auto-draft').
  * }
  */
 function export_wp( $args = array() ) {
@@ -144,6 +144,52 @@
 	// 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.
@@ -189,7 +235,7 @@
 	}
 
 	/**
-	 * Wrap given string in XML CDATA tag.
+	 * Wraps given string in XML CDATA tag.
 	 *
 	 * @since 2.1.0
 	 *
@@ -207,7 +253,7 @@
 	}
 
 	/**
-	 * Return the URL of the site
+	 * Returns the URL of the site.
 	 *
 	 * @since 2.5.0
 	 *
@@ -218,17 +264,17 @@
 			// Multisite: the base URL.
 			return network_home_url();
 		} else {
-			// WordPress (single site): the blog URL.
+			// WordPress (single site): the site URL.
 			return get_bloginfo_rss( 'url' );
 		}
 	}
 
 	/**
-	 * Output a cat_name XML tag from a given category object
+	 * Outputs a cat_name XML tag from a given category object.
 	 *
 	 * @since 2.1.0
 	 *
-	 * @param WP_Term $category Category Object
+	 * @param WP_Term $category Category Object.
 	 */
 	function wxr_cat_name( $category ) {
 		if ( empty( $category->name ) ) {
@@ -239,11 +285,11 @@
 	}
 
 	/**
-	 * Output a category_description XML tag from a given category object
+	 * Outputs a category_description XML tag from a given category object.
 	 *
 	 * @since 2.1.0
 	 *
-	 * @param WP_Term $category Category Object
+	 * @param WP_Term $category Category Object.
 	 */
 	function wxr_category_description( $category ) {
 		if ( empty( $category->description ) ) {
@@ -254,11 +300,11 @@
 	}
 
 	/**
-	 * Output a tag_name XML tag from a given tag object
+	 * Outputs a tag_name XML tag from a given tag object.
 	 *
 	 * @since 2.3.0
 	 *
-	 * @param WP_Term $tag Tag Object
+	 * @param WP_Term $tag Tag Object.
 	 */
 	function wxr_tag_name( $tag ) {
 		if ( empty( $tag->name ) ) {
@@ -269,11 +315,11 @@
 	}
 
 	/**
-	 * Output a tag_description XML tag from a given tag object
+	 * Outputs a tag_description XML tag from a given tag object.
 	 *
 	 * @since 2.3.0
 	 *
-	 * @param WP_Term $tag Tag Object
+	 * @param WP_Term $tag Tag Object.
 	 */
 	function wxr_tag_description( $tag ) {
 		if ( empty( $tag->description ) ) {
@@ -284,11 +330,11 @@
 	}
 
 	/**
-	 * Output a term_name XML tag from a given term object
+	 * Outputs a term_name XML tag from a given term object.
 	 *
 	 * @since 2.9.0
 	 *
-	 * @param WP_Term $term Term Object
+	 * @param WP_Term $term Term Object.
 	 */
 	function wxr_term_name( $term ) {
 		if ( empty( $term->name ) ) {
@@ -299,11 +345,11 @@
 	}
 
 	/**
-	 * Output a term_description XML tag from a given term object
+	 * Outputs a term_description XML tag from a given term object.
 	 *
 	 * @since 2.9.0
 	 *
-	 * @param WP_Term $term Term Object
+	 * @param WP_Term $term Term Object.
 	 */
 	function wxr_term_description( $term ) {
 		if ( empty( $term->description ) ) {
@@ -314,10 +360,12 @@
 	}
 
 	/**
-	 * Output term meta XML tags for a given term object.
+	 * Outputs term meta XML tags for a given term object.
 	 *
 	 * @since 4.6.0
 	 *
+	 * @global wpdb $wpdb WordPress database abstraction object.
+	 *
 	 * @param WP_Term $term Term object.
 	 */
 	function wxr_term_meta( $term ) {
@@ -345,7 +393,7 @@
 	}
 
 	/**
-	 * Output list of authors with posts
+	 * Outputs list of authors with posts.
 	 *
 	 * @since 3.1.0
 	 *
@@ -353,7 +401,7 @@
 	 *
 	 * @param int[] $post_ids Optional. Array of post IDs to filter the query by.
 	 */
-	function wxr_authors_list( array $post_ids = null ) {
+	function wxr_authors_list( ?array $post_ids = null ) {
 		global $wpdb;
 
 		if ( ! empty( $post_ids ) ) {
@@ -384,7 +432,7 @@
 	}
 
 	/**
-	 * Output all navigation menu terms
+	 * Outputs all navigation menu terms.
 	 *
 	 * @since 3.1.0
 	 */
@@ -405,7 +453,7 @@
 	}
 
 	/**
-	 * Output list of taxonomy terms, in XML tag format, associated with a post
+	 * Outputs list of taxonomy terms, in XML tag format, associated with a post.
 	 *
 	 * @since 2.3.0
 	 */
@@ -424,8 +472,12 @@
 	}
 
 	/**
-	 * @param bool   $return_me
-	 * @param string $meta_key
+	 * Determines whether to selectively skip post meta used for WXR exports.
+	 *
+	 * @since 3.3.0
+	 *
+	 * @param bool   $return_me Whether to skip the current post meta. Default false.
+	 * @param string $meta_key  Meta key.
 	 * @return bool
 	 */
 	function wxr_filter_postmeta( $return_me, $meta_key ) {
@@ -515,7 +567,8 @@
 	<?php endforeach; ?>
 	<?php
 	if ( 'all' === $args['content'] ) {
-		wxr_nav_menu_terms();}
+		wxr_nav_menu_terms();
+	}
 	?>
 
 	<?php
@@ -632,7 +685,7 @@
 			<wp:comment_id><?php echo (int) $c->comment_ID; ?></wp:comment_id>
 			<wp:comment_author><?php echo wxr_cdata( $c->comment_author ); ?></wp:comment_author>
 			<wp:comment_author_email><?php echo wxr_cdata( $c->comment_author_email ); ?></wp:comment_author_email>
-			<wp:comment_author_url><?php echo esc_url_raw( $c->comment_author_url ); ?></wp:comment_author_url>
+			<wp:comment_author_url><?php echo sanitize_url( $c->comment_author_url ); ?></wp:comment_author_url>
 			<wp:comment_author_IP><?php echo wxr_cdata( $c->comment_author_IP ); ?></wp:comment_author_IP>
 			<wp:comment_date><?php echo wxr_cdata( $c->comment_date ); ?></wp:comment_date>
 			<wp:comment_date_gmt><?php echo wxr_cdata( $c->comment_date_gmt ); ?></wp:comment_date_gmt>