0

We have a most recent block where we query a taxonomy for a custom post type and posts from two custom post types. This we do using this code

Full Code

<?php
/**
 * Highlights block
 *
**/
// Create id attribute allowing for custom "anchor" value.
$id = 'highlights-' . $block['id'];
if( !empty($block['anchor']) ) {
    $id = $block['anchor'];
}

// Create class attribute allowing for custom "className" and "align" values.
$className = 'block-highlights ';
if( !empty($block['className']) ) {
    $className .= ' ' . $block['className'];
}
if( !empty($block['align']) ) {
    $className .= ' align' . $block['align'];
}

$taxonomy = 'molecules_of_the_month';
$parent_args = [
    'taxonomy'      => $taxonomy,
    'parent'        => 0,
    'hide_empty'    => false,
    'number'        => 1,
    'fields'        => 'ids',
];
//get the first parent year
$parent_terms = get_terms( $parent_args );
//print_r($parent_terms);

$child_args = [
    'taxonomy'      => $taxonomy,
    'parent'        => $parent_terms[0],
    'hide_empty'    => false,
    'number'        => 1,
    'fields'        => 'ids',
];
//get the children
$child_terms = get_terms( $child_args );
//print_r($child_terms);


//setup the queries getting only ids
$query1 = new WP_Query(array('fields' => 'ids', 'post_type' => 'molecule', 'posts_per_page' => 2 ));
$query2 = new WP_Query(array('fields' => 'ids', 'post_type' => 'resource', 'posts_per_page' => 2));
$query3 = new WP_Query(array('fields' => 'ids', 'posts_per_page' => 3 ));


//now you got post IDs in $query->posts
$merged_ids = array_merge($query1->posts, $query2->posts, $query3->posts);

//new query, using post__in parameter
$highlights = new WP_Query(array('post__in' => $merged_ids, 'post_type' => array('post', 'molecule', 'resource') ));

?>

<div id="<?php echo esc_attr($id); ?>" class="<?php echo esc_attr($className); ?>">
<?php if($highlights): ?>
<div class="slider mobile-slider splide" data-splide='{ "type" : "loop", "perPage": "3", "arrows": 0, "breakpoints": { "99999": { "destroy": 1 }, "767": { "perPage": "1" } } }'>
      <div class="splide__track">
<ul class="post-grid splide__list">
    <?php
    //output MOTM
    if($child_terms):
    foreach ( $child_terms as $child_term ) {
        //get term object
        $term = get_term_by( 'id', $child_term, $taxonomy ); 
        //print_r($term);
    ?>
    <li class="post-grid-post splide__slide">
        <a href="<?php echo get_term_link($term); ?>">
            <?php 
            //get featured image
            $featured_image = get_field('tax_featured_image', $term);
            if( $featured_image ) {               
            ?>
            <figure class="post-featured-image">
                <?php  echo wp_get_attachment_image( $featured_image, 'full' ); ?>
            </figure>
            <?php
            }
            ?>
            <ul class="cat-pill-list">
                <li class="cat-pill" style="background: #38E8AD;">
                    Molecules of the Month
                </li>
            </ul>
            <h2 class="post-grid-title"><?php echo $term->name; ?></h2>
    <?php
        $description = get_term_meta( $child_term, 'intro_text', true );
        
        if($description){
        ?>
        <p> <?php echo wp_trim_words($description, 19); ?></p>
        <?php
        }else{
                echo wp_trim_words(term_description($term), 19 ); 
        }
    ?>
            <p class="reading-time"><?php echo dh_display_read_time(); ?></p>
        </a>
    </li>
    <?php
    }
    endif;
    ?>
<?php while( $highlights->have_posts() ) : $highlights->the_post(); ?>
<!-- Post Content goes here -->
    <li class="post-grid-post splide__slide">
        
        <a href="<?php the_permalink(); ?>">
            <figure class="post-featured-image"><?php the_post_thumbnail(); ?></figure>
            <?php
           $post_id = get_the_ID();
            if ( get_post_type( $post_id ) == 'resource' ) {
                $cats = get_the_terms( $post_id, 'resource_category');
                if($cats):
        ?>
        <ul class="cat-pill-list">
        <?php
                foreach ( $cats as $cat):
                    
                    $category_color = get_field('category_color', $cat);
                    $cat_text_color = get_field('cat_text_color', $cat);
        ?>
            <li class="cat-pill <?php echo $cat_text_color; ?>" style="background: <?php echo $category_color; ?>;">
                <?php echo $cat->name; ?>
            </li>
        <?php
                endforeach;
        ?>
        </ul>
        <?php
                endif;
            }elseif( get_post_type( $post_id ) == 'molecule' ){
        ?>
            <ul class="cat-pill-list">
                <li class="cat-pill" style="background: #38E8AD;">
                    Molecules of the Month
                </li>
            </ul>
        <?php        
            }else{
        ?>
            <ul class="cat-pill-list">
                <li class="cat-pill light" style="background: #EB546B">
                    Article
                </li>
            </ul>
        <?php        
            }
        ?>
            <h2 class="post-grid-title"><?php the_title(); ?></h2>
            <?php echo dh_excerpt(); ?>
            <p class="reading-time"><?php echo dh_display_read_time(); ?></p>
        </a>
    </li>

