How to seperate posts by categories?
-
12-05-2021 - |
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.
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 echo
ing.
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
or30
(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