4

I've run into a strange problem.

I have a custom loop built with get_posts that works fine when loading the page normally:

<?php
    $rows = get_posts(array(
        'post_type'     => 'drinks', 
        'numberposts'   => -1
    ));
?>

<?php foreach ($rows as $post) : setup_postdata($post) ?>
    <?php the_post_thumbnail() ?>
    <h3><?php the_title() ?></h3>
    <?php the_content() ?>
    <?php the_permalink() ?>
<?php endforeach; wp_reset_postdata() ?>

That code sits inside its own template called "drinks.php".

Now I've set up an AJAX function/URL to fetch this template using jQuery:

add_action('wp_ajax_h5b_get_user_drinks', 'h5b_ajax_get_user_drinks');
add_action('wp_ajax_nopriv_h5b_get_user_drinks', 'h5b_ajax_get_user_drinks');

function h5b_ajax_get_user_drinks () {
    include 'drinks.php';
    die;
}

However, when I fetch it with AJAX it seems that neither the_title(), the_post_thumbnail() or the_permalink() work. the_content() seems to work fine though.

If I var_dump($post) inside my loop it has all the data it should (like title, guid etc).

How can this be?

2 Answers 2

2

Try this:

function h5b_ajax_get_user_drinks() {
    return get_template_part( 'drinks' );

    exit;
}
6
  • I think that would require me to re-structure a lot of things. My drinks.php-file actually sits in themes/my-theme/modules/drinks.php.
    – powerbuoy
    Nov 16, 2012 at 12:52
  • It doesn't matter, you can do it like that: <code>get_teplate_part( 'modules/drinks' )</code>. :) Nov 16, 2012 at 12:53
  • Wow this actually worked! Thanks a lot. One question: Can I pass a variable to the template? When I did my include I could simply set a variable before including but it doesn't work now obviously. Would also love an explanation as to why this works - but not a normal include. Thanks again. Edit: Scratch the variable - I checked if it was an AJAX-request instead using $_SERVER['HTTP_X_REQUESTED_WITH']. Would still love to know what the difference is between get_template_part and a normal include.
    – powerbuoy
    Nov 16, 2012 at 12:56
  • 1
    You're returning before exit...
    – kaiser
    Nov 16, 2012 at 13:19
  • 2
    @powerbuoy, if you are using a child theme get_template_part will pull components from the parent if necessary. include will fail.
    – s_ha_dum
    Nov 16, 2012 at 15:25
5

You need to delcare $post as global, try:

 global $post;
<?php foreach ($rows as $post) : setup_postdata($post) ?>
    <?php the_post_thumbnail() ?>
    <h3><?php the_title() ?></h3>
    <?php the_content() ?>
    <?php the_permalink() ?>
<?php endforeach; wp_reset_postdata() ?>

Most of these functions can only work (and all of them when used without parameters) inside the Loop. What this means is that the global $post points to the appropriate post.

Note: setup_postdata($post) doesn't do this! Hence you need to manually declare global $post.

The accepted answer, which offers perhaps a more aesthetic answer uses get_template_part(), which in turn calls load_template() via (locate_template()). Looking the source - this declares $post variable as a global, from the comments:

The globals are set up for the template file to ensure that the WordPress environment is available from within the function.

Hence it works :).

11
  • I don't think that's the issue. I declare the $post variable myself on each iteration of the loop. TBH I'm not sure it's best practice to create loops like this, but I read it somewhere ages ago and it's always worked for me.
    – powerbuoy
    Nov 16, 2012 at 12:51
  • Would definitely like further explanation as to why this should work.
    – totels
    Nov 16, 2012 at 12:53
  • 1
    @powerbuoy If you follow the paper trail of functions right back to load_template you can see that the difference in a raw include versus the former is substantial. get_template_part (and friends), takes your requested file through an entire process of initialization passing along the KEY global variables needed to access common data and to allow certain API functions to operate correctly, include does not as it knows nothing of its (WP) environment. So you can use an include so long as you provide the necessary globals.
    – Adam
    Nov 16, 2012 at 13:34
  • 1
    @powerbuoy It works without AJAX/global $post because its already in the context of the loop which has already setup and provided the necessary globals. An AJAX function held externally to the loop does not know of the context in which it is required so you need to tell your function, "hey, you need this global, that global, to make this request work". Using get_template_part does this for you, otherwise you need to do it yourself. I do wonder the performance differential versus get_template_part and include, the latter may be more efficient.
    – Adam
    Nov 16, 2012 at 13:36
  • 1
    @powerbuoy - re the_content() working. It seems setup_postdate() sets up the $pages global (stores post content) which get_the_content() uses. Madness. Nov 19, 2012 at 21:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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