<?php endwhile; wp_reset_postdata();?>
</ul>
      </div>
</div>
<?php endif; ?>
</div>

But we want to mix $hightlights and filter the taxonomy, two custom post types by most recent, not do these three separately in their own content boxes by date.

We could add an ACF date picker field so we can sort taxonomies by a chosen date

'meta_key' => 'month_date', // name of custom field
'orderby' => 'meta_value_num',
'order' => 'ASC',

but that is only the start.

Clarifications

Child terms are the months which are parents of years. Each child term has a number of custom post type posts (molecules).

$highlights should show a most recent block with a mix of articles (posts), resources (custom post type posts) and child terms or molecules of the month and all in chronological order. A most recent block basically showing the latest resource articles, general articles and child therms and two of each. Currently we always get child terms first and then the content posts. And we want them to truly be mixed and loading in ascending order.

Question

How can we do this? How do you use this merged array and then query the latest two of each and mix them all up and sort ascending (latest first)?

Example

Ascending Order:

  1. molecule 31/03/2022 (cpt)
  2. molecule of the month March 2022 (child term of year 2022)
  3. resource 28/03/2022 (cpt)
  4. resource 27/03/2022 (cpt)
  5. article 26/03/2022 (post)
  6. molecule of the month February 2022 (child term of year 2022)
  7. article 20/03/2022 (post)
15
  • Perhaps I have misunderstood the issue - but you can pass multiple conditions to query arguments like post types to a query 'post_type' => array( 'molecule', 'resource' ), See WP_Query Codex Then just sort by date ascending
    – Bysander
    Commented Mar 28, 2022 at 13:20
  • @rhand can you elaborate on the "mix $hightlights and filter the taxonomy"? Because if you want the query to always query for 2 posts from each CPT, then your code is already doing that. So maybe you can add the full code you're using and a screenshot of the current "content boxes" (or output) and a mockup of the output you're hoping to have?
    – Sally CJ
    Commented Mar 29, 2022 at 0:42
  • 1
    Thanks @rhand. And actually, if only you provided that "Example" when I asked for a mockup, you might have already received an answer 2 days ago.. ✌ Anyway, I bet Mort1305 would be able to update his code, so let's wait for that 🙂
    – Sally CJ
    Commented Mar 31, 2022 at 2:07
  • 1
    I'm glad to hear you guys got it resolved, @Mort1305 (and actually, I was happy because I no longer needed to write an answer 😜✌) Cheers!
    – Sally CJ
    Commented Mar 31, 2022 at 8:18
  • 1
    Yes, well, this is more of a "can you bait my hook, cast my pole, jig it, reel in the fish, clean it, cook it, and serve it to me" kind of thing rather than a "can you point me to the nearest bait store" type of question.
    – Mort 1305
    Commented Mar 31, 2022 at 8:41

1 Answer 1

1
+100

There's way too much information in this, so much so that it's difficult to understand your question. First, I'd like to state my understanding of what I think you are asking.

You have a hierarchical taxonomy molecules_of_the_month and 3 post types the build-in post, a CPT molecule, and a CPT resource. What I think you want is an array containing one WP_Term object followed by several WP_Post objects: the taxonomy object is the most recent category (i.e. parent=2022, child=April); those post objects would contain the two most recent molecules, 2 most recent resources, and 3 most recent posts; and those post objects would be sorted by date. The items of the array are then displayed in blocks.

With that understanding, I'd like to demonstrate the answer by using code:

/**
 *  First, let's compile an array of the things we want to display.  The
 *  posts are the easy part, so let's do those first.
 */
$mort = array();
// Go thru the post types and the number of them we want.  Can change these numbers to get more/less of each post type.
foreach(array(
    'post'      => 3,
    'molecule'  => 3,
    'resource'  => 3,
) as $post_type => $numberposts) {
    // Get the `n` most recent posts of each type.
    foreach(get_posts(array(
        // By default, returns published posts descend sorted by date.
        'numberposts'   => $numberposts,
        'post_type'     => $post_type,
    )) as $p) {
        // Save date as key so we can easily sort later.
        $mort[date('Y-m-d', get_post_datetime($p, 'date', 'gmt')->getTimestamp()).'-0'] = $p;
    }
}

