wp_get_archives()
云策文档标注
概述
wp_get_archives() 是 WordPress 核心函数,用于根据类型和格式显示归档链接。它支持多种归档类型,如按日、周、月、年或按文章标题排序,并允许自定义输出格式和参数。
关键要点
- 函数接受一个参数数组 $args,控制归档类型、限制数量、格式、前后标记、是否显示文章计数、是否回显等。
- 归档类型包括 'daily'、'weekly'、'monthly'、'yearly'、'postbypost' 和 'alpha',其中 'postbypost' 和 'alpha' 显示文章标题而非日期。
- 输出格式支持 'link'、'option'、'html' 或自定义格式,通过 $before 和 $after 参数调整标记。
- 函数内部使用 SQL 查询和缓存机制(如 wp_cache_get_salted)优化性能,并应用过滤器 getarchives_where 和 getarchives_join 进行自定义。
- 返回类型取决于 $args['echo'] 参数:为 true 时直接输出,为 false 时返回字符串。
代码示例
// 显示最近12个月的归档链接
wp_get_archives( array( 'type' => 'monthly', 'limit' => 12 ) );
// 显示下拉菜单形式的月度归档,带文章计数
wp_get_archives( array( 'type' => 'monthly', 'format' => 'option', 'show_post_count' => 1 ) );
// 自定义格式返回数组
function theme_name_get_year_archive_array() {
$years = array();
$years_args = array(
'type' => 'monthly',
'format' => 'custom',
'before' => '',
'after' => '|',
'echo' => false,
'post_type' => 'news',
'order' => 'ASC'
);
$years_content = wp_get_archives($years_args);
// 处理 $years_content 返回数组
return $years;
}注意事项
- 使用过滤器 getarchives_where 和 getarchives_join 可以扩展查询,例如按分类筛选归档链接。
- 参数 $post_type 默认为 'post',从 WordPress 4.4.0 开始支持自定义文章类型。
- 在自定义格式时,需注意 $before 和 $after 的标记处理,以避免 HTML 结构错误。
原文内容
Displays archive links based on type and format.
Description
See also
Parameters
$argsstring|arrayrequired-
Default archive links arguments. Optional.
typestringType of archive to retrieve. Accepts'daily','weekly','monthly','yearly','postbypost', or'alpha'. Both'postbypost'and'alpha'display the same archive link list as well as post titles instead of displaying dates. The difference between the two is that'alpha'will order by post title and'postbypost'will order by post date.
Default'monthly'.limitstring|intNumber of links to limit the query to. Default empty (no limit).formatstringFormat each link should take using the $before and $after args.
Accepts'link'(<link>tag),'option'(<option>tag),'html'(<li>tag), or a custom format, which generates a link anchor with $before preceding and $after succeeding. Default'html'.beforestringMarkup to prepend to the beginning of each link. Default empty.afterstringMarkup to append to the end of each link. Default empty.show_post_countboolWhether to display the post count alongside the link. Default false.echobool|intWhether to echo or return the links list. Default1|trueto echo.orderstringWhether to use ascending or descending order. Accepts'ASC', or'DESC'.
Default'DESC'.post_typestringPost type. Default'post'.yearstringYear. Default current year.monthnumstringMonth number. Default current month number.daystringDay. Default current day.wstringWeek. Default current week.
Source
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' ),
);
$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;
}
}
Hooks
- apply_filters( ‘getarchives_join’, string $sql_join, array $parsed_args )
-
Filters the SQL JOIN clause for retrieving archives.
- apply_filters( ‘getarchives_where’, string $sql_where, array $parsed_args )
-
Filters the SQL WHERE clause for retrieving archives.
- apply_filters( ‘the_title’, string $post_title, int $post_id )
-
Filters the post title.
Skip to note 10 content
Khoi Pro
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( array( '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/
Skip to note 11 content
Codex
Display list of links to last two weeks of daily archives
Lists last 14 days that had at least one post, with count total for each day in parentheses, e.g. “November 2, 2015 (3)”.
'daily', 'limit' => 14, 'show_post_count' => 'true' ) ); ?>Skip to note 12 content
Codex
Dropdown Box
Displays a dropdown menu of monthly archives, in option tags, with the post count (uses JavaScript to navigate to the selected archive page).
<select name="archive-dropdown" onchange="document.location.href=this.options[this.selectedIndex].value;"> <option value=""></option> 'monthly', 'format' => 'option', 'show_post_count' => 1 ) ); ?> </select>Skip to note 13 content
LokiWP
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 = array(); $years_args = array( 'type' => 'monthly', 'format' => 'custom', // My advise: WordPress Core shoud be add support "format=array" to keep it easy to catch for many custom cases '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[] = array( 'name' => $year_vars[2], // Ex: January 2020 'value' => $year_vars[1] // Ex: <a href="http://demo.com/2020/01/" rel="nofollow ugc">http://demo.com/2020/01/</a> ); } } } return $years; }Skip to note 14 content
Codex
Default Usage
'monthly', 'limit' => '', 'format' => 'html', 'before' => '', 'after' => '', 'show_post_count' => false, 'echo' => 1, 'order' => 'DESC' ); wp_get_archives( $args ); ?>Skip to note 15 content
Codex
Display list of links to last 12 months of archives
'monthly', 'limit' => 12 ) ); ?>Skip to note 16 content
Codex
Display the titles of the last 20 posts
Uses
customas the value for theformatargument and specifiesbeforeandaftervalues (so, in this example, prints the titles within span tags and separated by commas):'postbypost', 'limit' => 20, 'format' => 'custom', 'before' => '<span class="my-post-title">', 'after' => '</span>, ' ) ); ?>Skip to note 17 content
Codex
Display linked titles of all posts, listed alphabetically
Of possible use on a sitemap.
Skip to note 18 content
talymo36
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.
'monthly', 'limit' => '', 'format' => 'custom', 'before' => '<div class="sub-item">', 'after' => '</div>', 'show_post_count' => false, 'echo' => 1, 'order' => 'DESC' ); wp_get_archives( $args ); ?>