diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php
index e569e02ef1..174c5c1b6e 100644
--- a/src/wp-includes/class-wp-query.php
+++ b/src/wp-includes/class-wp-query.php
@@ -1546,6 +1546,7 @@ class WP_Query {
 			'menu_order',
 			'comment_count',
 			'rand',
+			'post__in',
 		);
 
 		$primary_meta_key   = '';
@@ -1603,6 +1604,11 @@ class WP_Query {
 			case 'meta_value_num':
 				$orderby_clause = "{$primary_meta_query['alias']}.meta_value+0";
 				break;
+			case 'post__in':
+				if ( ! empty( $this->query_vars['post__in'] ) ) {
+					$orderby_clause = "FIELD({$wpdb->posts}.ID," . implode( ',', array_map( 'absint', $this->query_vars['post__in'] ) ) . ')';
+				}
+				break;
 			default:
 				if ( array_key_exists( $orderby, $meta_clauses ) ) {
 					// $orderby corresponds to a meta_query clause.
@@ -1627,18 +1633,26 @@ class WP_Query {
 	 * @since 4.0.0
 	 *
 	 * @param string $order The 'order' query variable.
+	 * @param string $orderby The 'orderby' query variable.
 	 * @return string The sanitized 'order' query variable.
 	 */
-	protected function parse_order( $order ) {
-		if ( ! is_string( $order ) || empty( $order ) ) {
-			return 'DESC';
+	protected function parse_order( $order, $orderby = '' ) {
+		if ( 'rand' === $orderby || 'none' === $orderby ) {
+			return '';
 		}
 
-		if ( 'ASC' === strtoupper( $order ) ) {
+		// These sorts should default to "ASC".
+		$force_asc = array( 'post__in', 'post_name__in', 'post_parent__in' );
+
+		if ( in_array( $orderby, $force_asc ) ) {
 			return 'ASC';
-		} else {
+		}
+
+		if ( ! is_string( $order ) || empty( $order ) ) {
 			return 'DESC';
 		}
+
+		return ( 'ASC' === strtoupper( $order ) ) ? 'ASC' : 'DESC';
 	}
 
 	/**
@@ -2232,68 +2246,59 @@ class WP_Query {
 			$where  .= $clauses['where'];
 		}
 
-		$rand = ( isset( $q['orderby'] ) && 'rand' === $q['orderby'] );
-		if ( ! isset( $q['order'] ) ) {
-			$q['order'] = $rand ? '' : 'DESC';
-		} else {
-			$q['order'] = $rand ? '' : $this->parse_order( $q['order'] );
-		}
-
 		// Order by.
-		if ( empty( $q['orderby'] ) ) {
+		$orderby_array = array();
+		$orderby = isset( $q['orderby'] ) ? $q['orderby'] : '';
+		$order = isset( $q['order'] ) ? $q['order'] : '';
+		$order = $this->parse_order( $order, $orderby );
+
+		if ( empty( $orderby ) ) {
 			/*
 			 * Boolean false or empty array blanks out ORDER BY,
 			 * while leaving the value unset or otherwise empty sets the default.
 			 */
-			if ( isset( $q['orderby'] ) && ( is_array( $q['orderby'] ) || false === $q['orderby'] ) ) {
-				$orderby = '';
-			} else {
-				$orderby = "{$wpdb->posts}.post_date " . $q['order'];
+			if ( ! is_array( $orderby ) && false !== $orderby ) {
+				$orderby  = "{$wpdb->posts}.post_date";
 			}
-		} elseif ( 'none' == $q['orderby'] ) {
+		}
+		elseif ( 'none' == $orderby ) {
 			$orderby = '';
-		} elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
-			$orderby = "FIELD( {$wpdb->posts}.ID, $post__in )";
-		} elseif ( $q['orderby'] == 'post_parent__in' && ! empty( $post_parent__in ) ) {
+		}
+		elseif ( 'post_parent__in' == $orderby && ! empty( $post_parent__in ) ) {
 			$orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )";
-		} elseif ( $q['orderby'] == 'post_name__in' && ! empty( $post_name__in ) ) {
+		}
+		elseif ( 'post_name__in' == $orderby && ! empty( $post_name__in ) ) {
 			$orderby = "FIELD( {$wpdb->posts}.post_name, $post_name__in )";
-		} else {
+		}
+		/**
+		 * Convert 'orderby' string to an array, which supports all of the following:
+		 * 'orderby' => 'title'
+		 * 'orderby' => 'title menu_order'
+		 * 'orderby' => array( 'title' => ASC', 'menu_order' => 'DESC' )
+		 */
+		elseif ( is_string( $orderby ) ) {
+			foreach ( explode( ' ', trim( $orderby ) ) as $key ) {
+				$orderby_array[ $key ] = $order;
+			}
+			$orderby = $orderby_array;
 			$orderby_array = array();
-			if ( is_array( $q['orderby'] ) ) {
-				foreach ( $q['orderby'] as $_orderby => $order ) {
-					$orderby = addslashes_gpc( urldecode( $_orderby ) );
-					$parsed  = $this->parse_orderby( $orderby );
-
-					if ( ! $parsed ) {
-						continue;
-					}
-
-					$orderby_array[] = $parsed . ' ' . $this->parse_order( $order );
-				}
-				$orderby = implode( ', ', $orderby_array );
-
-			} else {
-				$q['orderby'] = urldecode( $q['orderby'] );
-				$q['orderby'] = addslashes_gpc( $q['orderby'] );
-
-				foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
-					$parsed = $this->parse_orderby( $orderby );
-					// Only allow certain values for safety.
-					if ( ! $parsed ) {
-						continue;
-					}
+		}
 
-					$orderby_array[] = $parsed;
-				}
-				$orderby = implode( ' ' . $q['order'] . ', ', $orderby_array );
+		if ( is_array( $orderby ) ) {
+			foreach ( $orderby as $_orderby => $order ) {
+				$orderby_clean = addslashes_gpc( urldecode( $_orderby ) );
+				$parsed = $this->parse_orderby( $orderby_clean );
 
-				if ( empty( $orderby ) ) {
-					$orderby = "{$wpdb->posts}.post_date " . $q['order'];
-				} elseif ( ! empty( $q['order'] ) ) {
-					$orderby .= " {$q['order']}";
+				// Only allow certain values for safety.
+				if ( $parsed ) {
+					$orderby_array[] = $parsed . ' ' . $this->parse_order( $order, $orderby_clean );
 				}
 			}
+
+			$orderby = implode( ', ', $orderby_array );
+		}
+		elseif ( ! empty( $orderby ) && ! empty( $order ) ) {
+			$orderby .= " $order";
 		}
 
 		// Order search results by relevance only when another "orderby" is not specified in the query.
diff --git a/tests/phpunit/tests/post/query.php b/tests/phpunit/tests/post/query.php
index 3e95e73605..1112c87e04 100644
--- a/tests/phpunit/tests/post/query.php
+++ b/tests/phpunit/tests/post/query.php
@@ -174,6 +174,38 @@ class Tests_Post_Query extends WP_UnitTestCase {
 		$this->assertSame( $ordered, wp_list_pluck( $q->posts, 'ID' ) );
 	}
 
+	/**
+	 * @ticket 38034
+	 */
+	public function test_orderby_post__in_array() {
+		$posts = self::factory()->post->create_many( 4 );
+
+		$ordered = array( $posts[2], $posts[0], $posts[3] );
+
+		$q = new WP_Query( array(
+			'post_type' => 'any',
+			'post__in' => $ordered,
+			'orderby' => array( 'post__in' => 'ASC' ),
+		) );
+		$this->assertSame( $ordered, wp_list_pluck( $q->posts, 'ID' ) );
+	}
+
+	/**
+	 * @ticket 38034
+	 */
+	public function test_orderby_post__in_array_with_implied_order() {
+		$posts = self::factory()->post->create_many( 4 );
+
+		$ordered = array( $posts[2], $posts[0], $posts[3] );
+
+		$q = new WP_Query( array(
+			'post_type' => 'any',
+			'post__in' => $ordered,
+			'orderby' => 'post__in',
+		) );
+		$this->assertSame( $ordered, wp_list_pluck( $q->posts, 'ID' ) );
+	}
+
 	function test_post__in_attachment_ordering() {
 		$post_id    = self::factory()->post->create();
 		$att_ids    = array();
