: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if ( $this->is_home && $page <= 1 && is_array( $sticky_posts ) && ! empty( $sticky_posts ) && ! $q['ignore_sticky_posts'] ) {
$num_posts = count( $this->posts );
// Loop over posts and relocate stickies to the front.
for ( $i = 0; $i < $num_posts; $i++ ) {
if ( in_array( $this->posts[ $i ]->ID, $sticky_posts, true ) ) {
$sticky_post = $this->posts[ $i ];
// Remove sticky from current position.
array_splice( $this->posts, $i, 1 );
// Move to front, after other stickies.
array_splice( $this->posts, $sticky_offset, 0, array( $sticky_post ) );
// Increment the sticky offset. The next sticky will be placed at this offset.
// Remove post from sticky posts array.
$offset = array_search( $sticky_post->ID, $sticky_posts, true );
unset( $sticky_posts[ $offset ] );
// If any posts have been excluded specifically, Ignore those that are sticky.
if ( ! empty( $sticky_posts ) && ! empty( $q['post__not_in'] ) ) {
$sticky_posts = array_diff( $sticky_posts, $q['post__not_in'] );
// Fetch sticky posts that weren't in the query results.
if ( ! empty( $sticky_posts ) ) {
'post__in' => $sticky_posts,
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => count( $sticky_posts ),
'suppress_filters' => $q['suppress_filters'],
'cache_results' => $q['cache_results'],
'update_post_meta_cache' => $q['update_post_meta_cache'],
'update_post_term_cache' => $q['update_post_term_cache'],
'lazy_load_term_meta' => $q['lazy_load_term_meta'],
foreach ( $stickies as $sticky_post ) {
array_splice( $this->posts, $sticky_offset, 0, array( $sticky_post ) );
if ( ! $q['suppress_filters'] ) {
* Filters the array of retrieved posts after they've been fetched and
* @param WP_Post[] $posts Array of post objects.
* @param WP_Query $query The WP_Query instance (passed by reference).
$this->posts = apply_filters_ref_array( 'the_posts', array( $this->posts, &$this ) );
* Ensure that any posts added/modified via one of the filters above are
* of the type WP_Post and are filtered.
$this->post_count = count( $this->posts );
$this->posts = array_map( 'get_post', $this->posts );
if ( $q['cache_results'] ) {
if ( $is_unfiltered_query && $unfiltered_posts === $this->posts ) {
update_post_caches( $this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache'] );
$post_ids = wp_list_pluck( $this->posts, 'ID' );
_prime_post_caches( $post_ids, $q['update_post_term_cache'], $q['update_post_meta_cache'] );
$this->post = reset( $this->posts );
if ( ! empty( $this->posts ) && $q['update_menu_item_cache'] ) {
update_menu_item_cache( $this->posts );
if ( $q['lazy_load_term_meta'] ) {
wp_queue_posts_for_term_meta_lazyload( $this->posts );
* Sets up the amount of found posts and the number of pages (if limit clause was used)
* @global wpdb $wpdb WordPress database abstraction object.
* @param array $q Query variables.
* @param string $limits LIMIT clauses of the query.
private function set_found_posts( $q, $limits ) {
* Bail if posts is an empty array. Continue if posts is an empty string,
* null, or false to accommodate caching plugins that fill posts later.
if ( $q['no_found_rows'] || ( is_array( $this->posts ) && ! $this->posts ) ) {
if ( ! empty( $limits ) ) {
* Filters the query to run for retrieving the found posts.
* @param string $found_posts_query The query to run to find the found posts.
* @param WP_Query $query The WP_Query instance (passed by reference).
$found_posts_query = apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) );
$this->found_posts = (int) $wpdb->get_var( $found_posts_query );
if ( is_array( $this->posts ) ) {
$this->found_posts = count( $this->posts );
if ( null === $this->posts ) {
* Filters the number of found posts for the query.
* @param int $found_posts The number of posts found.
* @param WP_Query $query The WP_Query instance (passed by reference).
$this->found_posts = (int) apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );
if ( ! empty( $limits ) ) {
$this->max_num_pages = (int) ceil( $this->found_posts / $q['posts_per_page'] );
* Sets up the next post and iterate current post index.
* @return WP_Post Next post.
public function next_post() {
$this->post = $this->posts[ $this->current_post ];
* Sets up the current post.
* Retrieves the next post, sets up the post, sets the 'in the loop'
* @global WP_Post $post Global post object.
public function the_post() {
if ( ! $this->in_the_loop ) {
// Only prime the post cache for queries limited to the ID field.
$post_ids = array_filter( $this->posts, 'is_numeric' );
// Exclude any falsey values, such as 0.
$post_ids = array_filter( $post_ids );
_prime_post_caches( $post_ids, $this->query_vars['update_post_term_cache'], $this->query_vars['update_post_meta_cache'] );
$post_objects = array_map( 'get_post', $this->posts );
update_post_author_caches( $post_objects );
$this->in_the_loop = true;
$this->before_loop = false;
if ( -1 == $this->current_post ) { // Loop has just started.
* Fires once the loop is started.
* @param WP_Query $query The WP_Query instance (passed by reference).
do_action_ref_array( 'loop_start', array( &$this ) );
$post = $this->next_post();
$this->setup_postdata( $post );
* Determines whether there are more posts available in the loop.
* Calls the {@see 'loop_end'} action when the loop is complete.
* @return bool True if posts are available, false if end of the loop.
public function have_posts() {
if ( $this->current_post + 1 < $this->post_count ) {
} elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
* Fires once the loop has ended.
* @param WP_Query $query The WP_Query instance (passed by reference).
do_action_ref_array( 'loop_end', array( &$this ) );
// Do some cleaning up after the loop.
} elseif ( 0 === $this->post_count ) {
$this->before_loop = false;
* Fires if no results are found in a post query.
* @param WP_Query $query The WP_Query instance.
do_action( 'loop_no_results', $this );
$this->in_the_loop = false;
* Rewinds the posts and resets post index.
public function rewind_posts() {
$this->current_post = -1;
if ( $this->post_count > 0 ) {
$this->post = $this->posts[0];
* Iterates current comment index and returns WP_Comment object.
* @return WP_Comment Comment object.
public function next_comment() {
++$this->current_comment;
$this->comment = $this->comments[ $this->current_comment ];
* Sets up the current comment.
* @global WP_Comment $comment Global comment object.
public function the_comment() {
$comment = $this->next_comment();
if ( 0 == $this->current_comment ) {
* Fires once the comment loop is started.
do_action( 'comment_loop_start' );
* Determines whether there are more comments available.
* Automatically rewinds comments when finished.
* @return bool True if comments are available, false if no more comments.
public function have_comments() {
if ( $this->current_comment + 1 < $this->comment_count ) {
} elseif ( $this->current_comment + 1 == $this->comment_count ) {
$this->rewind_comments();
* Rewinds the comments, resets the comment index and comment to first.
public function rewind_comments() {
$this->current_comment = -1;
if ( $this->comment_count > 0 ) {
$this->comment = $this->comments[0];
* Sets up the WordPress query by parsing query string.
* @see WP_Query::parse_query() for all available arguments.
* @param string|array $query URL query string or array of query arguments.
* @return WP_Post[]|int[] Array of post objects or post IDs.
public function query( $query ) {
$this->query = wp_parse_args( $query );
$this->query_vars = $this->query;
return $this->get_posts();
* Retrieves the currently queried object.
* If queried object is not set, then the queried object will be set from
* the category, tag, taxonomy, posts page, single post, page, or author
* query variable. After it is set up, it will be returned.
* @return WP_Term|WP_Post_Type|WP_Post|WP_User|null The queried object.
public function get_queried_object() {
if ( isset( $this->queried_object ) ) {
return $this->queried_object;
$this->queried_object = null;
$this->queried_object_id = null;
if ( $this->is_category || $this->is_tag || $this->is_tax ) {
if ( $this->is_category ) {
$cat = $this->get( 'cat' );
$category_name = $this->get( 'category_name' );
$term = get_term( $cat, 'category' );
} elseif ( $category_name ) {
$term = get_term_by( 'slug', $category_name, 'category' );
} elseif ( $this->is_tag ) {
$tag_id = $this->get( 'tag_id' );
$tag = $this->get( 'tag' );
$term = get_term( $tag_id, 'post_tag' );
$term = get_term_by( 'slug', $tag, 'post_tag' );
// For other tax queries, grab the first term from the first clause.
if ( ! empty( $this->tax_query->queried_terms ) ) {
$queried_taxonomies = array_keys( $this->tax_query->queried_terms );
$matched_taxonomy = reset( $queried_taxonomies );
$query = $this->tax_query->queried_terms[ $matched_taxonomy ];
if ( ! empty( $query['terms'] ) ) {
if ( 'term_id' === $query['field'] ) {
$term = get_term( reset( $query['terms'] ), $matched_taxonomy );
$term = get_term_by( $query['field'], reset( $query['terms'] ), $matched_taxonomy );
if ( ! empty( $term ) && ! is_wp_error( $term ) ) {
$this->queried_object = $term;
$this->queried_object_id = (int) $term->term_id;
if ( $this->is_category && 'category' === $this->queried_object->taxonomy ) {
_make_cat_compat( $this->queried_object );
} elseif ( $this->is_post_type_archive ) {
$post_type = $this->get( 'post_type' );
if ( is_array( $post_type ) ) {
$post_type = reset( $post_type );
$this->queried_object = get_post_type_object( $post_type );
} elseif ( $this->is_posts_page ) {
$page_for_posts = get_option( 'page_for_posts' );
$this->queried_object = get_post( $page_for_posts );
$this->queried_object_id = (int) $this->queried_object->ID;
} elseif ( $this->is_singular && ! empty( $this->post ) ) {
$this->queried_object = $this->post;
$this->queried_object_id = (int) $this->post->ID;
} elseif ( $this->is_author ) {
$author = (int) $this->get( 'author' );
$author_name = $this->get( 'author_name' );
$this->queried_object_id = $author;
} elseif ( $author_name ) {
$user = get_user_by( 'slug', $author_name );
$this->queried_object_id = $user->ID;
$this->queried_object = get_userdata( $this->queried_object_id );
return $this->queried_object;
* Retrieves the ID of the currently queried object.
public function get_queried_object_id() {
$this->get_queried_object();
if ( isset( $this->queried_object_id ) ) {
return $this->queried_object_id;
* Sets up the WordPress query, if parameter is not empty.
* @see WP_Query::parse_query() for all available arguments.
* @param string|array $query URL query string or array of vars.
public function __construct( $query = '' ) {
if ( ! empty( $query ) ) {
* Makes private properties readable for backward compatibility.
* @param string $name Property to get.
* @return mixed Property.
public function __get( $name ) {
if ( in_array( $name, $this->compat_fields, true ) ) {