Reputation: 541
I'd like to list all years from which there are public Wordpress posts, and in a sub-menu below, the months from those years. Example:
I have a working version of this inside a loop, but it requires me to manually add a new list every year. Is there any way to adjust it, so that it includes the new year automatically?
<h1>2016</h1>
<ul>
<?php
$string = wp_get_archives('type=monthly&year=2016&echo=0');
$pattern = ' ((19|20)\d{2}(</a>))';
echo preg_replace($pattern, '\\3', $string); '<li></li>';?>
</ul></a>
<h1>2015</h1>
<?php
$string = wp_get_archives('type=monthly&year=2015&echo=0');
$pattern = ' ((19|20)\d{2}(</a>))';
echo preg_replace($pattern, '\\3', $string); '<li></li>';?>
</ul></a>
Upvotes: 5
Views: 14064
Reputation: 590
I would do it this way.
It's a bit shorter and easier to understand, and it relies on WP core functions, which is usually the preferable way to handle the data in WP. Also, it doesn't need expensive regex functions.
<?php
add_filter( 'getarchives_where', 'archives_in_specific_year', 10, 2 );
function archives_in_specific_year( $sql_where, $parsed_args ) {
if ( ! empty( $parsed_args['in_year'] ) ) {
$year = absint( $parsed_args['in_year'] );
$sql_where .= " AND YEAR(post_date) = $year";
}
return $sql_where;
}
?>
<?php
$args = [
'type' => 'yearly',
'echo' => false,
];
$years = wp_get_archives( $args );
$years_array = explode( "\t", trim( wp_strip_all_tags( $years ) ) );
foreach ( $years_array as $current_year ) {
$current_year = intval( $current_year );
$monthly_args = [
'type' => 'monthly',
'format' => 'custom',
'echo' => false,
'before' => '<span>',
'after' => '</span>',
'in_year' => $current_year,
];
$months = str_replace( ' ' . $current_year, '', wp_get_archives( $monthly_args ) );
$yearly_args = [
'type' => 'yearly',
'after' => '<div>' . $months . '</div>',
'in_year' => $current_year,
];
wp_get_archives( $yearly_args );
}
?>
Upvotes: 1
Reputation: 342
<select name="archive-dropdown" onchange="document.location.href=this.options[this.selectedIndex].value;">
<option value=""><?php echo esc_attr( __( 'Select Month' ) ); ?></option>
<?php wp_get_archives( array( 'type' => 'monthly', 'format' => 'option', 'show_post_count' => 1 ) ); ?>
</select>
Upvotes: 1
Reputation: 1
here's a simple mysql query, solved a similiar problem.
$query = 'SELECT DISTINCT MONTH(`post_date`) AS `month`, YEAR(`post_date`) AS `year` FROM `wp_posts` ORDER BY `post_date` ASC';
$results = $wpdb->get_results($query);
Upvotes: 0
Reputation: 541
Ok, found a very helpful post on stack exchange: here
Basically, add this to functions.php:
//List archives by year, then month
function wp_custom_archive($args = '') {
global $wpdb, $wp_locale;
$defaults = array(
'limit' => '',
'format' => 'html', 'before' => '',
'after' => '', 'show_post_count' => false,
'echo' => 1
);
$r = wp_parse_args( $args, $defaults );
extract( $r, EXTR_SKIP );
if ( '' != $limit ) {
$limit = absint($limit);
$limit = ' LIMIT '.$limit;
}
// over-ride general date format ? 0 = no: use the date format set in Options, 1 = yes: over-ride
$archive_date_format_over_ride = 0;
// options for daily archive (only if you over-ride the general date format)
$archive_day_date_format = 'Y/m/d';
// options for weekly archive (only if you over-ride the general date format)
$archive_week_start_date_format = 'Y/m/d';
$archive_week_end_date_format = 'Y/m/d';
if ( !$archive_date_format_over_ride ) {
$archive_day_date_format = get_option('date_format');
$archive_week_start_date_format = get_option('date_format');
$archive_week_end_date_format = get_option('date_format');
}
//filters
$where = apply_filters('customarchives_where', "WHERE post_type = 'post' AND post_status = 'publish'", $r );
$join = apply_filters('customarchives_join', "", $r);
$output = '<ul>';
$query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date DESC $limit";
$key = md5($query);
$cache = wp_cache_get( 'wp_custom_archive' , 'general');
if ( !isset( $cache[ $key ] ) ) {
$arcresults = $wpdb->get_results($query);
$cache[ $key ] = $arcresults;
wp_cache_set( 'wp_custom_archive', $cache, 'general' );
} else {
$arcresults = $cache[ $key ];
}
if ( $arcresults ) {
$afterafter = $after;
foreach ( (array) $arcresults as $arcresult ) {
$url = get_month_link( $arcresult->year, $arcresult->month );
$year_url = get_year_link($arcresult->year);
/* translators: 1: month name, 2: 4-digit year */
$text = sprintf(__('%s'), $wp_locale->get_month($arcresult->month));
$year_text = sprintf('%d', $arcresult->year);
if ( $show_post_count )
$after = ' ('.$arcresult->posts.')' . $afterafter;
$year_output = get_archives_link($year_url, $year_text, $format, $before, $after);
$output .= ( $arcresult->year != $temp_year ) ? $year_output : '';
$output .= get_archives_link($url, $text, $format, $before, $after);
$temp_year = $arcresult->year;
}
}
$output .= '</ul>';
if ( $echo )
echo $output;
else
return $output;
}
And then call this function on the page:
<?php wp_custom_archive(); ?>
It will return a list exactly as needed, by year then month, with links to each!
Upvotes: 5