Index: src/wp-includes/class-wp-customize-manager.php
===================================================================
--- src/wp-includes/class-wp-customize-manager.php	(revision 41820)
+++ src/wp-includes/class-wp-customize-manager.php	(working copy)
@@ -2831,6 +2831,79 @@
 	}
 
 	/**
+	 * Trash or delete a changeset post.
+	 *
+	 * The following re-formulates the logic from wp_trash_post() as done in
+	 * wp_publish_post(). The reason for bypassing wp_trash_post() is that it
+	 * will mutate the the post_content and the post_name when they should be
+	 * untouched.
+	 *
+	 * @since 4.9.0
+	 * @global wpdb $wpdb WordPress database abstraction object.
+	 *
+	 * @param int $post_id The changeset post ID.
+	 * @return mixed A WP_Post object for the trashed post or an empty value on failure.
+	 */
+	public function trash_changeset_post( $post_id ) {
+		global $wpdb;
+
+		$post_id = (int) $post_id;
+
+		if ( ! EMPTY_TRASH_DAYS ) {
+			return wp_delete_post( $post_id, true );
+		}
+
+		$post = get_post( $post_id );
+
+		if ( ! ( $post instanceof WP_Post ) ) {
+			return $post;
+		}
+
+		if ( 'trash' === get_post_status( $post ) ) {
+			return false;
+		}
+
+		/** This filter is documented in wp-includes/post.php */
+		$check = apply_filters( 'pre_trash_post', null, $post );
+		if ( null !== $check ) {
+			return $check;
+		}
+
+		/** This action is documented in wp-includes/post.php */
+		do_action( 'wp_trash_post', $post_id );
+
+		add_post_meta( $post_id, '_wp_trash_meta_status', $post->post_status );
+		add_post_meta( $post_id, '_wp_trash_meta_time', time() );
+
+		$old_status = $post->post_status;
+		$new_status = 'trash';
+		$wpdb->update( $wpdb->posts, array( 'post_status' => $new_status ), array( 'ID' => $post->ID ) );
+		clean_post_cache( $post->ID );
+
+		$post->post_status = $new_status;
+		wp_transition_post_status( $new_status, $old_status, $post );
+
+		/** This action is documented in wp-includes/post.php */
+		do_action( 'edit_post', $post->ID, $post );
+
+		/** This action is documented in wp-includes/post.php */
+		do_action( "save_post_{$post->post_type}", $post->ID, $post, true );
+
+		/** This action is documented in wp-includes/post.php */
+		do_action( 'save_post', $post->ID, $post, true );
+
+		/** This action is documented in wp-includes/post.php */
+		do_action( 'wp_insert_post', $post->ID, $post, true );
+
+		wp_trash_post_comments( $post_id );
+
+		/** This action is documented in wp-includes/post.php */
+		do_action( 'trashed_post', $post_id );
+
+		return $post;
+	}
+
+	/**
 	 * Handle request to trash a changeset.
 	 *
 	 * @since 4.9.0
@@ -2876,7 +2949,7 @@
 			return;
 		}
 
-		$r = wp_trash_post( $changeset_post_id );
+		$r = $this->trash_changeset_post( $changeset_post_id );
 		if ( ! ( $r instanceof WP_Post ) ) {
 			wp_send_json_error( array(
 				'code' => 'changeset_trash_failure',
Index: src/wp-includes/theme.php
===================================================================
--- src/wp-includes/theme.php	(revision 41820)
+++ src/wp-includes/theme.php	(working copy)
@@ -2909,47 +2909,7 @@
 	 * and thus garbage collected.
 	 */
 	if ( ! wp_revisions_enabled( $changeset_post ) ) {
-		$post = $changeset_post;
-		$post_id = $changeset_post->ID;
-
-		/*
-		 * The following re-formulates the logic from wp_trash_post() as done in
-		 * wp_publish_post(). The reason for bypassing wp_trash_post() is that it
-		 * will mutate the post_content and the post_name when they should be
-		 * untouched.
-		 */
-		if ( ! EMPTY_TRASH_DAYS ) {
-			wp_delete_post( $post_id, true );
-		} else {
-			/** This action is documented in wp-includes/post.php */
-			do_action( 'wp_trash_post', $post_id );
-
-			add_post_meta( $post_id, '_wp_trash_meta_status', $post->post_status );
-			add_post_meta( $post_id, '_wp_trash_meta_time', time() );
-
-			$old_status = $post->post_status;
-			$new_status = 'trash';
-			$wpdb->update( $wpdb->posts, array( 'post_status' => $new_status ), array( 'ID' => $post->ID ) );
-			clean_post_cache( $post->ID );
-
-			$post->post_status = $new_status;
-			wp_transition_post_status( $new_status, $old_status, $post );
-
-			/** This action is documented in wp-includes/post.php */
-			do_action( 'edit_post', $post->ID, $post );
-
-			/** This action is documented in wp-includes/post.php */
-			do_action( "save_post_{$post->post_type}", $post->ID, $post, true );
-
-			/** This action is documented in wp-includes/post.php */
-			do_action( 'save_post', $post->ID, $post, true );
-
-			/** This action is documented in wp-includes/post.php */
-			do_action( 'wp_insert_post', $post->ID, $post, true );
-
-			/** This action is documented in wp-includes/post.php */
-			do_action( 'trashed_post', $post_id );
-		}
+		$wp_customize->trash_changeset_post( $changeset_post->ID );
 	}
 }
 
Index: tests/phpunit/tests/customize/manager.php
===================================================================
--- tests/phpunit/tests/customize/manager.php	(revision 41820)
+++ tests/phpunit/tests/customize/manager.php	(working copy)
@@ -1710,6 +1710,35 @@
 	}
 
 	/**
+	 * Test that trash_changeset_post() trashes a changeset post with its name and content preserved.
+	 *
+ 	 * @covers WP_Customize_Manager::trash_changeset_post
+	 */
+	function test_trash_changeset_post_preserves_properties() {
+		$args = array(
+			'post_type' => 'customize_changeset',
+			'post_content' => wp_json_encode( array(
+				'blogname' => array(
+					'value' => 'Test',
+				),
+			) ),
+			'post_name' => wp_generate_uuid4(),
+			'post_status' => 'draft',
+		);
+
+		$post_id = wp_insert_post( $args );
+
+		$manager = $this->create_test_manager( $args['post_name'] );
+		$manager->trash_changeset_post( $post_id );
+
+		$post = get_post( $post_id );
+
+		$this->assertSame( 'trash', get_post_status( $post_id ) );
+		$this->assertSame( $args['post_name'], $post->post_name );
+		$this->assertSame( $args['post_content'], $post->post_content );
+	}
+
+	/**
 	 * Register scratchpad setting.
 	 *
 	 * @param WP_Customize_Manager $wp_customize Manager.
