I have the following issue:

I am creating a custom-meta-box for the user to add custom fields in a friendly way.
I want to generate a drop-down box with all posts that fall under category 10.
I have created a loop inside the functions file for retrieving the posts I want and to create a dropdown select list.

So when I go to admin -> posts and select a post to edit, I get the following issue:
the last post will load no matter which one I select.

Here is the code used inside the functions file and then called when generating the html code for the custom meta-box:

function get_project_ids($proj_cat = 10) {

$output = '';

$catt = get_categories('parent='.$proj_cat.'&hide_empty=0');

    foreach ($catt as $c) :

        $output .= '<optgroup label="'.$c->name.'">';
        $d = get_categories('parent='.$c->cat_ID.'&hide_empty=0');

            foreach ($d as $e) :
            $output .= '<optgroup label="'.$e->name.'">';

                $args = array( 'nopaging' => true, 'cat' => $e->cat_ID );
                $project_query = new WP_Query( $args );

                    while ( $wp_query->have_posts() ) : $wp_query->the_post();
                        $project_id = (get_post_meta($post->ID, 'project_code', true) != "")?get_post_meta($post->ID, 'project_code', true):"";
                        $output .= '<option value="'.$post->ID.'">'.$project_id.'-'.get_the_title().'</option>';    

                $wp_query = null;
                $wp_query = $original_query;

            $output .= '</optgroup> <!-- END level-b -->';

        $output .= '</optgroup> <!-- END level-a -->';

return $output;
  • Where does $e come from? Second: Where's the original $output you're .= adding too? Third: Why are you setting $wp_query to null? No reason to do that.
    – kaiser
    Commented Jul 3, 2011 at 21:28
  • ok you're right I should be more clear. (i) $e comes from a foreach loop and is the id of the category (ii) $output is initialized a few lines back. (iii) I'm actually following an example from codex where the original wp query is temporary put aside. ... The thing is that this query for some reason forces the same post in the admin edit post page.
    – ion
    Commented Jul 3, 2011 at 23:44
  • Could you please simply post your whole code? And then add the information to your Q? Hint: You can edit your Q. Hint #2: You have a "help" link for commenting and such that will you show you the mark-up stuff like code in comments and else. Thanks.
    – kaiser
    Commented Jul 4, 2011 at 1:51

4 Answers 4


I am not sure about the issue, but my advice would be to try and refactor this to use get_posts() and template tags that can work without $post global variable. Basically do not touch globals at all.

Loops in front-end are almost civilized nowadays, but internals of admin are still very wild. :)

  • Great man!!!! It worked ... I will edit my original post with the working code
    – ion
    Commented Jul 4, 2011 at 11:11
  • @ion it is more proper to add working solutions as new answer (even for own question), that is how site is supposed to work
    – Rarst
    Commented Jul 4, 2011 at 11:24
  • And it is still an issue today.
    – Adrian
    Commented Aug 16, 2016 at 18:23

You're creating a new query, called $project_query, then never using it.

Then you're using $wp_query, for which there is no global $wp_query; statement.

Then you're assigning null to $wp_query then assigning the value of an undefined variable to it.

Instead remove the two unnecessary lines and use $project_query instead. here's the modified query loop:

            $args = array( 'nopaging' => true, 'cat' => $e->cat_ID );
            $project_query = new WP_Query( $args );

                while ( $project_query ->have_posts() ) : $project_query ->the_post();
                    $project_id = (get_post_meta($post->ID, 'project_code', true) != "")?get_post_meta($post->ID, 'project_code', true):"";
                    $output .= '<option value="'.$post->ID.'">'.$project_id.'-'.get_the_title().'</option>';    

  • I was unable to get this to work properly. It would still overwrite the post slug / excerpt (when editing a post). Commented Oct 20, 2015 at 19:54
  • That's an entirely new and separate problem, you shouldn't be setting input names that clash with ones already used by core
    – Tom J Nowell
    Commented Oct 21, 2015 at 6:03
  • how is that a separate problem? And can you help me see / understand what I'm doing to "set input names that clash with ones used by core"? Commented Oct 21, 2015 at 14:04
  • You should ask a new question
    – Tom J Nowell
    Commented Oct 21, 2015 at 22:25

This is the working code:

global $post;
$tmp_post = $post;
$args = array( 'numberposts' => 10000, 'category' => $e->cat_ID );
$myposts = get_posts( $args );
foreach( $myposts as $post ) : setup_postdata($post);
    $project_id = (get_post_meta($post->ID, 'project_code', true) != "")?get_post_meta($post->ID, 'project_code', true):"";
    $output .= '<option value="'.$post->ID.'">'.$project_id.'-'.get_the_title().'</option>';    
$post = $tmp_post;
  • Mark your question as answered.
    – fuxia
    Commented Feb 14, 2012 at 11:52
  • Can someone advise why $tmp_post = $post; is being added before the foreach statement and $post = $tmp_post; is being added after it. Without this it doesn't work and I am not advanced enough to figure out why this is being done and how it is solving things :)
    – Matt Royal
    Commented Sep 8, 2015 at 12:06

Found this question, reviewed the answers, but had to do a combination because I wanted to use the WP_Query, AND was still having issues in the admin dashboard.

This code works properly for me in a metabox when editing posts:

function custom_metabox() {
    global $post;
    $temp_post = $post;

    $args = array(
        'post_type'  => 'custom_post_type',
        'meta_key'   => '_custom_meta_key',
        'meta_value' => TRUE

    $custom = new WP_Query( $args );

    if ( $custom->have_posts() ) {
        while ( $custom->have_posts() ) {
            // ... with access to the data with functions like get_the_ID(), get_the_title(), etc.


    $post = $temp_post;

    // ... the rest of my metabox ...

NOTE: Without the global $post, $temp_post = $post and $post = $temp_post, I was still having issues with the slug and the excerpt getting overwritten. By adding those bits of code, this seems to be working solidly now.

  • 1
    This is the purpose of the wp_reset_postdata call, you should call it inside the if statement so that it only resets the post data when necessary. Your current code resets the postdata even when it hasn't changed
    – Tom J Nowell
    Commented Oct 21, 2015 at 6:02
  • @TomJNowell - Good point. I've edited the answer. Commented Oct 21, 2015 at 14:01
  • Thanks. Spent hours searching for a solution to this problem. This solved it, though I would like to hear why do we have to manually reassign the $post object. And if the function does not have access to $post object, in that case, the $custom->reset_postdata() should work fine, but it did not in my case..
    – Paras Shah
    Commented Mar 6, 2019 at 5:33
  • @ParasShah - you are probably right. I authored that answer over 3 years ago, when my WP skills were not as good. I haven't investigated / tested, but would be open to edits to the answer if in fact storing and resetting $post proves to not be necessary. Commented Mar 6, 2019 at 14:39

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.