Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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?

share|improve this question
add comment

2 Answers

up vote 2 down vote accepted

Try this:

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

    exit;
}
share|improve this answer
    
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 '12 at 12:52
    
It doesn't matter, you can do it like that: <code>get_teplate_part( 'modules/drinks' )</code>. :) –  Mateusz Hajdziony Nov 16 '12 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 '12 at 12:56
1  
You're returning before exit... –  kaiser Nov 16 '12 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 '12 at 15:25
show 1 more comment

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 :).

share|improve this answer
    
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 '12 at 12:51
    
Would definitely like further explanation as to why this should work. –  totels Nov 16 '12 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. –  userabuser Nov 16 '12 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. –  userabuser Nov 16 '12 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. –  Stephen Harris Nov 19 '12 at 21:16
show 6 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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