WordPress: Order WP_Query with a custom date field and split the loop after each month

I use the WordPress custom post type to manage and display events on my site. To sort events, I use a custom meta field with a date in it (stored as follows: YYYY-MM-DD). I check the meta box for the current date. Like this:

$current_date_query = date ('Ym-d'); $temp = $wp_query; $wp_query= null; $wp_query = new WP_Query(); $wp_query->query( array( 'post_type' => 'event', 'meta_key' => 'event_date', 'meta_compare' => '>=', 'meta_value' => $current_date_query, 'post_status' => 'publish', 'posts_per_page' => '99', 'orderby' => 'meta_value', 'order' => 'ASC', 'paged' => $paged ) ); ?> ... Loop stuff ... <?php endif; $wp_query = null; $wp_query = $temp; wp_reset_query(); ?> 

Now I want to add a heading before each new month. Like this:

January 2018

  • Event 1
  • Event 2
  • Event 3

February 2018

  • Event 4
  • Event 5

March 2018

  • Event 5

etc.

Is there a way to split the cycle after every month? I think I need to use the month from the meta field, but I don’t know how to do it.

I tried the following solution (thanks to the comment from @FluffyKitten):

 <?php /* declare an array to save the data */ $quarters = array(); foreach($posts as $q) { $donor_date = get_post_meta($q->ID,'gid_22',true); $donor_month = date('m',strtotime($donor_date)); /* format the date once - best practice is not to repeat code */ $formatteddate = date('d/m/Y',strtotime($donor_date)); /* organise the dates by quarter, using the heading as the key for easy display */ if(in_array($donor_month, array('01'))) $quarters["January"][] = $formatteddate; else if(in_array($donor_month, array('02'))) $quarters["February"][] = $formatteddate; else if(in_array($donor_month, array('03'))) $quarters["March"][] = $formatteddate; else if(in_array($donor_month, array('04'))) $quarters["April"][] = $formatteddate; else if(in_array($donor_month, array('05'))) $quarters["May"][] = $formatteddate; else if(in_array($donor_month, array('06'))) $quarters["June"][] = $formatteddate; else if(in_array($donor_month, array('07'))) $quarters["July"][] = $formatteddate; else if(in_array($donor_month, array('08'))) $quarters["August"][] = $formatteddate; else if(in_array($donor_month, array('09'))) $quarters["September"][] = $formatteddate; else if(in_array($donor_month, array('10'))) $quarters["Ocotber"][] = $formatteddate; else if(in_array($donor_month, array('11'))) $quarters["November"][] = $formatteddate; else if(in_array($donor_month, array('12'))) $quarters["December"][] = $formatteddate; } /* now go through your array and display the results */ foreach ($quarters as $quartername => $quarter){ /* $quarters won't have any entry for quarters with no dates, so technically this 'if' isn't needed, however I've added it in case it will be needed it for any other changes you make */ if ($quarter){ ?> <h3><?php echo $quartername; ?></h3> <table> <?php foreach ($quarter as $qdate ){ ?> <tr><td> <?php echo $qdate; ?> </td></tr> <?php } // end foreach($quarter...) ?> </table> <?php } // end if } // end foreach($quarters...) ?> 

Now I get this result:

Ocotber

  • 10/02/2018
  • 10/29/2017

January

  • 01/02/2018

December

  • 12/02/2017
  • 12/01/2017

May

  • 05/02/2018

...

The order is based on the publication date and is not based on a custom field. There is also no difference between the years. 2017 should have its own cycle, as well as 2018.

If I try to put my own array in the first array of the loop, it will have no effect, and it will only display as text in the interface.

Edit: I could order a month using a custom query like this:

 $posts = query_posts( array( 'post_type' => 'event', 'meta_key' => 'event_date', 'meta_compare' => '>=', 'meta_value' => $current_date_query, 'post_status' => 'publish', 'posts_per_page' => '99', 'orderby' => 'meta_value', 'order' => 'ASC', 'paged' => $paged ) ); 

The problem is now only a year. This is all for months with different years per month.

+5
source share
2 answers

The solution you tried to use @FluffyKitten does not work properly, because it is grouped into groups of the same month, and not the same month and year, so it drops when there are records for the same month of different years.

Since @ChinLeung suggested you keep the current month in a variable to check when it changed and display your headers. To implement this for your example, you would do the following:

 // Set current month $current_month = ''; // Get event posts in order $events = query_posts( array( 'post_type' => 'event', 'meta_key' => 'event_date', 'meta_compare' => '>=', 'meta_value' => date ('Ym-d'), 'meta_type' => 'DATE', 'post_status' => 'publish', 'posts_per_page' => '99', 'orderby' => 'meta_value', 'order' => 'ASC', 'paged' => $paged ) ); // Iterate over events foreach($events as $key => $event){ // Get event date from post meta $event_date = get_post_meta($event->ID, 'event_date', $single = true); // Cache event month/year $event_month = date('F Y', strtotime($event_date)); // Open new group if new month if($current_month != $event_month){ if($key !== 0) echo '</ul>'; echo "<h2>{$event_month}</h2>"; echo '<ul>'; } // Add event date as new list item echo "<li>{$event_date}</li>"; // Cache $curret_month $current_month = $event_month; } // Close the last list if query had events if(count($events)) echo '</ul>'; 

EDIT

To update this solution for working in the mail type archive, instead of the above, add the following to your theme functions.php:

 /** * Get event date * * @return string */ function get_event_date() { /** @global WP_Post $post */ global $post; /** Get event date from post meta */ return get_post_meta($post->ID, 'event_date', $single = true); } /** * Get event month/year formatted * * @param string $event_date * * @return string */ function format_event_date($event_date) { return date('F Y', strtotime($event_date)); } /** * Order events archive by event date post meta * * @param WP_Query $query * * @return WP_Query */ function events_archive_pre_get_posts($query) { if (!$query->is_main_query() || !is_post_type_archive('event')) return $query; $query->set('meta_key', 'event_date'); $query->set('meta_compare', '>='); $query->set('meta_value', date('Ym-d')); $query->set('meta_type', 'DATE'); $query->set('posts_per_page', 2); $query->set('orderby', 'meta_value'); $query->set('order', 'ASC'); return $query; } add_filter('pre_get_posts', 'events_archive_pre_get_posts'); 

Then you can set the number of posts per page to the desired number, and pagination will work as expected. Here's a template for a post post type template that you can use to add date headers between neatly formatted HTML lists, or at least until SO converts the tabs to spaces:

 <?php // Template header get_header(); ?> <?php /** @global WP_Query */ global $wp_query; ?> <?php // Events archive loop for($previous_month = ''; have_posts(); $previous_month = $formatted_date): the_post(); // Get event date from post meta $event_date = get_event_date(); // Format event month/year $formatted_date = format_event_date($event_date); // The formatted date is the first or not the same as previous event if($previous_month != $formatted_date): // Close previous list if this is not the first if($wp_query->current_post !== 0) echo "\n\t</ul>\n"; // New month template ?> <h2><?php echo $formatted_date; ?></h2> <?php // Open new list echo "\t<ul>\n"; endif; // Event post template ?> <li><?php echo $event_date; ?></li> <?php endfor; // Reset query wp_reset_query(); // Close the last list if query had events if(have_posts()) echo "\t</ul>\n"; ?> <?php // Pagination the_posts_pagination(); ?> <?php // Template footer get_footer(); 
+1
source

You can save the current month of the cycle in a variable and check if the cycle is still in the same month.

Suppose $events is an array of all the events that you want to display as an instance of WP_Post .

 $current = 0; foreach($events as $event){ $eventDate = get_field('event_date', $event->ID); $month = date('m', strtotime($eventDate)); // New month if($current != $month){ $current = $month; // Perform actions of new month } // Perform normal actions for the event } 
+1
source

Source: https://habr.com/ru/post/1272233/


All Articles