Whats the Problem?
When building dynamic websites with WordPress, you might need to list upcoming events or posts from a custom post type while ensuring that only future events are displayed. This requires integrating custom fields for event dates and filtering posts based on these dates. Achieving this functionality can be complex, especially when working with Advanced Custom Fields (ACF) and custom taxonomies.
The Solution
To solve this problem, we’ll create a custom Gutenberg block in WordPress that lists terms from a selected taxonomy, displaying only posts with future event dates. We’ll use ACF for custom fields, specifically for selecting the post type and taxonomy, as well as storing event start dates. The solution involves querying posts with WP_Query and filtering them based on the event dates.
Step-by-Step Guide
- Create the Custom Block: Register a custom Gutenberg block that will handle displaying the list of terms and their posts.
- Fetch ACF Fields:Retrieve the selected post type and taxonomy using ACF. Default to `post` and `category` if these fields are empty.
- Fetch and Filter Terms: Fetch terms from the selected taxonomy and check if each term has posts with future event dates or no date set.
- Filter Posts Based on Event Date: For each term, query the posts and filter out those with past event dates. Only include posts with future dates or no date set.
- Display the Terms and Posts: Output the terms with their descriptions and the list of filtered posts. Ensure the event start date is formatted and displayed after the post title.
Below is a code example that demonstrates this approach:
<?php
// Fetch the ACF fields
$post_type = get_field('select_post_type') ?: 'post';
$taxonomy = get_field('select_taxonomy') ?: 'category';
// Fetch terms
$terms = get_terms(array(
'taxonomy' => $taxonomy,
'hide_empty' => true,
));
if (!empty($terms) && !is_wp_error($terms)) {
$terms_with_posts = [];
// Loop through each term and check if it has posts
foreach ($terms as $term) {
// Get posts for each term with date conditions
$query = new WP_Query(array(
'post_type' => $post_type,
'tax_query' => array(
array(
'taxonomy' => $taxonomy,
'field' => 'term_id',
'terms' => $term->term_id,
),
),
'meta_query' => array(
array(
'key' => 'event_start_date',
'compare' => 'EXISTS', // Ensure 'event_start_date' exists
),
),
'posts_per_page' => -1, // Fetch all posts to filter later
));
// Check if any posts are returned
if ($query->have_posts()) {
// Filter posts based on the event_start_date
$filtered_posts = [];
while ($query->have_posts()) {
$query->the_post();
$post_id = get_the_ID();
$event_start_date = get_field('event_start_date', $post_id);
if ($event_start_date) {
$event_date = strtotime($event_start_date);
$current_date = current_time('timestamp');
// Include post if the date is in the future or not set
if ($event_date >= $current_date) {
$filtered_posts[] = get_the_ID();
}
} else {
$filtered_posts[] = get_the_ID(); // Include posts without a date set
}
}
wp_reset_postdata();
// Add the term if there are filtered posts
if (!empty($filtered_posts)) {
$terms_with_posts[] = $term;
}
}
}
if (!empty($terms_with_posts)) {
echo '<div class="upcoming-list-container">';
foreach ($terms_with_posts as $term) {
$term_link = get_term_link($term);
$term_name = $term->name;
$term_description = term_description($term->term_id, $taxonomy); // Get the term description
// Get posts for each term again for display
$query = new WP_Query(array(
'post_type' => $post_type,
'tax_query' => array(
array(
'taxonomy' => $taxonomy,
'field' => 'term_id',
'terms' => $term->term_id,
),
),
'meta_query' => array(
array(
'key' => 'event_start_date',
'compare' => 'EXISTS', // Ensure 'event_start_date' exists
),
),
));
echo '<div class="upcoming-list-term">';
echo '<div class="list-inner-header">';
echo '<h2 class="list-term_title"><a href="' . esc_url($term_link) . '">' . esc_html($term_name) . '</a></h2>';
if ($term_description) {
echo wp_kses_post($term_description); // Display term description with HTML allowed
}
echo '</div>';
echo '<div class="list-inner_container">';
switch ($post_type) {
case 'event':
echo '<h3 class="list-title">Upcoming Classes</h3>';
break;
default:
echo '<h3 class="list-title">Upcoming Events</h3>';
break;
}
echo '<ul class="upcoming-list-posts">';
while ($query->have_posts()) {
$query->the_post();
$post_id = get_the_ID(); // Get the current post ID
$event_start_date = get_field('event_start_date', $post_id); // Pass post ID here
if ($event_start_date) {
$event_date = strtotime($event_start_date);
$current_date = current_time('timestamp');
// Format the date if it is in the future or not set
if ($event_date >= $current_date) {
$formatted_date = date('F j, Y', $event_date);
} else {
$formatted_date = 'Date not set';
}
} else {
$formatted_date = 'Date not set';
}
if ($formatted_date !== 'Date not set') {
echo '<li class="upcoming-list">';
echo '<a href="' . get_permalink() . '">' . esc_html($formatted_date) . ' – ' . get_the_title() . '</a>';
echo '</li>';
}
}
echo '</ul>';
echo '</div>';
echo '</div>';
wp_reset_postdata();
}
echo '</div>';
} else {
echo '<p>No terms with posts found.</p>';
}
} else {
echo '<p>No terms found.</p>';
}
?>