setup_postdata()
Sets up all urgent data of the post (except global $post variable).
Fills in the global variables that are needed for some Template Tags that are used inside WordPress Loop to work correctly. Some of these template tags are: the_author(), wp_link_pages(), the_weekday_date(), is_new_day().
Sets the following global variables:
$id $authordata $currentday $currentmonth $page $pages $multipage $more $numpages
The function does not set the $post variable as global. So you have to do this yourself. Failure to do so will cause problems with any hooks that use any of the above globals in conjunction with the $post global, as they will refer to separate entities.
The function expects the passed variable to have the same object as the global $post. That is, the passed variable must be a global $post object. If the function is used inside a loop, you have to pass the current post object in the loop.
When this function is used, we always need to flush the post data with wp_reset_postdata() after The Loop.
See the_post() function - it works based on this function.
No Hooks.
Return
true|false
. True when finished.
Usage
global $post; setup_postdata( $post );
- $post(WP_Post|object|int) (required)
- WP_Post instance or Post ID/object.
Examples
#1 Another example to explain setup_postdata()
This example is taken from a user comment:
Question:
Greetings! I think I'm missing something:
1) Such a code:
$top_posts = get_posts([ 'posts_per_page' => 5, ]); if ( $top_posts ) { foreach ( $top_posts as $post ) { // setup_postdata($post); the_title(); echo '<hr>'; } } wp_reset_postdata();
It works fine, it outputs what you need. Why use setup_postdata($post);?
2) Such a code:
$top_posts = get_posts([ 'posts_per_page' => 5, ]); if ( $top_posts ) { foreach ($top_posts as $item) { setup_postdata($item); the_title(); echo '<hr>'; } } wp_reset_postdata();
Outputs 5 times the title of the first post. Here I don't understand why at all? Is the name of $post variable mandatory when looping?
Answer:
1 code
In the description setup_postdata(), it says what it is for:
Fills global variables: $id, $authordata, $currentday, $currentmonth, $page, $pages, $multipage, $more, $numpages. They are needed for the correct operation of the Template Tags, which must be used within the WordPress Loop.
I.e. without it some tags of the template will not work properly! For the_title() it is not needed...
2 code
the_title() and similar ones work exactly with $post, by specifying $post for foreach you sort of change the global $post value to the current, but if you specify $item, no override occurs, so 5 identical headers...
setup_postdata() does not appear in this question, it has another task: to define other global variables besides $post needed for the template tags. For example, you could write it like this:
... foreach ($top_posts as $item) { $post = $item; // rewrite the glob. `$post` setup_postdata($item); the_title(); echo '<hr>'; } ...
And from this code you can see that it's easier to use $post...
Also, you don't have $post defined as global in your code, which means that your code is in some file directly (i.e. it is in the global scope of PHP) and therefore $post is already global there. So for example, if you wrap your code in a function, you would have to write global $post
at the beginning of the function so that $post is global when used inside the function (in the local scope of the code). Otherwise template tags like the_title() will not work properly.
#2 How to pass the $post argument correctly
Let's say we get the post data into the $post_object variable, then we need to create a variable called $post and pass that data into it. setup_postdata() works only with the global variable $post.
global $post; // Pass the received post data to the $post variable and not to any other. $post = $post_object; setup_postdata( $post ); // the_title(); // the_permalink();
A short record of the example above:
setup_postdata( $GLOBALS['post'] = & $post_object );
And here is a wrong variant:
global $post; setup_postdata( $post_object ); // bad
#3 An example with get_posts() loop
Get posts from category 1 and display them as links:
<ul> <?php global $post; $myposts = get_posts( array( 'numberposts' => 5, 'offset'=> 1, 'category' => 1 ) ); foreach( $myposts as $post ){ setup_postdata($post); ?> <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li> <?php } wp_reset_postdata(); // important ?> </ul>
#4 Get posts directly from the database
<ul> <?php global $wpdb, $post; $result = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish'" ); foreach( $result as $post ){ setup_postdata( $post ); ?> <li><a href="<?php the_permalink()?>"><?php the_title();?></a></li> <?php } wp_reset_postdata(); // important ?> </ul>
#5 If not $post variable passed to the function argument
Demonstration of what happens if you pass not the global variable $post as an argument, but any other - the function will not work as it expected.
Let's pass $pst, but not $post:
global $post; $posts = get_posts( "posts_per_page=2" ); foreach( $posts as $pst ){ setup_postdata( $pst ); echo the_title(); echo '<br>'; } echo '$post->post_title - '. $post->post_title . '<br>'; /* Display: current global post title current global post title $post->post_title - current global post title */
Now lets pass normal $post:
// repeat only with $post instead of $pst $posts = get_posts( "posts_per_page=2" ); foreach( $posts as $post ){ setup_postdata( $post ); echo the_title(); echo '<br>'; } echo '$post->post_title - '. $post->post_title . '<br>'; /* Display: Received first post title Received second post title $post->post_title - Received second post title */
Notes
- Global. WP_Query. $wp_query WordPress Query object.
Changelog
Since 1.5.0 | Introduced. |
Since 4.4.0 | Added the ability to pass a post ID to $post. |
setup_postdata() setup postdata code WP 6.1.1
function setup_postdata( $post ) { global $wp_query; if ( ! empty( $wp_query ) && $wp_query instanceof WP_Query ) { return $wp_query->setup_postdata( $post ); } return false; }