/**
 *  Time to query taxonomies.  We have to look at the name of the term because the
 *  user might assign "January" and "1981" to a "molecule" post dated 15 October 2021
 *  with the intention it be a molecule of the month in Jan '81.
 */
foreach($mort as $p) {
    // Grab the post's molecules_of_the_month terms
    $terms = get_the_terms($p, 'molecules_of_the_month');
    // Check is required as might be FALSE or WP_Error.
    if(is_array($terms)) {
        // Look at all the terms (could be empty if a 'resource' or
        // 'post' in which case this foreach-block will not execute).
        foreach($terms as $term) {
            if(!empty($term->parent)) {
            // We found a month MOTM term.  The post might have a publish date in
            // a different month, so it is necessary to generate a key for sorting
            // from the term itself.
            $date_str = '1 '. $term->name .' '. get_term($term->parent, $term->taxonomy)->name;
            $date_str = date('Y-m-t', strtotime($date_str));
            $mort[$date_str.'-1'] = $term;
            }
        }
    }
}

/**
 *  All done adding stuff to the array.  It's now time to sort this big pile
 *  of goop.  As we saved each object in a key having a specially formatted
 *  date, all we need to do is sort by that key.  We want the most recently
 *  dated object to be at index=0, so we key sort decending.
 *
 *  A word on our date keys:  they are in YYYY-MM-DD format.  Also, notice
 *  the -0 and -1 appended to the end of the date (0 for posts, 1 for terms)?
 *  That's so taxonomies are sorted closer to index=0 than posts.  (Rather have
 *  posts be given priority:  change -0 suffix to -1 on line 21; change
 *  -1 suffix to -0 on line 43; and change the "Y-m-t" to "Y-m-01" on line 43.
 */
krsort($mort);

/**
 *  Now that we have our array of data, its time to display.  For
 *  simplicity, let's create two functions for HTML output:  one to
 *  output a term; and another to output a post.
 */
if(!function_exists('mort_output_term_block')) { // Protection
function mort_output_term_block($term) {
    ?><a href="<?php echo get_term_link($term); ?>"><?php 
        //get featured image
        $featured_image = get_field('tax_featured_image', $term);
        if($featured_image) {
            ?><figure class="post-featured-image">
                <?php echo wp_get_attachment_image($featured_image, 'full'); ?>
            </figure><?php
        }
        ?><ul class="cat-pill-list">
            <li class="cat-pill" style="background: #38E8AD;">
                <?php _e('Molecules of the Month') ?>
            </li>
        </ul>
        <h2 class="post-grid-title"><?php echo $term->name; ?></h2>
        <?php
        $description = get_term_meta( $term, 'intro_text', true );
        if($description) {
            ?><p><?php echo wp_trim_words($description, 19); ?></p><?php
        } else {
            echo wp_trim_words(term_description($term), 19);
        }
        ?><p class="reading-time"><?php echo dh_display_read_time(); ?></p>
    </a><?php
}}
if(!function_exists('mort_output_post_block')) { // Protection
function mort_output_post_block($_post) {
    // Set the global post so we don't have to pass it to all of the
    // template functions.  Also, remember the old global post so we can
    // restored it when we're done with the output of this block.
    global $post;
    $post_saved = $post;
    $post = $_post;
    ?><a href="<?php the_permalink(); ?>">
        <figure class="post-featured-image">
            <?php the_post_thumbnail(); ?>
        </figure><?php
        switch(get_post_type($post)) {
            case 'resource':
                $cats = get_the_terms($post, 'resource_category');
                if($cats) {
                    ?><ul class="cat-pill-list"><?php
                    foreach($cats as $cat) {
                        $text_color = get_field('cat_text_color', $cat);
                        $cat_color = get_field('category_color', $cat);
                        ?><li class="cat-pill <?php echo $text_color; ?>" style="background: <?php echo $cat_color; ?>;">
                            <?php echo $cat->name; ?>
                        </li><?php
                    }
                    ?></ul><?php
                }
                break;
            case 'molecule':
                ?><ul class="cat-pill-list">
                    <li class="cat-pill" style="background: #38E8AD;">
                        <?php _e('Molecules of the Month'); ?>
                    </li>
                </ul><?php
                break;
            default:
                ?><ul class="cat-pill-list">
                    <li class="cat-pill light" style="background: #EB546B">
                        <?php _e('Article'); ?>
                    </li>
                </ul><?php        
        }
        ?><h2 class="post-grid-title"><?php the_title(); ?></h2>
        <?php echo dh_excerpt(); ?>
        <p class="reading-time"><?php echo dh_display_read_time(); ?></p>
    </a><?php
    // Restore the global post
    $post = $post_saved;
}}

