0

Just learning PHP. Wondering what I'm doing wrong here.

The aim is: if custom field in taxonomy term (in "shows" taxonomy) has data, show posts loop of taxonomy term in a custom post type ("blogs"). The field data has the name of the desired taxonomy term. My code is returning all the posts in the post type instead of my specified term. I was also convinced I limited the post count to 2, but that changed up on me for some reason and it's displaying infinite posts.

<?php
$news = get_field('news', $term);
if ( $news ) {
    ?>
    <h2 class="showhead">News & Upcoming Shows</h2>
    <?php
    $custom_terms = get_terms('show-blogs');
    foreach ( $custom_terms as $custom_term ) {
        wp_reset_query();
        $args = array(
            'post_type' => 'blogs',
            'posts_per_page' => 2,
            'tax_query' => array(
                array(
                    'taxonomy' => 'show-blogs',
                    'field' => $news,
                    'terms' => $custom_term->slug,
                    'posts_per_page' => 2,
                ),
            ),
        );
        $loop = new WP_Query( $args );
        if ( $loop->have_posts() ) {
            while ( $loop->have_posts()) {
                $loop->the_post();
                ?>
                <table style="border:none;border: none;max-width: 50%;float: left;">
                    <tr>
                        <td rowspan="2" style="border:none;width: 113px;">
                            <?php  the_post_thumbnail('thumbnail'); ?>
                        </td>
                        <td style="border:none;height: 45px;">
                            <?php the_title( sprintf( '<h3><a href="%s" rel="bookmark">', esc_url( get_permalink() ) ),'</a></h3>' ); ?>
                        </td>
                    </tr>
                    <tr>       
                        <td style="border:none"><?php the_excerpt();?></td>
                    </tr>
                </table>
                <?php
            }
        }
    }
}

One thing I could do differently to make things easier is just call the "shows" term as it's the same as the "blogs" term which I need.

Any guidance is appreciated.

7
  • Hello! Your code is difficult to read, can you edit your question and add proper indenting? Try to keep so that you only do 1 thing per line too. Also, can you clarify what you meant by "if custom field in taxonomy term"? Is this ACF terminology? ( note that ACF specific support is not in scope on this stack, but it's difficult to tell if this is an ACF question or something else )
    – Tom J Nowell
    Oct 15, 2018 at 1:17
  • Thanks, Tom. I'm new here and can't find an edit button. Oct 15, 2018 at 1:19
  • It's underneath the tags, to the left of the box with your name in
    – Tom J Nowell
    Oct 15, 2018 at 1:19
  • Yes, I used ACF. I presumed WP handles the fields created with it the same as manually-created fields. Oct 15, 2018 at 1:21
  • Mostly, but it treats repeater fields very differently, and how and what it stores in those fields can be ACF specific, so a hefty dose of context is needed. Also ACF 4 is very, very different to ACF 5 ( avoid ACF 4 )
    – Tom J Nowell
    Oct 15, 2018 at 1:25

1 Answer 1

0

So you got a lot of stuff right, and some things wrong, so I'll go through it line by line

First:

    wp_reset_query();

This function cleans up after a query_posts call, you should never use either of them. Sadly, a lot of tutorial writers use this instead of what they intended to use, wp_reset_postdata, as it calls that function internally.

To save time, this is what a well formed WP_Query that cleans up after itself looks like:

$args = array();
$q = new WP_Query( $args );
if ( $q->have_posts() ) { // if posts were found
    while( $q->have_posts() { // for each post
        $q->the_post(); // set the current post
        the_title(); // display its title
        the_content(); // display its content
    }
    // after the loop, reset the current post back to before the loop 
    wp_reset_postdata();
} else {
    // no posts were found
}

Notice that wp_reset_postdata is called after the while loop, but inside the if statement. This way the postdata is only reset if there is work to cleanup.

Second:

Your query arguments are close but not quite right:

    $args = array(
        'post_type' => 'blogs',
        'posts_per_page' => 2,
        'tax_query' => array(
            array(
                'taxonomy' => 'show-blogs',
                'field' => $news,
                'terms' => $custom_term->slug,
                'posts_per_page' => 2,
            ),
        ),
    );
    $loop = new WP_Query( $args );

Notes:

  • field identifies what it is you're searching for. AKA the term withe ID 5, or the term with the slug test, etc, it has a limited number of possible values. The default is term_id, so you should remove this
  • terms is right, but you can make things simpler by passing in the term ID instead, aka 'terms' => $custom_term->term_id,, this might even be a tiny bit faster. Eitherway, always prefer term IDs over term slugs or names, as slugs/names can be edited, but IDs always remain the same
  • The extra posts_per_page doesn't belong in tax_query

Third:

Your code is pulling 2 posts as you wanted, it's just doing it multiple times. Instead of 1 query that's misbehaving, it's multiple queries doing the same thing, but for different terms.

$custom_terms = get_terms('show-blogs');
foreach ( $custom_terms as $custom_term ) {

Lets say that $custom_terms contains 5 terms. That's 5 iterations of the loop, and a query for 2 posts in each loop, so 2 posts x 5 iterations = 10 posts.

We can demonstrate this by modifying the start of

$custom_terms = get_terms('show-blogs');
foreach ( $custom_terms as $custom_term ) {
    ?><h3>Show Blog: <?php echo esc_html( $custom_term->name ); ?></h3><?php

Now we should see each term as a header, followed by 2 posts.

Notable mentions:

  • Congratulations on using esc_url, escaping is a greatly under-appreciated security measure that can do wonders for securing a site. Escape late escape often
  • Some CSS grid should make your table layout much simpler/easier to manage
  • Avoid putting things like } etc on the same line, and indent them, and stick to one style e.g. while () {} rather than while(): endwhile;, it avoids an entire class of mistakes and bugs, and it's much nicer to read and type
1
  • 1
    I feel I would be rude if I didn't directly tell you how appreciative I am of your time and attention. That post was awesome. Oct 16, 2018 at 4:26

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.