I have a custom post type, promotions, and it has 2 meta fields to set dates with jQuery date picker, begin date & end date, year, month, day.

What I'm trying to do is show a list of months with a header for the year between each grouping, clicking a month would take you to an archive of promotions posts that began in the same year as the heading, clicking the year would be an archive of all the promotions that started in that year.



I realize an easy way to do this could be to just have a year and month taxonomy for the end date and beginning date but it has been requested, and would be the most user friendly, to only require the user entering data to have to enter the ending date, and begining date of the promotion once.


1 Answer 1


I'd recommend something like the following:

  • Slurp up a list of all of the distinct meta values corresponding to the start date meta_key. I don't see a WP function that does this, so you'll have to do something like the following:

    $start_dates = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = %s", 'start_date' ) );
  • Loop through the start dates to sniff out the years and months that are used, and put them into a structured array:

    $year_months = array();
    foreach( (array) $start_dates as $sd ) {
        // Assuming your $sd is already in UNIX format. strtotime() if not
        $year = date( 'Y', $sd );
        $month = date( 'm', $sd );
        if ( !isset( $year_months[$year] ) ) {
            $year_months[$year] = array();
        } else {
            if ( !in_array( $month, $year_months[$year] ) ) {
                $year_months[$year][] = $month;
    // sort
    arsort( $year_months );

    That'll give you an array that looks like

    [2012] => 'January', 'March', 'June',
    [2011] => 'April', 'March', etc

    (though you may need to do some usort() magic on these month arrays to get them in the right order). Since this is a costly-ish process, you might want to stash it in an option or a transient, which gets busted on update_post_meta().

  • Loop through the array to build your list:

    $html = '<ul>';
    foreach( (array) $year_months as $year => $months ) {
        $html .= '<li><h3>' . esc_html( $year ) . '</h3>';
        $html .= '<ul>';
        foreach( $months as $month ) {
            $html .= '<li><a href="' . $whatever_your_link_is . '">' . esc_html( $month ) . '</a></li>'; 
        $html .= '</ul>';
        $html .= '</li>';
    $html = '</ul>';
    echo $html;
  • As for how you get $whatever_your_link_is, probably the simplest way is to pass meta_value and meta_key arguments to the URL and let WP_Query take care of the rest, though if you need something more sophisticated, you'll probably have to pass some custom URL parameters and then use meta_query.

Good luck!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.