I have a custom php page and i need to override the global posts variables, but i cant get it to work. When going through the main loop im able to override the global posts, but i cant override whatever have_posts() is using to obtain the count. Im obtaining data from a 3rd party API so i need to build the WP object on the fly and then override the default objects returned from the default query. I have the following code and its working, but the problem is that i get a result that contains the post and then several null objects afterwards.


global $post, $posts, $found_posts, $post_count;

$post->ID = 99999999999;
$post->post_content = "TEST PAGE content";
$post->post_title = "Page Title";
$post->post_name = "test";

$posts = array($post);
$post_count = 1;
$found_posts = 1;

if ( have_posts() ) {
    while ( have_posts() ) {

The above code generates the following output. I need to get rid of the NULLs. To do this i need to make it so have_posts() only returns true once.

object(WP_Post)#2975 (24) { ["ID"]=> int(99999999999) ["post_author"]=> string(1) "1" ["post_date"]=> string(19) "2016-01-21 19:50:24" ["post_date_gmt"]=> string(19) "2016-01-21 19:50:24" ["post_content"]=> string(17) "TEST PAGE content" ["post_title"]=> string(10) "Page Title" ["post_excerpt"]=> string(0) "" ["post_status"]=> string(7) "publish" ["comment_status"]=> string(6) "closed" ["ping_status"]=> string(6) "closed" ["post_password"]=> string(0) "" ["post_name"]=> string(4) "test" ["to_ping"]=> string(0) "" ["pinged"]=> string(0) "" ["post_modified"]=> string(19) "2016-01-21 19:50:24" ["post_modified_gmt"]=> string(19) "2016-01-21 19:50:24" ["post_content_filtered"]=> string(0) "" ["post_parent"]=> int(0) ["guid"]=> string(36) "" ["menu_order"]=> int(0) ["post_type"]=> string(4) "page" ["post_mime_type"]=> string(0) "" ["comment_count"]=> string(1) "0" ["filter"]=> string(3) "raw" } NULL NULL NULL NULL NULL NULL NULL NULL NULL

  • You are just doing it wrong. Don't populate $post by yourself and if your design calls for it then it is probably broken. Commented Jan 22, 2016 at 12:19
  • I'm not calling the wp dB though I can't use wp query as the data comes from a different location Commented Jan 22, 2016 at 13:01
  • As I said, it means you have a bad design. $post is a wordpress API object which have assumed side effects, you are just likely to get into trouble by trying to do all the things that need to be done by yourself Commented Jan 22, 2016 at 13:11

2 Answers 2


It is quite hard to understand what you need to do here, but you need to look at the following

  • Do not use the global variables as local variables, it breaks the global variables and causes issues with the loop. It is also quite hard to debug when you run into issues. The only global variable that should be used as a local variable is when you work with setup_postdata(). setup_postdata() requires the $post global. You just need to remember to reset the $post global afterwards.

  • Use the actions and filters available inside WP_Query to change the result from a specific query object

In general, the $post_count property is calculated from the amount of posts inside $posts. Just before posts are counted, we get the the_posts filter. This allows us to add/remove post objects (or rearrange the post order) from the $posts array. Any alteration here in the amount of posts will result in the `$post_count property being altered

Here is the relevant code from the WP_Query class

if ( ! $q['suppress_filters'] ) {
     * Filter the array of retrieved posts after they've been fetched and
     * internally processed.
     * @since 1.5.0
     * @param array    $posts The array of retrieved posts.
     * @param WP_Query &$this 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.
if ( $this->posts ) {
    $this->post_count = count( $this->posts );
    $this->posts = array_map( 'get_post', $this->posts );
    if ( $q['cache_results'] )
        update_post_caches($this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache']);
    $this->post = reset( $this->posts );
} else {
    $this->post_count = 0;
    $this->posts = array();

If you want to add a post into the array of posts returned, this will be the place to do it

add_filter( 'the_posts', function ( $posts, \WP_Query $q )
    if ( !$q->is_main_query ) // Only target the main query, return if not. Add any additional conditions
        return $posts;

    $post_to_add = [
        // Valid post properties

    $post_to_add = array_map( 'get_post', $post_to_add );

    // Add some checks to make sure our $post_to_inject is a valid.

    // Add $post_to_add in front of $posts array
    $posts = array_merge( $post_to_add, $posts );

    // If you need to replace $posts with your object
    //$posts = [$post_to_add];

    return $posts;
}, 10, 2 );

$post gets set from the first post in the $posts array, so there is also no need to fiddle with that.

As for $found_posts you can make use of the found_posts filter to adjust the amount of posts found

add_filter( 'found_posts', function ( $found_posts, \WP_Query $q )
        if ( !$q->is_main_query ) // Only target the main query, return if not. Add any additional conditions
            return $found_posts;

    $found_posts = 1; // Taken info from your question

    return $found_posts;

As I said, I'm not particulary sure what you need to do, but I hope I did touch the point you are after


I found the solution to this was in the $wp_query variable. By getting the global variable for this and overriding the values within it i was able to have full control over what displayed on the page. This allowed me to generate a WP post object that came from a database outside of wordpress, but didnt have to do anything difficult to make it display.

Here is a full guide that explains how to do it http://yomotherboard.com/how-to-add-a-custom-php-page-to-wordpress-using-a-plugin/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.