/**
 *  Now that we're all setup, it's finally time for the big show!  Let's
 *  display the blocks!
 */
// Create id attribute allowing for custom "anchor" value.
$id = 'highlights-' . $block['id'];
if( !empty($block['anchor']) ) {
    $id = $block['anchor'];
}
// Create class attribute allowing for custom "className" and "align" values.
$className = 'block-highlights ';
if( !empty($block['className']) ) {
    $className .= ' ' . $block['className'];
}
if( !empty($block['align']) ) {
    $className .= ' align' . $block['align'];
}
?><div id="<?php echo esc_attr($id); ?>" class="<?php echo esc_attr($className); ?>"><?php
if($mort) {
    ?><div class="slider mobile-slider splide" data-splide='{ "type" : "loop", "perPage": "3", "arrows": 0, "breakpoints": { "99999": { "destroy": 1 }, "767": { "perPage": "1" } } }'>
        <div class="splide__track">
            <ul class="post-grid splide__list">
            <?php
            foreach($mort as $display_me) {
                ?><li class="post-grid-post splide__slide"><?php
                // Each object is displayed depending on what it is.
                switch(get_class($display_me)) {
                    // It's a term!
                    case 'WP_Term':
                        mort_output_term_block($display_me);
                        break;
                    // It's a post!
                    case 'WP_Post':
                    default:
                        mort_output_post_block($display_me);
                }
                ?></li><?php
            }
            ?></ul>
        </div>
    </div><?php
}
?></div>

The only lingering question in my mind is how your child taxonomy is sorted by month. I just used the arguments you provided. But on the surface, without the use of any filters, it seems as though the child taxonomy won't be sorted as expected. Instead, if the name of the month as saved as the taxonomy name, the get_terms() of the child taxonomy will return the first element in the array [ "April", "August", "December", "February", "January", "July", "June", "March", "May", "November", "October", "September" ], which, in this case, is always "April". If you're having a problem like this, I can solve it if you provide more information about how the taxonomy of children is structured (i.e.: what is saved as name and slug; is there any sort of term metadata that identifies the month as a number; etc) and on what it is applied (in example, the molecules_of_the_month taxonomy is only applied to molecule CPTs, and you want the WP_Term object to be displayed of the most recent molecule post). I have an idea on what to do, but am unable to propose an answer without more info.

UPDATE (3/31) Thank you so much to @rhand for introducing me to the chat function and teaching me a bit about GitHub so I can fork some code. The code was updated there to reflect the discussions we had in chat where we resolved issues. After completion, the code was copied in its entirety above.

10
  • Thanks for this @mort-1305 . Could not make it work yet as I had errors. I updated the question. I removed the code snippets and left full block code. I also added example recent block which I hope will help. As for ordering terms see gist.github.com/jasperf/ace2dd906187d8eaa2074a736436cb29 . We order by term id on archive and page template and that will not work here as we need a date.
    – rhand
    Commented Mar 31, 2022 at 2:17
  • This code gist.github.com/jasperf/abefe3f40ae26ceb9fecdd3b651e2970 now partly works. Only no months loading as var $child_term now loads nothing as it is not defined yet and still need to deal with loading/adding date for child term mom. Well, and need to check order based on example added to question now. And three rows of three would be nicer for desktop view.
    – rhand
    Commented Mar 31, 2022 at 3:37
  • @rhand -- In re this code, lines 6-19 should likely be moved to between lines 187-188 for coding clarity: I updated my code to reflect this. Great job updating the question, it's a little clearer. Let's do one thing at a time. First, your code limits the number of post_types (see $query1, $query2, $query3), but the example list provided does not. Do you want to limit the number of each post_types that appear or do you want to get the most recent posts of any of these 3 post_types?
    – Mort 1305
    Commented Mar 31, 2022 at 4:40
  • More notes in re this code. I've joined GitHub so I can help you edit the code. Also, I have a coding error in my answer in re $child_term and fixed it.
    – Mort 1305
    Commented Mar 31, 2022 at 4:50
  • If you are on Github I guess you can fork the gist. Will check update to see how the $child_term is dealt with. As for your question: I do want to limit to 3 items per custom post post & child term. That way I have 4 rows of three at that looks nicer with resources, articles, molecules and molecules of the month. If we want to exclude a cpt like molecules when need be that would be nice.
    – rhand
    Commented Mar 31, 2022 at 5:00

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.