I have a widget that must display my custom post type. I don't display title or content, but just the values of 3 custom fields (acf) : start date, end date and city.
Here is my loop. I grab all the custom post that have the selected taxonomies (category and level). It's working.
$args = array(
'post_type' => 'formation',
'posts_per_page' => $instance['number_events'],
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'categories-formations',
'field' => 'id',
'terms' => $tax_id,
),
array(
'taxonomy' => 'niveau-formations',
'field' => 'id',
'terms' => $niveau_id,
),
),
);
$upcoming_events = new WP_Query($args);
if ( $title ) {
echo $before_title . $title . $after_title;
}
// vars
?>
<ul class="event_entries">
<?php
while( $upcoming_events->have_posts() ): $upcoming_events->the_post();
$event_start_date = get_field( 'date_de_debut');
$event_end_date = get_field('date_de_fin' );
$city = get_field('ville');
$posts = $upcoming_events->posts;
echo '<h3>' . $city . '</h3>';
echo '<ul>';
echo '<li>Du' . $event_start_date . ' au ' . $event_end_date . '</li>';
echo '</ul>';
endwhile; ?>
<?php
wp_reset_query();
echo $after_widget;
}
In frontend, I have my list with the city name as h3 and the corresponding start and end date in a ul li group.
Paris
Du13/07/2020 au 24/07/2020
Paris
Du22/06/2020 au 26/06/2020
Orléans
Du18/05/2020 au 22/05/2020
What I want to have is to group by city name, in order to have this: (all dates corresponding to a particular city grouped together)
Paris
Du13/07/2020 au 24/07/2020
Du22/06/2020 au 26/06/2020
Orléans
Du18/05/2020 au 22/05/2020
Please can anyone help me because i'm on this since two days, trying multiple queries and loop. I don't know how to achieve this. I would like to understand the logic.
I have a widget that must display my custom post type. I don't display title or content, but just the values of 3 custom fields (acf) : start date, end date and city.
Here is my loop. I grab all the custom post that have the selected taxonomies (category and level). It's working.
$args = array(
'post_type' => 'formation',
'posts_per_page' => $instance['number_events'],
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'categories-formations',
'field' => 'id',
'terms' => $tax_id,
),
array(
'taxonomy' => 'niveau-formations',
'field' => 'id',
'terms' => $niveau_id,
),
),
);
$upcoming_events = new WP_Query($args);
if ( $title ) {
echo $before_title . $title . $after_title;
}
// vars
?>
<ul class="event_entries">
<?php
while( $upcoming_events->have_posts() ): $upcoming_events->the_post();
$event_start_date = get_field( 'date_de_debut');
$event_end_date = get_field('date_de_fin' );
$city = get_field('ville');
$posts = $upcoming_events->posts;
echo '<h3>' . $city . '</h3>';
echo '<ul>';
echo '<li>Du' . $event_start_date . ' au ' . $event_end_date . '</li>';
echo '</ul>';
endwhile; ?>
<?php
wp_reset_query();
echo $after_widget;
}
In frontend, I have my list with the city name as h3 and the corresponding start and end date in a ul li group.
Paris
Du13/07/2020 au 24/07/2020
Paris
Du22/06/2020 au 26/06/2020
Orléans
Du18/05/2020 au 22/05/2020
What I want to have is to group by city name, in order to have this: (all dates corresponding to a particular city grouped together)
Paris
Du13/07/2020 au 24/07/2020
Du22/06/2020 au 26/06/2020
Orléans
Du18/05/2020 au 22/05/2020
Please can anyone help me because i'm on this since two days, trying multiple queries and loop. I don't know how to achieve this. I would like to understand the logic.
Share Improve this question edited Mar 24, 2020 at 0:06 WordPress Speed 2,2833 gold badges19 silver badges34 bronze badges asked Mar 22, 2020 at 15:45 blogobblogob 1377 bronze badges1 Answer
Reset to default 1First off, in your tax queries (tax_query
), you should use 'field' => 'term_id'
and not 'field' => 'id'
— i.e. use term_id
and not id
. But the default value/field is term_id
(term ID), though.
So you can achieve the grouped display like so, and you'd use the code in place of those lines starting from the <ul class="event_entries">
up to that wp_reset_query();
— you don't need to reset the global/main query because you're just making a secondary query which doesn't touch the global $wp_query
variable:
<?php
// First, group the posts by the city.
$groups = array();
foreach ( $upcoming_events->posts as $i => $p ) {
$city = get_field( 'ville', $p->ID );
if ( ! isset( $groups[ $city ] ) ) {
$groups[ $city ] = array();
}
$groups[ $city ][] =& $upcoming_events->posts[ $i ];
}
// Optional, sort the city names.
ksort( $groups, SORT_FLAG_CASE );
// Then display the posts.
if ( ! empty( $groups ) ) {
echo '<ul class="event_entries">';
foreach ( $groups as $city => $posts ) {
if ( ! empty( $posts ) ) {
// Display city name.
echo '<h3>' . $city . '</h3>';
// Display posts in that city.
echo '<ul>';
foreach ( $posts as $post ) {
$event_start_date = get_field( 'date_de_debut', $post->ID );
$event_end_date = get_field( 'date_de_fin', $post->ID );
echo '<li>Du' . $event_start_date . ' au ' . $event_end_date . '</li>';
}
echo '</ul>';
}
}
echo '</ul>'; // close .event_entries
}
Note that I'm assuming all the posts always have a valid city.
Also, the above technique doesn't alter the original posts in the $upcoming_events
object, and if you called setup_postdata()
in your code, you should also call wp_reset_postdata()
at the end of your code/function.
UPDATE: In response to your comment.
Sorry, I can't give a full tutorial or detailed guide on The Loop, but check that linked article and you'd at least understand what is, and how to use or work with The Loop.
However, what I can tell you from the above code, are:
When you do
$upcoming_events = new WP_Query()
, the$upcoming_events
variable becomes an instance of theWP_Query
class and therefore, the variable will inherit/contain all the (public) properties (e.g.$upcoming_events->posts
) and methods/functions (e.g.$upcoming_events->query()
) of the class. And you can find out about those properties and methods by checking the official reference here."I also don't understand what is
$upcoming_events->posts as $i => $p
'..what are$i
and$p
??" -$i
is the index of the current item in the$upcoming_events->posts
which is being looped through, whereas$p
is the value of that current item (i.e.$upcoming_events->posts[ $i ]
) which is aWP_Post
instance — but if you're having trouble understanding that "current item", then you need to check the PHP manual onforeach
, or you can ask or search for "What isforeach
in PHP?" on Stack Overflow.."I also don't understand
$groups[ $city ][] =& $upcoming_events->posts[ $i ];
" - well, that is just an alternative to$groups[ $city ][] = $upcoming_events->posts[ $i ];
(copying; note the=
versus=&
). And it's called "assigning by reference" which basically helps improve performance in that we don't need to copy the post objects to$groups
and simply reference to them in the original$upcoming_events->posts
.See this Stack Overflow question and/or this article for more details.
But basically, think of references like shortcuts in your computer; e.g. an icon on the desktop that points to a file, e.g. a text file. So
$my_var =& $file;
is like making a shortcut to that text file, whereas$my_var = $file;
(once again, note the=
vs=&
) is like you copied the file to your desktop."I don't understand what is inside the
$posts
variable" - if you mean thatforeach ( $groups as $city => $posts )
, then that$posts
is an array of post object references, so$posts[0]
for example, is a reference to$upcoming_events->posts[0]
which is a post object. I.e. They both point to the exact sameWP_Post
instance (see point #2 above).
So I hope those 4 points help you, but for more information about PHP-specific things like foreach
/loop and references, please ask on Stack Overflow or search on Google, etc. :)