setup_postdata()WP 1.5.0

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.

Used By: the_post()
1 time — 0.000149 sec (fast) | 50000 times — 5.16 sec (fast)

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

#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.

0

#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
0

#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>
0

#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>
0

#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() 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;
}