wp_get_archives() │ WP 1.2.0
Outputs a list of links to archive pages by date (days, months, years).
This function is a template tag and can be used anywhere in the template.
1 time — 0.0141909 sec (extremely slow) | 50000 times — 138.17 sec (extremely slow) | PHP 8.2.25, WP 6.8.1
Returns
null|String . A string when the result is returned.
Usage Template
wp_get_archives( [
'type' => 'monthly',
'limit' => '', // with '0' we will get a syntax error (the value must be specified as an int or an empty string)
'format' => 'html',
'before' => '',
'after' => '',
'show_post_count' => false,
'echo' => 1,
'post_type' => 'post',
] );
Usage
wp_get_archives( $args );
type(string)
Type of the output list, can be:
yearly - links to archive pages by years.
monthly - list of links to archive pages by months (default).
daily - list of links to archive pages by days.
weekly - list of links to archive pages by weeks.
postbypost - list of links to posts sorted by date.
alpha - same as "postbypost", but sorting will be done by the article title.
Default: 'monthly'
limit(int)
Number of archive links to retrieve.
Default: unlimited.
format(string)
Format of the returned list. Available values:
html - HTML tag <li> before and after the link (default).
option - Dropdown list <select>.
link - Inside HTML <link>.
custom - Custom tag, use the arguments before and after.
Default: 'html'
before(string)
Text (html tag) before the link. Works only when the parameter format is set to html or custom.
Default: ''
after(string)
Text (html tag) after the link. Works only when the parameter format is set to html or custom.
Default: ''
show_post_count(boolean)
Show the number of posts next to the link. Works with all output types (type), except postbypost.
— 1 (True)
— 0 (False) - Default
Default: false
echo(boolean)
Output the result to the screen (default) or return for further processing (false).
Default: true
post_type(string)
Name of the post type. Since version 4.4.
Default: 'post'
Examples
#1 Display an archive of posts grouped by month.
Only the last 12 months will be shown:
<?php wp_get_archives('type=monthly&limit=12'); ?>
#2 Display an archive of posts grouped by day
Only the last 14 days will be shown, with count total for each day in parentheses, e.g. “November 2, 2015 (3)”.
<?php wp_get_archives( [ 'type'=>'daily', 'limit'=>14, 'show_post_count' => 'true' ] ); ?>
#3 Display a list of the last 20 posts and sort it by title:
<?php wp_get_archives( 'type=postbypost&limit=20&format=custom' ); ?>
#4 Display the drop-down list of the archive by month in the HTML tag <select>
The number of posts for each month will be displayed next to it:
<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( 'type=monthly&format=option&show_post_count=1' ); ?>
</select>
#5 Display a list of all posts in alphabetical order.
Might come in handy for a site map:
<?php wp_get_archives( 'type=alpha' ); ?>
#6 Add rel=nofollow to links from the list
If you want to add rel="nofollow" to all links from the list, you can use this function call:
$archives = wp_get_archives( [
'echo' => 0,
'type' => 'postbypost',
'limit' => 3,
'format' => 'html',
] );
echo str_replace( '<a', '<a rel="nofollow"', $archives );
#7 Filter a specific category/term
To filter a specific category/term, we have a specific case to add filters. It works in case we wish to change archive link based on get_query_var( 'news_category' ).
For example, on same template we have:
– News Category #1 has dropdown of 2019, 2018, 2017.
– News Category #2 has dropdown of 2017.
If the user access /news/news-category-2/2019, it will return no posts. We should disable an archive link 2018, 2019 if a current category is News Category.
The below code work with Taxonomy “news_category” and custom post type “news”. To work with default post, you should change back to Taxonomy “category” and default post “post”.
In templates/custom-archive-template.php
add_filter( 'getarchives_where', 'custom_archive_by_category_where' );
add_filter( 'getarchives_join', 'custom_archive_by_category_join' );
$args = array();
wp_get_archives( [
'type' => 'yearly',
'format' => 'option',
'post_type' => 'news',
] );
remove_filter( 'getarchives_where', 'custom_archive_by_category_where' );
remove_filter( 'getarchives_join', 'custom_archive_by_category_join' );
In functions.php:
function custom_archive_by_category_join( $x ) {
global $wpdb;
return $x . "
INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)
INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)";
}
function custom_archive_by_category_where($x) {
global $wpdb;
$current_term_slug = get_query_var( 'news_category' );
if (!empty($current_term_slug)) {
$current_term = get_term_by('slug', $current_term_slug, 'news_category');
if (is_wp_error($current_term) ) {
return $x;
}
$current_term_id = $current_term->term_id;
return $x . "
AND $wpdb->term_taxonomy.taxonomy = 'news_category'
AND $wpdb->term_taxonomy.term_id IN ($current_term_id)";
}
return $x;
}
Read more about https://developer.wordpress.org/reference/hooks/getarchives_where/ and https://developer.wordpress.org/reference/hooks/getarchives_join/
#8 Get array with name and value keys
To return an array of years with name and value only like:
array(
array(
'name' => 'January 2020',
'value' => 'http://demo.com/2020/01/'
),
array(
'name' => 'February 2020',
'value' => 'http://demo.com/2020/02/'
)
)
We must capture using echo=false&format=custom:
function theme_name_get_year_archive_array() {
$years = [];
$years_args = [
'type' => 'monthly',
'format' => 'custom',
'before' => '',
'after' => '|',
'echo' => false,
'post_type' => 'news',
'order' => 'ASC',
];
// Get Years
$years_content = wp_get_archives( $years_args );
if( ! empty( $years_content ) ){
$years_arr = explode( '|', $years_content );
$years_arr = array_filter( $years_arr, function( $item ) {
return trim( $item ) !== '';
} ); // Remove empty whitespace item from array
foreach( $years_arr as $year_item ){
$year_row = trim( $year_item );
preg_match( '/href=["\']?([^"\'>]+)["\']>(.+)<\/a>/', $year_row, $year_vars );
if( ! empty( $year_vars ) ){
$years[] = [
'name' => $year_vars[2], // Ex: January 2020
'value' => $year_vars[1] // Ex: http://demo.com/2020/01/
];
}
}
}
return $years;
}
#9 Display the titles of the last 20 posts
Uses custom as the value for the format argument and specifies before and after values (so, in this example, prints the titles within span tags and separated by commas):
<?php
wp_get_archives( [
'type' => 'postbypost',
'limit' => 20,
'format' => 'custom',
'before' => '<span class="my-post-title">',
'after' => '</span>, ',
] );
?>
#10 Custom wrappers on each link
An example using custom wrappers on each link item in the archive.
Helpful if you are doing special styling that require a more complicated structure.
<?php
$args = array(
'type' => 'monthly',
'limit' => '',
'format' => 'custom',
'before' => '<div class="sub-item">',
'after' => '</div>',
'show_post_count' => false,
'echo' => 1,
'order' => 'DESC'
);
wp_get_archives( $args );
?>
Add Your Own Example
Notes
See: get_archives_link()
Global. wpdb. $wpdb WordPress database abstraction object.
Global. WP_Locale. $wp_locale WordPress date and time locale object.
Changelog
Since 1.2.0
Introduced.
Since 4.4.0
The $post_type argument was added.
Since 5.2.0
The $year, $monthnum, $day, and $w arguments were added.
wp_get_archives() wp get archives code
WP 7.0
function wp_get_archives( $args = '' ) {
global $wpdb, $wp_locale;
$defaults = array(
'type' => 'monthly',
'limit' => '',
'format' => 'html',
'before' => '',
'after' => '',
'show_post_count' => false,
'echo' => 1,
'order' => 'DESC',
'post_type' => 'post',
'year' => get_query_var( 'year' ),
'monthnum' => get_query_var( 'monthnum' ),
'day' => get_query_var( 'day' ),
'w' => get_query_var( 'w' ),
);
/**
* Filters the arguments for displaying archive links.
*
* @since 7.0.0
*
* @see wp_get_archives()
*
* @param array<string, string|int|bool> $args Arguments.
*/
$args = apply_filters( 'wp_get_archives_args', $args );
$parsed_args = wp_parse_args( $args, $defaults );
$post_type_object = get_post_type_object( $parsed_args['post_type'] );
if ( ! is_post_type_viewable( $post_type_object ) ) {
return;
}
$parsed_args['post_type'] = $post_type_object->name;
if ( '' === $parsed_args['type'] ) {
$parsed_args['type'] = 'monthly';
}
if ( ! empty( $parsed_args['limit'] ) ) {
$parsed_args['limit'] = absint( $parsed_args['limit'] );
$parsed_args['limit'] = ' LIMIT ' . $parsed_args['limit'];
}
$order = strtoupper( $parsed_args['order'] );
if ( 'ASC' !== $order ) {
$order = 'DESC';
}
// This is what will separate dates on weekly archive links.
$archive_week_separator = '–';
$sql_where = $wpdb->prepare( "WHERE post_type = %s AND post_status = 'publish'", $parsed_args['post_type'] );
/**
* Filters the SQL WHERE clause for retrieving archives.
*
* @since 2.2.0
*
* @param string $sql_where Portion of SQL query containing the WHERE clause.
* @param array $parsed_args An array of default arguments.
*/
$where = apply_filters( 'getarchives_where', $sql_where, $parsed_args );
/**
* Filters the SQL JOIN clause for retrieving archives.
*
* @since 2.2.0
*
* @param string $sql_join Portion of SQL query containing JOIN clause.
* @param array $parsed_args An array of default arguments.
*/
$join = apply_filters( 'getarchives_join', '', $parsed_args );
$output = '';
$last_changed = wp_cache_get_last_changed( 'posts' );
$limit = $parsed_args['limit'];
if ( 'monthly' === $parsed_args['type'] ) {
$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 $order $limit";
$key = md5( $query );
$key = "wp_get_archives:$key";
$results = wp_cache_get_salted( $key, 'post-queries', $last_changed );
if ( ! $results ) {
$results = $wpdb->get_results( $query );
wp_cache_set_salted( $key, $results, 'post-queries', $last_changed );
}
if ( $results ) {
$after = $parsed_args['after'];
foreach ( (array) $results as $result ) {
$url = get_month_link( $result->year, $result->month );
if ( 'post' !== $parsed_args['post_type'] ) {
$url = add_query_arg( 'post_type', $parsed_args['post_type'], $url );
}
/* translators: 1: Month name, 2: 4-digit year. */
$text = sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $result->month ), $result->year );
if ( $parsed_args['show_post_count'] ) {
$parsed_args['after'] = ' (' . $result->posts . ')' . $after;
}
$selected = is_archive() && (string) $parsed_args['year'] === $result->year && (string) $parsed_args['monthnum'] === $result->month;
$output .= get_archives_link( $url, $text, $parsed_args['format'], $parsed_args['before'], $parsed_args['after'], $selected );
}
}
} elseif ( 'yearly' === $parsed_args['type'] ) {
$query = "SELECT YEAR(post_date) AS `year`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date) ORDER BY post_date $order $limit";
$key = md5( $query );
$key = "wp_get_archives:$key";
$results = wp_cache_get_salted( $key, 'post-queries', $last_changed );
if ( ! $results ) {
$results = $wpdb->get_results( $query );
wp_cache_set_salted( $key, $results, 'post-queries', $last_changed );
}
if ( $results ) {
$after = $parsed_args['after'];
foreach ( (array) $results as $result ) {
$url = get_year_link( $result->year );
if ( 'post' !== $parsed_args['post_type'] ) {
$url = add_query_arg( 'post_type', $parsed_args['post_type'], $url );
}
$text = sprintf( '%d', $result->year );
if ( $parsed_args['show_post_count'] ) {
$parsed_args['after'] = ' (' . $result->posts . ')' . $after;
}
$selected = is_archive() && (string) $parsed_args['year'] === $result->year;
$output .= get_archives_link( $url, $text, $parsed_args['format'], $parsed_args['before'], $parsed_args['after'], $selected );
}
}
} elseif ( 'daily' === $parsed_args['type'] ) {
$query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, DAYOFMONTH(post_date) AS `dayofmonth`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date), DAYOFMONTH(post_date) ORDER BY post_date $order $limit";
$key = md5( $query );
$key = "wp_get_archives:$key";
$results = wp_cache_get_salted( $key, 'post-queries', $last_changed );
if ( ! $results ) {
$results = $wpdb->get_results( $query );
wp_cache_set_salted( $key, $results, 'post-queries', $last_changed );
}
if ( $results ) {
$after = $parsed_args['after'];
foreach ( (array) $results as $result ) {
$url = get_day_link( $result->year, $result->month, $result->dayofmonth );
if ( 'post' !== $parsed_args['post_type'] ) {
$url = add_query_arg( 'post_type', $parsed_args['post_type'], $url );
}
$date = sprintf( '%1$d-%2$02d-%3$02d 00:00:00', $result->year, $result->month, $result->dayofmonth );
$text = mysql2date( get_option( 'date_format' ), $date );
if ( $parsed_args['show_post_count'] ) {
$parsed_args['after'] = ' (' . $result->posts . ')' . $after;
}
$selected = is_archive() && (string) $parsed_args['year'] === $result->year && (string) $parsed_args['monthnum'] === $result->month && (string) $parsed_args['day'] === $result->dayofmonth;
$output .= get_archives_link( $url, $text, $parsed_args['format'], $parsed_args['before'], $parsed_args['after'], $selected );
}
}
} elseif ( 'weekly' === $parsed_args['type'] ) {
$week = _wp_mysql_week( '`post_date`' );
$query = "SELECT DISTINCT $week AS `week`, YEAR( `post_date` ) AS `yr`, DATE_FORMAT( `post_date`, '%Y-%m-%d' ) AS `yyyymmdd`, count( `ID` ) AS `posts` FROM `$wpdb->posts` $join $where GROUP BY $week, YEAR( `post_date` ) ORDER BY `post_date` $order $limit";
$key = md5( $query );
$key = "wp_get_archives:$key";
$results = wp_cache_get_salted( $key, 'post-queries', $last_changed );
if ( ! $results ) {
$results = $wpdb->get_results( $query );
wp_cache_set_salted( $key, $results, 'post-queries', $last_changed );
}
$arc_w_last = '';
if ( $results ) {
$after = $parsed_args['after'];
foreach ( (array) $results as $result ) {
if ( $result->week !== $arc_w_last ) {
$arc_year = $result->yr;
$arc_w_last = $result->week;
$arc_week = get_weekstartend( $result->yyyymmdd, get_option( 'start_of_week' ) );
$arc_week_start = date_i18n( get_option( 'date_format' ), $arc_week['start'] );
$arc_week_end = date_i18n( get_option( 'date_format' ), $arc_week['end'] );
$url = add_query_arg(
array(
'm' => $arc_year,
'w' => $result->week,
),
home_url( '/' )
);
if ( 'post' !== $parsed_args['post_type'] ) {
$url = add_query_arg( 'post_type', $parsed_args['post_type'], $url );
}
$text = $arc_week_start . $archive_week_separator . $arc_week_end;
if ( $parsed_args['show_post_count'] ) {
$parsed_args['after'] = ' (' . $result->posts . ')' . $after;
}
$selected = is_archive() && (string) $parsed_args['year'] === $result->yr && (string) $parsed_args['w'] === $result->week;
$output .= get_archives_link( $url, $text, $parsed_args['format'], $parsed_args['before'], $parsed_args['after'], $selected );
}
}
}
} elseif ( ( 'postbypost' === $parsed_args['type'] ) || ( 'alpha' === $parsed_args['type'] ) ) {
$orderby = ( 'alpha' === $parsed_args['type'] ) ? 'post_title ASC ' : 'post_date DESC, ID DESC ';
$query = "SELECT * FROM $wpdb->posts $join $where ORDER BY $orderby $limit";
$key = md5( $query );
$key = "wp_get_archives:$key";
$results = wp_cache_get_salted( $key, 'post-queries', $last_changed );
if ( ! $results ) {
$results = $wpdb->get_results( $query );
wp_cache_set_salted( $key, $results, 'post-queries', $last_changed );
}
if ( $results ) {
foreach ( (array) $results as $result ) {
if ( '0000-00-00 00:00:00' !== $result->post_date ) {
$url = get_permalink( $result );
if ( $result->post_title ) {
/** This filter is documented in wp-includes/post-template.php */
$text = strip_tags( apply_filters( 'the_title', $result->post_title, $result->ID ) );
} else {
$text = $result->ID;
}
$selected = get_the_ID() === $result->ID;
$output .= get_archives_link( $url, $text, $parsed_args['format'], $parsed_args['before'], $parsed_args['after'], $selected );
}
}
}
}
if ( $parsed_args['echo'] ) {
echo $output;
} else {
return $output;
}
}
Related Functions