wp/wp-includes/class-wp-query.php
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
equal deleted inserted replaced
21:48c4eec2b7e6 22:8c2e4d02f4ef
   440 	/**
   440 	/**
   441 	 * Whether query vars have changed since the initial parse_query() call. Used to catch modifications to query vars made
   441 	 * Whether query vars have changed since the initial parse_query() call. Used to catch modifications to query vars made
   442 	 * via pre_get_posts hooks.
   442 	 * via pre_get_posts hooks.
   443 	 *
   443 	 *
   444 	 * @since 3.1.1
   444 	 * @since 3.1.1
       
   445 	 * @var bool
   445 	 */
   446 	 */
   446 	private $query_vars_changed = true;
   447 	private $query_vars_changed = true;
   447 
   448 
   448 	/**
   449 	/**
   449 	 * Set if post thumbnails are cached
   450 	 * Set if post thumbnails are cached
   470 	private $stopwords;
   471 	private $stopwords;
   471 
   472 
   472 	private $compat_fields = array( 'query_vars_hash', 'query_vars_changed' );
   473 	private $compat_fields = array( 'query_vars_hash', 'query_vars_changed' );
   473 
   474 
   474 	private $compat_methods = array( 'init_query_flags', 'parse_tax_query' );
   475 	private $compat_methods = array( 'init_query_flags', 'parse_tax_query' );
       
   476 
       
   477 	/**
       
   478 	 * The cache key generated by the query.
       
   479 	 *
       
   480 	 * The cache key is generated by the method ::generate_cache_key() after the
       
   481 	 * query has been normalized.
       
   482 	 *
       
   483 	 * @since 6.8.0
       
   484 	 * @var string
       
   485 	 */
       
   486 	private $query_cache_key = '';
   475 
   487 
   476 	/**
   488 	/**
   477 	 * Resets query flags to false.
   489 	 * Resets query flags to false.
   478 	 *
   490 	 *
   479 	 * The query flags are what page info WordPress was able to figure out.
   491 	 * The query flags are what page info WordPress was able to figure out.
  1098 			}
  1110 			}
  1099 		}
  1111 		}
  1100 
  1112 
  1101 		if ( ! empty( $qv['post_type'] ) ) {
  1113 		if ( ! empty( $qv['post_type'] ) ) {
  1102 			if ( is_array( $qv['post_type'] ) ) {
  1114 			if ( is_array( $qv['post_type'] ) ) {
  1103 				$qv['post_type'] = array_map( 'sanitize_key', $qv['post_type'] );
  1115 				$qv['post_type'] = array_map( 'sanitize_key', array_unique( $qv['post_type'] ) );
       
  1116 				sort( $qv['post_type'] );
  1104 			} else {
  1117 			} else {
  1105 				$qv['post_type'] = sanitize_key( $qv['post_type'] );
  1118 				$qv['post_type'] = sanitize_key( $qv['post_type'] );
  1106 			}
  1119 			}
  1107 		}
  1120 		}
  1108 
  1121 
  1109 		if ( ! empty( $qv['post_status'] ) ) {
  1122 		if ( ! empty( $qv['post_status'] ) ) {
  1110 			if ( is_array( $qv['post_status'] ) ) {
  1123 			if ( is_array( $qv['post_status'] ) ) {
  1111 				$qv['post_status'] = array_map( 'sanitize_key', $qv['post_status'] );
  1124 				$qv['post_status'] = array_map( 'sanitize_key', array_unique( $qv['post_status'] ) );
       
  1125 				sort( $qv['post_status'] );
  1112 			} else {
  1126 			} else {
  1113 				$qv['post_status'] = preg_replace( '|[^a-z0-9_,-]|', '', $qv['post_status'] );
  1127 				$qv['post_status'] = preg_replace( '|[^a-z0-9_,-]|', '', $qv['post_status'] );
  1114 			}
  1128 			}
  1115 		}
  1129 		}
  1116 
  1130 
  1179 					$q[ $t->query_var ] = wp_basename( $q[ $t->query_var ] );
  1193 					$q[ $t->query_var ] = wp_basename( $q[ $t->query_var ] );
  1180 				}
  1194 				}
  1181 
  1195 
  1182 				$term = $q[ $t->query_var ];
  1196 				$term = $q[ $t->query_var ];
  1183 
  1197 
  1184 				if ( is_array( $term ) ) {
  1198 				if ( ! is_array( $term ) ) {
  1185 					$term = implode( ',', $term );
  1199 					$term = explode( ',', $term );
  1186 				}
  1200 					$term = array_map( 'trim', $term );
       
  1201 				}
       
  1202 				sort( $term );
       
  1203 				$term = implode( ',', $term );
  1187 
  1204 
  1188 				if ( str_contains( $term, '+' ) ) {
  1205 				if ( str_contains( $term, '+' ) ) {
  1189 					$terms = preg_split( '/[+]+/', $term );
  1206 					$terms = preg_split( '/[+]+/', $term );
  1190 					foreach ( $terms as $term ) {
  1207 					foreach ( $terms as $term ) {
  1191 						$tax_query[] = array_merge(
  1208 						$tax_query[] = array_merge(
  1217 			$cat_in     = array();
  1234 			$cat_in     = array();
  1218 			$cat_not_in = array();
  1235 			$cat_not_in = array();
  1219 
  1236 
  1220 			$cat_array = preg_split( '/[,\s]+/', urldecode( $q['cat'] ) );
  1237 			$cat_array = preg_split( '/[,\s]+/', urldecode( $q['cat'] ) );
  1221 			$cat_array = array_map( 'intval', $cat_array );
  1238 			$cat_array = array_map( 'intval', $cat_array );
  1222 			$q['cat']  = implode( ',', $cat_array );
  1239 			sort( $cat_array );
       
  1240 			$q['cat'] = implode( ',', $cat_array );
  1223 
  1241 
  1224 			foreach ( $cat_array as $cat ) {
  1242 			foreach ( $cat_array as $cat ) {
  1225 				if ( $cat > 0 ) {
  1243 				if ( $cat > 0 ) {
  1226 					$cat_in[] = $cat;
  1244 					$cat_in[] = $cat;
  1227 				} elseif ( $cat < 0 ) {
  1245 				} elseif ( $cat < 0 ) {
  1259 			unset( $q['category__and'] );
  1277 			unset( $q['category__and'] );
  1260 		}
  1278 		}
  1261 
  1279 
  1262 		if ( ! empty( $q['category__in'] ) ) {
  1280 		if ( ! empty( $q['category__in'] ) ) {
  1263 			$q['category__in'] = array_map( 'absint', array_unique( (array) $q['category__in'] ) );
  1281 			$q['category__in'] = array_map( 'absint', array_unique( (array) $q['category__in'] ) );
  1264 			$tax_query[]       = array(
  1282 			sort( $q['category__in'] );
       
  1283 			$tax_query[] = array(
  1265 				'taxonomy'         => 'category',
  1284 				'taxonomy'         => 'category',
  1266 				'terms'            => $q['category__in'],
  1285 				'terms'            => $q['category__in'],
  1267 				'field'            => 'term_id',
  1286 				'field'            => 'term_id',
  1268 				'include_children' => false,
  1287 				'include_children' => false,
  1269 			);
  1288 			);
  1270 		}
  1289 		}
  1271 
  1290 
  1272 		if ( ! empty( $q['category__not_in'] ) ) {
  1291 		if ( ! empty( $q['category__not_in'] ) ) {
  1273 			$q['category__not_in'] = array_map( 'absint', array_unique( (array) $q['category__not_in'] ) );
  1292 			$q['category__not_in'] = array_map( 'absint', array_unique( (array) $q['category__not_in'] ) );
  1274 			$tax_query[]           = array(
  1293 			sort( $q['category__not_in'] );
       
  1294 			$tax_query[] = array(
  1275 				'taxonomy'         => 'category',
  1295 				'taxonomy'         => 'category',
  1276 				'terms'            => $q['category__not_in'],
  1296 				'terms'            => $q['category__not_in'],
  1277 				'operator'         => 'NOT IN',
  1297 				'operator'         => 'NOT IN',
  1278 				'include_children' => false,
  1298 				'include_children' => false,
  1279 			);
  1299 			);
  1280 		}
  1300 		}
  1281 
  1301 
  1282 		if ( ! empty( $q['category__and'] ) ) {
  1302 		if ( ! empty( $q['category__and'] ) ) {
  1283 			$q['category__and'] = array_map( 'absint', array_unique( (array) $q['category__and'] ) );
  1303 			$q['category__and'] = array_map( 'absint', array_unique( (array) $q['category__and'] ) );
  1284 			$tax_query[]        = array(
  1304 			sort( $q['category__and'] );
       
  1305 			$tax_query[] = array(
  1285 				'taxonomy'         => 'category',
  1306 				'taxonomy'         => 'category',
  1286 				'terms'            => $q['category__and'],
  1307 				'terms'            => $q['category__and'],
  1287 				'field'            => 'term_id',
  1308 				'field'            => 'term_id',
  1288 				'operator'         => 'AND',
  1309 				'operator'         => 'AND',
  1289 				'include_children' => false,
  1310 				'include_children' => false,
  1297 
  1318 
  1298 		// Tag stuff.
  1319 		// Tag stuff.
  1299 
  1320 
  1300 		if ( '' !== $q['tag'] && ! $this->is_singular && $this->query_vars_changed ) {
  1321 		if ( '' !== $q['tag'] && ! $this->is_singular && $this->query_vars_changed ) {
  1301 			if ( str_contains( $q['tag'], ',' ) ) {
  1322 			if ( str_contains( $q['tag'], ',' ) ) {
       
  1323 				// @todo Handle normalizing `tag` query string.
  1302 				$tags = preg_split( '/[,\r\n\t ]+/', $q['tag'] );
  1324 				$tags = preg_split( '/[,\r\n\t ]+/', $q['tag'] );
  1303 				foreach ( (array) $tags as $tag ) {
  1325 				foreach ( (array) $tags as $tag ) {
  1304 					$tag                 = sanitize_term_field( 'slug', $tag, 0, 'post_tag', 'db' );
  1326 					$tag                 = sanitize_term_field( 'slug', $tag, 0, 'post_tag', 'db' );
  1305 					$q['tag_slug__in'][] = $tag;
  1327 					$q['tag_slug__in'][] = $tag;
       
  1328 					sort( $q['tag_slug__in'] );
  1306 				}
  1329 				}
  1307 			} elseif ( preg_match( '/[+\r\n\t ]+/', $q['tag'] ) || ! empty( $q['cat'] ) ) {
  1330 			} elseif ( preg_match( '/[+\r\n\t ]+/', $q['tag'] ) || ! empty( $q['cat'] ) ) {
  1308 				$tags = preg_split( '/[+\r\n\t ]+/', $q['tag'] );
  1331 				$tags = preg_split( '/[+\r\n\t ]+/', $q['tag'] );
  1309 				foreach ( (array) $tags as $tag ) {
  1332 				foreach ( (array) $tags as $tag ) {
  1310 					$tag                  = sanitize_term_field( 'slug', $tag, 0, 'post_tag', 'db' );
  1333 					$tag                  = sanitize_term_field( 'slug', $tag, 0, 'post_tag', 'db' );
  1311 					$q['tag_slug__and'][] = $tag;
  1334 					$q['tag_slug__and'][] = $tag;
  1312 				}
  1335 				}
  1313 			} else {
  1336 			} else {
  1314 				$q['tag']            = sanitize_term_field( 'slug', $q['tag'], 0, 'post_tag', 'db' );
  1337 				$q['tag']            = sanitize_term_field( 'slug', $q['tag'], 0, 'post_tag', 'db' );
  1315 				$q['tag_slug__in'][] = $q['tag'];
  1338 				$q['tag_slug__in'][] = $q['tag'];
       
  1339 				sort( $q['tag_slug__in'] );
  1316 			}
  1340 			}
  1317 		}
  1341 		}
  1318 
  1342 
  1319 		if ( ! empty( $q['tag_id'] ) ) {
  1343 		if ( ! empty( $q['tag_id'] ) ) {
  1320 			$q['tag_id'] = absint( $q['tag_id'] );
  1344 			$q['tag_id'] = absint( $q['tag_id'] );
  1324 			);
  1348 			);
  1325 		}
  1349 		}
  1326 
  1350 
  1327 		if ( ! empty( $q['tag__in'] ) ) {
  1351 		if ( ! empty( $q['tag__in'] ) ) {
  1328 			$q['tag__in'] = array_map( 'absint', array_unique( (array) $q['tag__in'] ) );
  1352 			$q['tag__in'] = array_map( 'absint', array_unique( (array) $q['tag__in'] ) );
  1329 			$tax_query[]  = array(
  1353 			sort( $q['tag__in'] );
       
  1354 			$tax_query[] = array(
  1330 				'taxonomy' => 'post_tag',
  1355 				'taxonomy' => 'post_tag',
  1331 				'terms'    => $q['tag__in'],
  1356 				'terms'    => $q['tag__in'],
  1332 			);
  1357 			);
  1333 		}
  1358 		}
  1334 
  1359 
  1335 		if ( ! empty( $q['tag__not_in'] ) ) {
  1360 		if ( ! empty( $q['tag__not_in'] ) ) {
  1336 			$q['tag__not_in'] = array_map( 'absint', array_unique( (array) $q['tag__not_in'] ) );
  1361 			$q['tag__not_in'] = array_map( 'absint', array_unique( (array) $q['tag__not_in'] ) );
  1337 			$tax_query[]      = array(
  1362 			sort( $q['tag__not_in'] );
       
  1363 			$tax_query[] = array(
  1338 				'taxonomy' => 'post_tag',
  1364 				'taxonomy' => 'post_tag',
  1339 				'terms'    => $q['tag__not_in'],
  1365 				'terms'    => $q['tag__not_in'],
  1340 				'operator' => 'NOT IN',
  1366 				'operator' => 'NOT IN',
  1341 			);
  1367 			);
  1342 		}
  1368 		}
  1343 
  1369 
  1344 		if ( ! empty( $q['tag__and'] ) ) {
  1370 		if ( ! empty( $q['tag__and'] ) ) {
  1345 			$q['tag__and'] = array_map( 'absint', array_unique( (array) $q['tag__and'] ) );
  1371 			$q['tag__and'] = array_map( 'absint', array_unique( (array) $q['tag__and'] ) );
  1346 			$tax_query[]   = array(
  1372 			sort( $q['tag__and'] );
       
  1373 			$tax_query[] = array(
  1347 				'taxonomy' => 'post_tag',
  1374 				'taxonomy' => 'post_tag',
  1348 				'terms'    => $q['tag__and'],
  1375 				'terms'    => $q['tag__and'],
  1349 				'operator' => 'AND',
  1376 				'operator' => 'AND',
  1350 			);
  1377 			);
  1351 		}
  1378 		}
  1352 
  1379 
  1353 		if ( ! empty( $q['tag_slug__in'] ) ) {
  1380 		if ( ! empty( $q['tag_slug__in'] ) ) {
  1354 			$q['tag_slug__in'] = array_map( 'sanitize_title_for_query', array_unique( (array) $q['tag_slug__in'] ) );
  1381 			$q['tag_slug__in'] = array_map( 'sanitize_title_for_query', array_unique( (array) $q['tag_slug__in'] ) );
  1355 			$tax_query[]       = array(
  1382 			sort( $q['tag_slug__in'] );
       
  1383 			$tax_query[] = array(
  1356 				'taxonomy' => 'post_tag',
  1384 				'taxonomy' => 'post_tag',
  1357 				'terms'    => $q['tag_slug__in'],
  1385 				'terms'    => $q['tag_slug__in'],
  1358 				'field'    => 'slug',
  1386 				'field'    => 'slug',
  1359 			);
  1387 			);
  1360 		}
  1388 		}
  1361 
  1389 
  1362 		if ( ! empty( $q['tag_slug__and'] ) ) {
  1390 		if ( ! empty( $q['tag_slug__and'] ) ) {
  1363 			$q['tag_slug__and'] = array_map( 'sanitize_title_for_query', array_unique( (array) $q['tag_slug__and'] ) );
  1391 			$q['tag_slug__and'] = array_map( 'sanitize_title_for_query', array_unique( (array) $q['tag_slug__and'] ) );
  1364 			$tax_query[]        = array(
  1392 			sort( $q['tag_slug__and'] );
       
  1393 			$tax_query[] = array(
  1365 				'taxonomy' => 'post_tag',
  1394 				'taxonomy' => 'post_tag',
  1366 				'terms'    => $q['tag_slug__and'],
  1395 				'terms'    => $q['tag_slug__and'],
  1367 				'field'    => 'slug',
  1396 				'field'    => 'slug',
  1368 				'operator' => 'AND',
  1397 				'operator' => 'AND',
  1369 			);
  1398 			);
  1900 		$this->meta_query = new WP_Meta_Query();
  1929 		$this->meta_query = new WP_Meta_Query();
  1901 		$this->meta_query->parse_query_vars( $q );
  1930 		$this->meta_query->parse_query_vars( $q );
  1902 
  1931 
  1903 		// Set a flag if a 'pre_get_posts' hook changed the query vars.
  1932 		// Set a flag if a 'pre_get_posts' hook changed the query vars.
  1904 		$hash = md5( serialize( $this->query_vars ) );
  1933 		$hash = md5( serialize( $this->query_vars ) );
  1905 		if ( $hash != $this->query_vars_hash ) {
  1934 		if ( $hash !== $this->query_vars_hash ) {
  1906 			$this->query_vars_changed = true;
  1935 			$this->query_vars_changed = true;
  1907 			$this->query_vars_hash    = $hash;
  1936 			$this->query_vars_hash    = $hash;
  1908 		}
  1937 		}
  1909 		unset( $hash );
  1938 		unset( $hash );
  1910 
  1939 
  2000 			} else {
  2029 			} else {
  2001 				$q['posts_per_page'] = get_option( 'posts_per_rss' );
  2030 				$q['posts_per_page'] = get_option( 'posts_per_rss' );
  2002 			}
  2031 			}
  2003 			$q['nopaging'] = false;
  2032 			$q['nopaging'] = false;
  2004 		}
  2033 		}
       
  2034 
  2005 		$q['posts_per_page'] = (int) $q['posts_per_page'];
  2035 		$q['posts_per_page'] = (int) $q['posts_per_page'];
  2006 		if ( $q['posts_per_page'] < -1 ) {
  2036 		if ( $q['posts_per_page'] < -1 ) {
  2007 			$q['posts_per_page'] = abs( $q['posts_per_page'] );
  2037 			$q['posts_per_page'] = abs( $q['posts_per_page'] );
  2008 		} elseif ( 0 == $q['posts_per_page'] ) {
  2038 		} elseif ( 0 === $q['posts_per_page'] ) {
  2009 			$q['posts_per_page'] = 1;
  2039 			$q['posts_per_page'] = 1;
  2010 		}
  2040 		}
  2011 
  2041 
  2012 		if ( ! isset( $q['comments_per_page'] ) || 0 == $q['comments_per_page'] ) {
  2042 		if ( ! isset( $q['comments_per_page'] ) || 0 == $q['comments_per_page'] ) {
  2013 			$q['comments_per_page'] = get_option( 'comments_per_page' );
  2043 			$q['comments_per_page'] = get_option( 'comments_per_page' );
  2035 				$fields = "{$wpdb->posts}.ID";
  2065 				$fields = "{$wpdb->posts}.ID";
  2036 				break;
  2066 				break;
  2037 			case 'id=>parent':
  2067 			case 'id=>parent':
  2038 				$fields = "{$wpdb->posts}.ID, {$wpdb->posts}.post_parent";
  2068 				$fields = "{$wpdb->posts}.ID, {$wpdb->posts}.post_parent";
  2039 				break;
  2069 				break;
       
  2070 			case '':
       
  2071 				/*
       
  2072 				 * Set the default to 'all'.
       
  2073 				 *
       
  2074 				 * This is used in `WP_Query::the_post` to determine if the
       
  2075 				 * entire post object has been queried.
       
  2076 				 */
       
  2077 				$q['fields'] = 'all';
       
  2078 				// Falls through.
  2040 			default:
  2079 			default:
  2041 				$fields = "{$wpdb->posts}.*";
  2080 				$fields = "{$wpdb->posts}.*";
  2042 		}
  2081 		}
  2043 
  2082 
  2044 		if ( '' !== $q['menu_order'] ) {
  2083 		if ( '' !== $q['menu_order'] ) {
  2183 			$q['attachment'] = sanitize_title_for_query( wp_basename( $q['attachment'] ) );
  2222 			$q['attachment'] = sanitize_title_for_query( wp_basename( $q['attachment'] ) );
  2184 			$q['name']       = $q['attachment'];
  2223 			$q['name']       = $q['attachment'];
  2185 			$where          .= " AND {$wpdb->posts}.post_name = '" . $q['attachment'] . "'";
  2224 			$where          .= " AND {$wpdb->posts}.post_name = '" . $q['attachment'] . "'";
  2186 		} elseif ( is_array( $q['post_name__in'] ) && ! empty( $q['post_name__in'] ) ) {
  2225 		} elseif ( is_array( $q['post_name__in'] ) && ! empty( $q['post_name__in'] ) ) {
  2187 			$q['post_name__in'] = array_map( 'sanitize_title_for_query', $q['post_name__in'] );
  2226 			$q['post_name__in'] = array_map( 'sanitize_title_for_query', $q['post_name__in'] );
  2188 			$post_name__in      = "'" . implode( "','", $q['post_name__in'] ) . "'";
  2227 			// Duplicate array before sorting to allow for the orderby clause.
  2189 			$where             .= " AND {$wpdb->posts}.post_name IN ($post_name__in)";
  2228 			$post_name__in_for_where = array_unique( $q['post_name__in'] );
       
  2229 			sort( $post_name__in_for_where );
       
  2230 			$post_name__in = "'" . implode( "','", $post_name__in_for_where ) . "'";
       
  2231 			$where        .= " AND {$wpdb->posts}.post_name IN ($post_name__in)";
  2190 		}
  2232 		}
  2191 
  2233 
  2192 		// If an attachment is requested by number, let it supersede any post number.
  2234 		// If an attachment is requested by number, let it supersede any post number.
  2193 		if ( $q['attachment_id'] ) {
  2235 		if ( $q['attachment_id'] ) {
  2194 			$q['p'] = absint( $q['attachment_id'] );
  2236 			$q['p'] = absint( $q['attachment_id'] );
  2196 
  2238 
  2197 		// If a post number is specified, load that post.
  2239 		// If a post number is specified, load that post.
  2198 		if ( $q['p'] ) {
  2240 		if ( $q['p'] ) {
  2199 			$where .= " AND {$wpdb->posts}.ID = " . $q['p'];
  2241 			$where .= " AND {$wpdb->posts}.ID = " . $q['p'];
  2200 		} elseif ( $q['post__in'] ) {
  2242 		} elseif ( $q['post__in'] ) {
  2201 			$post__in = implode( ',', array_map( 'absint', $q['post__in'] ) );
  2243 			// Duplicate array before sorting to allow for the orderby clause.
       
  2244 			$post__in_for_where = $q['post__in'];
       
  2245 			$post__in_for_where = array_unique( array_map( 'absint', $post__in_for_where ) );
       
  2246 			sort( $post__in_for_where );
       
  2247 			$post__in = implode( ',', array_map( 'absint', $post__in_for_where ) );
  2202 			$where   .= " AND {$wpdb->posts}.ID IN ($post__in)";
  2248 			$where   .= " AND {$wpdb->posts}.ID IN ($post__in)";
  2203 		} elseif ( $q['post__not_in'] ) {
  2249 		} elseif ( $q['post__not_in'] ) {
       
  2250 			sort( $q['post__not_in'] );
  2204 			$post__not_in = implode( ',', array_map( 'absint', $q['post__not_in'] ) );
  2251 			$post__not_in = implode( ',', array_map( 'absint', $q['post__not_in'] ) );
  2205 			$where       .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)";
  2252 			$where       .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)";
  2206 		}
  2253 		}
  2207 
  2254 
  2208 		if ( is_numeric( $q['post_parent'] ) ) {
  2255 		if ( is_numeric( $q['post_parent'] ) ) {
  2209 			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_parent = %d ", $q['post_parent'] );
  2256 			$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_parent = %d ", $q['post_parent'] );
  2210 		} elseif ( $q['post_parent__in'] ) {
  2257 		} elseif ( $q['post_parent__in'] ) {
  2211 			$post_parent__in = implode( ',', array_map( 'absint', $q['post_parent__in'] ) );
  2258 			// Duplicate array before sorting to allow for the orderby clause.
       
  2259 			$post_parent__in_for_where = $q['post_parent__in'];
       
  2260 			$post_parent__in_for_where = array_unique( array_map( 'absint', $post_parent__in_for_where ) );
       
  2261 			sort( $post_parent__in_for_where );
       
  2262 			$post_parent__in = implode( ',', array_map( 'absint', $post_parent__in_for_where ) );
  2212 			$where          .= " AND {$wpdb->posts}.post_parent IN ($post_parent__in)";
  2263 			$where          .= " AND {$wpdb->posts}.post_parent IN ($post_parent__in)";
  2213 		} elseif ( $q['post_parent__not_in'] ) {
  2264 		} elseif ( $q['post_parent__not_in'] ) {
       
  2265 			sort( $q['post_parent__not_in'] );
  2214 			$post_parent__not_in = implode( ',', array_map( 'absint', $q['post_parent__not_in'] ) );
  2266 			$post_parent__not_in = implode( ',', array_map( 'absint', $q['post_parent__not_in'] ) );
  2215 			$where              .= " AND {$wpdb->posts}.post_parent NOT IN ($post_parent__not_in)";
  2267 			$where              .= " AND {$wpdb->posts}.post_parent NOT IN ($post_parent__not_in)";
  2216 		}
  2268 		}
  2217 
  2269 
  2218 		if ( $q['page_id'] ) {
  2270 		if ( $q['page_id'] ) {
  2338 		// Author/user stuff.
  2390 		// Author/user stuff.
  2339 
  2391 
  2340 		if ( ! empty( $q['author'] ) && '0' != $q['author'] ) {
  2392 		if ( ! empty( $q['author'] ) && '0' != $q['author'] ) {
  2341 			$q['author'] = addslashes_gpc( '' . urldecode( $q['author'] ) );
  2393 			$q['author'] = addslashes_gpc( '' . urldecode( $q['author'] ) );
  2342 			$authors     = array_unique( array_map( 'intval', preg_split( '/[,\s]+/', $q['author'] ) ) );
  2394 			$authors     = array_unique( array_map( 'intval', preg_split( '/[,\s]+/', $q['author'] ) ) );
       
  2395 			sort( $authors );
  2343 			foreach ( $authors as $author ) {
  2396 			foreach ( $authors as $author ) {
  2344 				$key         = $author > 0 ? 'author__in' : 'author__not_in';
  2397 				$key         = $author > 0 ? 'author__in' : 'author__not_in';
  2345 				$q[ $key ][] = abs( $author );
  2398 				$q[ $key ][] = abs( $author );
  2346 			}
  2399 			}
  2347 			$q['author'] = implode( ',', $authors );
  2400 			$q['author'] = implode( ',', $authors );
  2348 		}
  2401 		}
  2349 
  2402 
  2350 		if ( ! empty( $q['author__not_in'] ) ) {
  2403 		if ( ! empty( $q['author__not_in'] ) ) {
  2351 			$author__not_in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__not_in'] ) ) );
  2404 			if ( is_array( $q['author__not_in'] ) ) {
       
  2405 				$q['author__not_in'] = array_unique( array_map( 'absint', $q['author__not_in'] ) );
       
  2406 				sort( $q['author__not_in'] );
       
  2407 			}
       
  2408 			$author__not_in = implode( ',', (array) $q['author__not_in'] );
  2352 			$where         .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";
  2409 			$where         .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";
  2353 		} elseif ( ! empty( $q['author__in'] ) ) {
  2410 		} elseif ( ! empty( $q['author__in'] ) ) {
       
  2411 			if ( is_array( $q['author__in'] ) ) {
       
  2412 				$q['author__in'] = array_unique( array_map( 'absint', $q['author__in'] ) );
       
  2413 				sort( $q['author__in'] );
       
  2414 			}
  2354 			$author__in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__in'] ) ) );
  2415 			$author__in = implode( ',', array_map( 'absint', array_unique( (array) $q['author__in'] ) ) );
  2355 			$where     .= " AND {$wpdb->posts}.post_author IN ($author__in) ";
  2416 			$where     .= " AND {$wpdb->posts}.post_author IN ($author__in) ";
  2356 		}
  2417 		}
  2357 
  2418 
  2358 		// Author stuff for nice URLs.
  2419 		// Author stuff for nice URLs.
  2585 			$statuswheres = array();
  2646 			$statuswheres = array();
  2586 			$q_status     = $q['post_status'];
  2647 			$q_status     = $q['post_status'];
  2587 			if ( ! is_array( $q_status ) ) {
  2648 			if ( ! is_array( $q_status ) ) {
  2588 				$q_status = explode( ',', $q_status );
  2649 				$q_status = explode( ',', $q_status );
  2589 			}
  2650 			}
       
  2651 			sort( $q_status );
  2590 			$r_status = array();
  2652 			$r_status = array();
  2591 			$p_status = array();
  2653 			$p_status = array();
  2592 			$e_status = array();
  2654 			$e_status = array();
  2593 			if ( in_array( 'any', $q_status, true ) ) {
  2655 			if ( in_array( 'any', $q_status, true ) ) {
  2594 				foreach ( get_post_stati( array( 'exclude_from_search' => true ) ) as $status ) {
  2656 				foreach ( get_post_stati( array( 'exclude_from_search' => true ) ) as $status ) {
  3292 			}
  3354 			}
  3293 
  3355 
  3294 			return $post_parents;
  3356 			return $post_parents;
  3295 		}
  3357 		}
  3296 
  3358 
  3297 		$is_unfiltered_query = $old_request == $this->request && "{$wpdb->posts}.*" === $fields;
  3359 		$is_unfiltered_query = $old_request === $this->request && "{$wpdb->posts}.*" === $fields;
  3298 
  3360 
  3299 		if ( null === $this->posts ) {
  3361 		if ( null === $this->posts ) {
  3300 			$split_the_query = (
  3362 			$split_the_query = (
  3301 				$is_unfiltered_query
  3363 				$is_unfiltered_query
  3302 				&& (
  3364 				&& (
  3684 	 */
  3746 	 */
  3685 	public function the_post() {
  3747 	public function the_post() {
  3686 		global $post;
  3748 		global $post;
  3687 
  3749 
  3688 		if ( ! $this->in_the_loop ) {
  3750 		if ( ! $this->in_the_loop ) {
  3689 			// Only prime the post cache for queries limited to the ID field.
  3751 			if ( 'all' === $this->query_vars['fields'] ) {
  3690 			$post_ids = array_filter( $this->posts, 'is_numeric' );
  3752 				// Full post objects queried.
  3691 			// Exclude any falsey values, such as 0.
  3753 				$post_objects = $this->posts;
  3692 			$post_ids = array_filter( $post_ids );
  3754 			} else {
  3693 			if ( $post_ids ) {
  3755 				if ( 'ids' === $this->query_vars['fields'] ) {
       
  3756 					// Post IDs queried.
       
  3757 					$post_ids = $this->posts;
       
  3758 				} else {
       
  3759 					// Only partial objects queried, need to prime the cache for the loop.
       
  3760 					$post_ids = array_reduce(
       
  3761 						$this->posts,
       
  3762 						function ( $carry, $post ) {
       
  3763 							if ( isset( $post->ID ) ) {
       
  3764 								$carry[] = $post->ID;
       
  3765 							}
       
  3766 
       
  3767 							return $carry;
       
  3768 						},
       
  3769 						array()
       
  3770 					);
       
  3771 				}
  3694 				_prime_post_caches( $post_ids, $this->query_vars['update_post_term_cache'], $this->query_vars['update_post_meta_cache'] );
  3772 				_prime_post_caches( $post_ids, $this->query_vars['update_post_term_cache'], $this->query_vars['update_post_meta_cache'] );
  3695 			}
  3773 				$post_objects = array_map( 'get_post', $post_ids );
  3696 			$post_objects = array_map( 'get_post', $this->posts );
  3774 			}
  3697 			update_post_author_caches( $post_objects );
  3775 			update_post_author_caches( $post_objects );
  3698 		}
  3776 		}
  3699 
  3777 
  3700 		$this->in_the_loop = true;
  3778 		$this->in_the_loop = true;
  3701 		$this->before_loop = false;
  3779 		$this->before_loop = false;
  3702 
  3780 
  3703 		if ( -1 == $this->current_post ) { // Loop has just started.
  3781 		if ( -1 === $this->current_post ) { // Loop has just started.
  3704 			/**
  3782 			/**
  3705 			 * Fires once the loop is started.
  3783 			 * Fires once the loop is started.
  3706 			 *
  3784 			 *
  3707 			 * @since 2.0.0
  3785 			 * @since 2.0.0
  3708 			 *
  3786 			 *
  3710 			 */
  3788 			 */
  3711 			do_action_ref_array( 'loop_start', array( &$this ) );
  3789 			do_action_ref_array( 'loop_start', array( &$this ) );
  3712 		}
  3790 		}
  3713 
  3791 
  3714 		$post = $this->next_post();
  3792 		$post = $this->next_post();
       
  3793 
       
  3794 		// Ensure a full post object is available.
       
  3795 		if ( 'all' !== $this->query_vars['fields'] ) {
       
  3796 			if ( 'ids' === $this->query_vars['fields'] ) {
       
  3797 				// Post IDs queried.
       
  3798 				$post = get_post( $post );
       
  3799 			} elseif ( isset( $post->ID ) ) {
       
  3800 				/*
       
  3801 				 * Partial objecct queried.
       
  3802 				 *
       
  3803 				 * The post object was queried with a partial set of
       
  3804 				 * fields, populate the entire object for the loop.
       
  3805 				 */
       
  3806 				$post = get_post( $post->ID );
       
  3807 			}
       
  3808 		}
       
  3809 
       
  3810 		// Set up the global post object for the loop.
  3715 		$this->setup_postdata( $post );
  3811 		$this->setup_postdata( $post );
  3716 	}
  3812 	}
  3717 
  3813 
  3718 	/**
  3814 	/**
  3719 	 * Determines whether there are more posts available in the loop.
  3815 	 * Determines whether there are more posts available in the loop.
  3725 	 * @return bool True if posts are available, false if end of the loop.
  3821 	 * @return bool True if posts are available, false if end of the loop.
  3726 	 */
  3822 	 */
  3727 	public function have_posts() {
  3823 	public function have_posts() {
  3728 		if ( $this->current_post + 1 < $this->post_count ) {
  3824 		if ( $this->current_post + 1 < $this->post_count ) {
  3729 			return true;
  3825 			return true;
  3730 		} elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
  3826 		} elseif ( $this->current_post + 1 === $this->post_count && $this->post_count > 0 ) {
  3731 			/**
  3827 			/**
  3732 			 * Fires once the loop has ended.
  3828 			 * Fires once the loop has ended.
  3733 			 *
  3829 			 *
  3734 			 * @since 2.0.0
  3830 			 * @since 2.0.0
  3735 			 *
  3831 			 *
  3736 			 * @param WP_Query $query The WP_Query instance (passed by reference).
  3832 			 * @param WP_Query $query The WP_Query instance (passed by reference).
  3737 			 */
  3833 			 */
  3738 			do_action_ref_array( 'loop_end', array( &$this ) );
  3834 			do_action_ref_array( 'loop_end', array( &$this ) );
       
  3835 
  3739 			// Do some cleaning up after the loop.
  3836 			// Do some cleaning up after the loop.
  3740 			$this->rewind_posts();
  3837 			$this->rewind_posts();
  3741 		} elseif ( 0 === $this->post_count ) {
  3838 		} elseif ( 0 === $this->post_count ) {
  3742 			$this->before_loop = false;
  3839 			$this->before_loop = false;
  3743 
  3840 
  3792 	public function the_comment() {
  3889 	public function the_comment() {
  3793 		global $comment;
  3890 		global $comment;
  3794 
  3891 
  3795 		$comment = $this->next_comment();
  3892 		$comment = $this->next_comment();
  3796 
  3893 
  3797 		if ( 0 == $this->current_comment ) {
  3894 		if ( 0 === $this->current_comment ) {
  3798 			/**
  3895 			/**
  3799 			 * Fires once the comment loop is started.
  3896 			 * Fires once the comment loop is started.
  3800 			 *
  3897 			 *
  3801 			 * @since 2.2.0
  3898 			 * @since 2.2.0
  3802 			 */
  3899 			 */
  3814 	 * @return bool True if comments are available, false if no more comments.
  3911 	 * @return bool True if comments are available, false if no more comments.
  3815 	 */
  3912 	 */
  3816 	public function have_comments() {
  3913 	public function have_comments() {
  3817 		if ( $this->current_comment + 1 < $this->comment_count ) {
  3914 		if ( $this->current_comment + 1 < $this->comment_count ) {
  3818 			return true;
  3915 			return true;
  3819 		} elseif ( $this->current_comment + 1 == $this->comment_count ) {
  3916 		} elseif ( $this->current_comment + 1 === $this->comment_count ) {
  3820 			$this->rewind_comments();
  3917 			$this->rewind_comments();
  3821 		}
  3918 		}
  3822 
  3919 
  3823 		return false;
  3920 		return false;
  3824 	}
  3921 	}
  4009 	 */
  4106 	 */
  4010 	public function __isset( $name ) {
  4107 	public function __isset( $name ) {
  4011 		if ( in_array( $name, $this->compat_fields, true ) ) {
  4108 		if ( in_array( $name, $this->compat_fields, true ) ) {
  4012 			return isset( $this->$name );
  4109 			return isset( $this->$name );
  4013 		}
  4110 		}
       
  4111 
       
  4112 		return false;
  4014 	}
  4113 	}
  4015 
  4114 
  4016 	/**
  4115 	/**
  4017 	 * Makes private/protected methods readable for backward compatibility.
  4116 	 * Makes private/protected methods readable for backward compatibility.
  4018 	 *
  4117 	 *
  4477 		} else {
  4576 		} else {
  4478 			foreach ( $page as $pagepath ) {
  4577 			foreach ( $page as $pagepath ) {
  4479 				if ( ! strpos( $pagepath, '/' ) ) {
  4578 				if ( ! strpos( $pagepath, '/' ) ) {
  4480 					continue;
  4579 					continue;
  4481 				}
  4580 				}
       
  4581 
  4482 				$pagepath_obj = get_page_by_path( $pagepath );
  4582 				$pagepath_obj = get_page_by_path( $pagepath );
  4483 
  4583 
  4484 				if ( $pagepath_obj && ( $pagepath_obj->ID == $page_obj->ID ) ) {
  4584 				if ( $pagepath_obj && ( $pagepath_obj->ID === $page_obj->ID ) ) {
  4485 					return true;
  4585 					return true;
  4486 				}
  4586 				}
  4487 			}
  4587 			}
  4488 		}
  4588 		}
  4489 
  4589 
  4587 		} else {
  4687 		} else {
  4588 			foreach ( $post as $postpath ) {
  4688 			foreach ( $post as $postpath ) {
  4589 				if ( ! strpos( $postpath, '/' ) ) {
  4689 				if ( ! strpos( $postpath, '/' ) ) {
  4590 					continue;
  4690 					continue;
  4591 				}
  4691 				}
       
  4692 
  4592 				$postpath_obj = get_page_by_path( $postpath, OBJECT, $post_obj->post_type );
  4693 				$postpath_obj = get_page_by_path( $postpath, OBJECT, $post_obj->post_type );
  4593 
  4694 
  4594 				if ( $postpath_obj && ( $postpath_obj->ID == $post_obj->ID ) ) {
  4695 				if ( $postpath_obj && ( $postpath_obj->ID === $post_obj->ID ) ) {
  4595 					return true;
  4696 					return true;
  4596 				}
  4697 				}
  4597 			}
  4698 			}
  4598 		}
  4699 		}
  4599 		return false;
  4700 		return false;
  4897 		}
  4998 		}
  4898 		$args['post_type'] = (array) $args['post_type'];
  4999 		$args['post_type'] = (array) $args['post_type'];
  4899 		// Sort post types to ensure same cache key generation.
  5000 		// Sort post types to ensure same cache key generation.
  4900 		sort( $args['post_type'] );
  5001 		sort( $args['post_type'] );
  4901 
  5002 
       
  5003 		/*
       
  5004 		 * Sort arrays that can be used for ordering prior to cache key generation.
       
  5005 		 *
       
  5006 		 * These arrays are sorted in the query generator for the purposes of the
       
  5007 		 * WHERE clause but the arguments are not modified as they can be used for
       
  5008 		 * the orderby clase.
       
  5009 		 *
       
  5010 		 * Their use in the orderby clause will generate a different SQL query so
       
  5011 		 * they can be sorted for the cache key generation.
       
  5012 		 */
       
  5013 		$sortable_arrays_with_int_values = array(
       
  5014 			'post__in',
       
  5015 			'post_parent__in',
       
  5016 		);
       
  5017 		foreach ( $sortable_arrays_with_int_values as $key ) {
       
  5018 			if ( isset( $args[ $key ] ) && is_array( $args[ $key ] ) ) {
       
  5019 				$args[ $key ] = array_unique( array_map( 'absint', $args[ $key ] ) );
       
  5020 				sort( $args[ $key ] );
       
  5021 			}
       
  5022 		}
       
  5023 
       
  5024 		// Sort and unique the 'post_name__in' for cache key generation.
       
  5025 		if ( isset( $args['post_name__in'] ) && is_array( $args['post_name__in'] ) ) {
       
  5026 			$args['post_name__in'] = array_unique( $args['post_name__in'] );
       
  5027 			sort( $args['post_name__in'] );
       
  5028 		}
       
  5029 
  4902 		if ( isset( $args['post_status'] ) ) {
  5030 		if ( isset( $args['post_status'] ) ) {
  4903 			$args['post_status'] = (array) $args['post_status'];
  5031 			$args['post_status'] = (array) $args['post_status'];
  4904 			// Sort post status to ensure same cache key generation.
  5032 			// Sort post status to ensure same cache key generation.
  4905 			sort( $args['post_status'] );
  5033 			sort( $args['post_status'] );
  4906 		}
  5034 		}
  4937 		$last_changed = wp_cache_get_last_changed( 'posts' );
  5065 		$last_changed = wp_cache_get_last_changed( 'posts' );
  4938 		if ( ! empty( $this->tax_query->queries ) ) {
  5066 		if ( ! empty( $this->tax_query->queries ) ) {
  4939 			$last_changed .= wp_cache_get_last_changed( 'terms' );
  5067 			$last_changed .= wp_cache_get_last_changed( 'terms' );
  4940 		}
  5068 		}
  4941 
  5069 
  4942 		return "wp_query:$key:$last_changed";
  5070 		$this->query_cache_key = "wp_query:$key:$last_changed";
       
  5071 		return $this->query_cache_key;
  4943 	}
  5072 	}
  4944 
  5073 
  4945 	/**
  5074 	/**
  4946 	 * After looping through a nested query, this function
  5075 	 * After looping through a nested query, this function
  4947 	 * restores the $post global to the current post in this query.
  5076 	 * restores the $post global to the current post in this query.