Let me try to explain what happened to me :

I have a shortcode plugin which display child pages of the current page (a mod of http://wpist.me/wp/child-pages-shortcode/, very useful).

In the display function, it uses get_posts(), with very basic code, conform to the codex examples (http://codex.wordpress.org/Function_Reference/get_posts) :

global $post;
foreach ($pages as $post) {
    $html = $post->post_title;
    $html .= get_the_excerpt();
    $html .= get_the_content();

With PHP 5.2, it works as expected. I updated to PHP 5.4, and get_the_content() is returning the parent content, instead of the current child. Previous lines are still returning the correct data, but it seems that the first call to a get_the_* function changes the content of the global $post.

It works fine if I use $post->* instead of get_the_*(), but get_the_*() has useful automatic treatment.

I found a way to make it work, so I post it here, so maybe someone can explain me why it's behave like this.

  1. I changed the name of the loop var to avoid messing the global $post (I don't understand why codex example use $post in their loop, by the way…)

  2. I added a setup_postdata call after each get_the_*() calls to reinit the global to the correct post :

working code :

global $post;
foreach ($pages as $mypost) {
    $html = $mypost->post_title;
    $html .= get_the_excerpt();
    $html .= get_the_content();


Edit : the full code of my function (this is working correctly) in case the simplified version confuses you :

private function display($param, $block_template)
global $post;

$html = '';
// defining the content of $template
// cut
// end defining $template

$args = array(
    'post_status' => 'publish',
    'post_type' => 'page',
    'post_parent' => $param['id'],
    'orderby' => 'menu_order',
    'order' => 'ASC',
    'nopaging' => true,
$args = apply_filters('child-pages-shortcode-query', $args, $param);

$pages = get_posts($args);
foreach ($pages as $post2) {
    $post = apply_filters('child_pages_shortcode_post', $post2);
    $url = get_permalink($post2->ID);
    $img = get_the_post_thumbnail($post2->ID, $param['size']);
    $img = preg_replace( '/(width|height)="\d*"\s/', "", $img);
    $tpl = $template;
    $tpl = str_replace('%width%', esc_attr($param['width']), $tpl);
    $tpl = str_replace('%post_id%', intval($post2->ID), $tpl);
    $tpl = str_replace('%post_title%', $post2->post_title, $tpl);
    $tpl = str_replace('%post_subtitle%', get_post_meta($post2->ID, "Sous titre", true), $tpl);
    $tpl = str_replace('%post_url%', esc_url($url), $tpl);
    $tpl = str_replace('%post_thumb%', $img, $tpl);
    if (isset($param['disabled_excerpt_filters']) && $param['disabled_excerpt_filters']) {
        $tpl = str_replace('%post_excerpt%', $post2->post_excerpt, $tpl);
    } else {
        $tpl = str_replace('%post_excerpt%', get_the_excerpt(), $tpl);
    if (isset($param['disabled_excerpt_filters']) && $param['disabled_excerpt_filters']) {
        $tpl = str_replace('%post_content%', $post2->post_content, $tpl);
    } else {
        $tpl = str_replace('%post_content%', get_the_content(), $tpl);
    $html .= $tpl;


if (!$block_template) {
    $html .= '<hr style="border:0px; clear:both;"></div>';

return apply_filters("child-pages-shortcode-output", $html);
  • 2
    you're redefining $html with every operation. Do you mean to be concatenating? $html .= 'something else';
    – GhostToast
    Commented Jan 14, 2014 at 15:04
  • No, it's a very simplified version of my code. You can ignore this.
    – Matthieu
    Commented Jan 14, 2014 at 15:42
  • Seems this has a lot to do with this plugin: WordPress › Child Pages Shortcode « WordPress Plugins -- tried running your code without the shortcode/plugin reference?
    – GhostToast
    Commented Jan 14, 2014 at 16:38

2 Answers 2


With all of the get_the_* flavor of functions, you have the option of passing an ID. Why not do:

$html .= get_the_excerpt($post->ID);

Otherwise it's implying the originating post ID.


You actually need to name var $post for everything to work smoothly. setup_postdata() is not actually setting $post's data, is just uses it for rest of global stuff.

Either you are not showing enough code to see what might be going wrong or get_ function has something hooked inside of it that messes up global.

  • Along these lines, I think it odd that $post is globalized prior to this foreach
    – GhostToast
    Commented Jan 14, 2014 at 16:16
  • Me too. But it's in the third example of the codex : codex.wordpress.org/Function_Reference/get_posts
    – Matthieu
    Commented Jan 14, 2014 at 16:28
  • I can't make it work by using $post in the loop. But it works fine with $mypost.
    – Matthieu
    Commented Jan 14, 2014 at 16:29
  • Globalized $post is correct for custom loop. If this is going wrong it's due to something not part of code displayed.
    – Rarst
    Commented Jan 14, 2014 at 16:33
  • I don't have the time to made a simple test case, but I'm pretty sure that it doesn't work in PHP 5.4 when using $post in the loop. It looks like a change in the context behavior of PHP...
    – Matthieu
    Commented Jan 14, 2014 at 16:43

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.