Question

I have CPT called "investment" and I want to display all the posts in that CPT by it's category. I'm doing that via shortcode.

e.g. [myshortcode type_of_post="investment" cat="12,30"]

and I want it to display posts as below

Category 12

  • post1
  • post2

Category 30

  • post3
  • post4

the problem that I have right now is that It shows all the posts but I'm struggling to separate posts by their categories.

that's how it shows right now

  • post1
  • post2
  • post3
  • post4

Here's my code

  // define attributes
    extract( shortcode_atts( array (
        'cat'   => '',
        'type_of_post' => '',
        'orderby' => 'date',
    ), $atts ) );

seperate posts

if($type_of_post){
    $args['post_type'] = $type_of_post;
}
if($cat) {
    $args['category__in'] = array_map('intval',explode(',',$cat));
}

Query

    $query = new WP_Query( $args );

    if( $query->have_posts() ){
        echo "<div class='row col-div investment'>";
        while( $query->have_posts() ){
            $query->the_post();
            $id = get_the_ID();
            $page = get_post($id);
            $image = get_the_post_thumbnail_url($id);

           display_layout($page,$image); //calls the function below
        }
        echo '</div>';
}

display posts

function display_layout($page,$image) {
    echo "<div class='col-sm-6  pair-cards'>
            <div class='sub-div'>
                <div class='card-img'>
                <a href='$page->post_name'><img src='$image' alt='$page->post_name'  /></a>
                </div>".
                    "<div class='entry-title'><a href='$page->post_name'>" .  $page->post_title  .  "</a></div>
                <div class='card-desc'>".
                    "<p>" . strip_tags($page->post_excerpt) ."</p>
                </div>
                <div class='read-more'>
                    <a href='$page->post_name'> Read More </a>
                </div>
            </div>
        </div>";
}

I hope I've explained my problem clearly.

Was it helpful?

Solution

In the loop you'll want to get the posts terms. Then instead of echo'ing, return the output and group it into an array where the keys are the categories. Then loop through the grouped array and output your categories and related posts. Something similar to:

// to hold and sort your output
$categories = array();

// loop through posts
while( $query->have_posts() ){

    // get the posts terms
    $terms = wp_get_post_terms(..
    $firstTerm = $terms[0];

    // see if the first term is defined in our holder
    if (!isset($categories[$firstTerm->name])) {
        $categories[$firstTerm->name] = array();
    }

    // ..

    $categories[$firstTerm->name][] = display_layout($page,$image);
}

Your display_layout() function would return your html instead of echoing.

Then you'd loop through $categories for your output:

foreach ($categories as $catName => $catItems) {
    echo "<strong>{$catName}</strong>";
    foreach ($catItems as $catItem) {
        echo $catItem;
    }
}

This isn't a copy/paste answer, it's just an idea for the logic of storing and sorting your values in an array - please keep in mind that you will want to:

  • use better logic than "first term", as the first term won't necessarily be 12 or 30 (unless you only did one-term-per-post - but that still leaves high probability of human error), you'll want to loop through all the terms and see if it contains a $cat value
  • use IDs instead of strings for the array keys, $firstTerm->term_id instead of $firstTerm->name, finding a different way of carrying over the name value.
  • wrap this in a cache so each page load isn't doing a ton of queries
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top