WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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.


share|improve this question

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!

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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