3

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>';    
                    endwhile; 

                wp_reset_postdata();
                $wp_query = null;
                $wp_query = $original_query;

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

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

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 Jul 3 '11 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 Jul 3 '11 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 Jul 4 '11 at 1:51
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 Jul 4 '11 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 Jul 4 '11 at 11:24
  • And it is still an issue today. – Adrian Aug 16 '16 at 18:23
3

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>';    
                endwhile; 

            wp_reset_postdata();
  • I was unable to get this to work properly. It would still overwrite the post slug / excerpt (when editing a post). – cale_b Oct 20 '15 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 Oct 21 '15 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"? – cale_b Oct 21 '15 at 14:04
  • You should ask a new question – Tom J Nowell Oct 21 '15 at 22:25
2

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>';    
endforeach;
$post = $tmp_post;
  • Mark your question as answered. – fuxia Feb 14 '12 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 Sep 8 '15 at 12:06
1

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() ) {
            $custom->the_post();
            // ... with access to the data with functions like get_the_ID(), get_the_title(), etc.
        }

        wp_reset_postdata();
    }

    $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 Oct 21 '15 at 6:02
  • @TomJNowell - Good point. I've edited the answer. – cale_b Oct 21 '15 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 Mar 6 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. – cale_b Mar 6 at 14:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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