Where is your code? In a function? Somewhere in a template?
setup_postdata
does not replace the global $post
with the $post
object passed in. It does, however, modify some other globals.
So if you’re trying to use the various the_*
template tags, you need to explicitly replace the global $post
object on which they depend.
In a function, for example…
<?php
function wpse73103_loop_example()
{
global $post; // this is important!
$posts = new WP_Query(/* your args here */);
// because $post is global above, this will
// overwrite the global object.
foreach($posts as $post)
{
setup_postdata($post);
// do stuff
}
wp_reset_postdata(); // back to normal
}
Anyway, the moral of the story is that you should try putting global $post;
before any of the code you posted (which is very much correct).