WP笔记

WordPress文章列表模板带分页

WordPress博客类网站通常用文章(post)类型发布内容。为了让用户和搜索引擎快速了解网站的全部内容,可以制作一个文章列表页面,删繁就简,只将标题等重要信息展示出来,用户阅读标题就能了解网站内容是否对自己有用,搜索引擎则能更方便的找到链接,这有些类似HTML 网站地图

方案一:带分页的文章列表

以下代码就是全部,包含分页和样式,不用安装其它插件。存成一个php文件放到当前主题根目录下,编辑页面时模板选择Article List即可。

模板代码

<?php
/**
 * Template Name: Article List
 *
 */

// 分页函数
if ( ! function_exists( 'sola_pagination' ) ) :
    function sola_pagination( $paged = '', $max_page = '' ){
        $big = 999999999; // need an unlikely integer
        if( ! $paged )
            $paged = get_query_var('paged');
        if( ! $max_page )
            $max_page = $wp_query->max_num_pages;

        echo paginate_links( array(
            'base'       => str_replace($big, '%#%', esc_url(get_pagenum_link( $big ))),
            'format'     => '?paged=%#%',
            'current'    => max( 1, $paged ),
            'total'      => $max_page,
            'mid_size'   => 10,
            'prev_text'  => __('«'),
            'next_text'  => __('»'),
            'type'       => 'list'
        ) );
    }
endif;

/** 获取该页面的标题和内容 */
global $post;
$post_title = $post->post_title;
$post_content = apply_filters('the_content', $post->post_content);
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;

/** 用WP_Query获取posts */
$args = array(
	'posts_per_page'       => 50,
	'paged'                => $paged,
	'post_type'            => array( 'post' ), 
	'post_status'          => array( 'publish'),
	'ignore_sticky_posts ' => false,
	'orderby'              => 'date',
	'order'                => 'DESC',
);

$post_list = new WP_Query( $args );
 
get_header(); ?>

	<div id="primary" class="content-area">
		<main id="main" class="site-main" role="main">

			<?php if ( $post_list->have_posts() ) : ?>

				<div class="entry-content">
					<!-- 输出当前页面的标题和写在编辑器里的内容 -->
					<h1><?php echo esc_html($post_title); ?></h1>
					<?php echo $post_content;?>

					<!-- 输出文章列表 -->
					<ul class="article-list">
						<?php while ( $post_list->have_posts() ) : $post_list->the_post(); ?>
							<li>
								<!-- 带连接的文章标题 -->
								<span class="post-title">
									<a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>" target="_blank"><?php the_title(); ?></a>
								</span>
								<!-- 显示评论数 -->							
								<span class="post-comment"><?php comments_number( '', '1条评论', '%条评论' ); ?></span>
								<!-- 显示发布日期 -->
								<span class="post-date"><?php echo esc_html( get_the_date() ); ?></span>
					
							</li>
						<?php endwhile; ?>
					</ul>
					
					<!-- 分页 -->
					<?php sola_pagination($paged, $post_list->max_num_pages); ?>
					
				</div><!-- .entry-content -->
				<!-- 文章列表显示结束 -->
									
			<?php endif; 
			wp_reset_postdata();
			?>

		</main><!-- #main -->
	</div><!-- #primary -->

	<!-- Custom style for this template -->
	<style>
		.article-list li{
		    list-style:none;
		    font-size:1.2rem;
		    display:flex;
		    padding:1rem 0;
		}
		.article-list li + li{
		    border-top:1px solid #c7c7c7;
		}

		.article-list .post-date,
		.article-list .post-comment{
		    margin-left:auto;
		    font-size:.9rem;
		}
		.page-numbers{
		    display:flex;
		    justify-content:center;
		}
		.page-numbers li{
		    list-style:none;
		    padding:1rem;
		    margin:.5rem;

		}
	</style>

<?php

get_footer();

如何使用模板

在后台编辑文章时,输入希望的标题,并从Template/模板列表里选择Article List。

在后台创建WordPress文章列表

保存文章后,访问该页面,就能看到带分页和日期的文章列表,具体样式不同主题会不一样,本文使用了WordPress默认主题测试。

WordPress文章列表前台效果

代码解释

这个模板将所有需要的function都写在一个文件里,不依赖其它文件。

  1. 用注释声明这是一个page模板,模板名称为Article List,了解更多模板知识请参考WordPress官方文档
  2. 定义分页的函数sola_pagination,稍后会在后面调用。
  3. 获取模板页面的标题、内容,可以显示在模板列表之前,并获得当前处于第几页的信息,赋值给$paged变量
  4. WP_Query查询文章,posts_per_page指定每页显示几篇,post_type参数为post,表示只查询posts,你也可以设置为page,或custom post type,或用数组指定多个类型,具体方法参考post type parameters
  5. get_header()开始,进入模板显示环节,所需的php查询都已完成。
  6. 接着有一段自定义css样式,一起写在模板里,因为这些样式只出现在该模板里,inline是最佳方式。
  7. 最后,调用get_footer()函数,模板完成。

方案二:按年分组并带有分页的文章列表

此方案会将文章按照年份来分组,可以一目了然的知道文章属于哪一年,并将其分为两栏显示。使用方法与方案一相同——用模板来创建。

模板代码

<?php
/**
 * Template Name: Article List
 *
 */

// 获取当前页面的标题和内容
global $post;
$post_title   = $post->post_title;
$post_content = apply_filters('the_content', $post->post_content);

// 获取文章列表的分页和数据信息
$paged          = (get_query_var('paged')) ? get_query_var('paged') : 1;
$posts_per_page = 15;
$post_data      = sola_get_posts_by_year( $paged, $posts_per_page );
$post_list      = $post_data[0] ?? false;
$max_page       = $post_data[1] ?? 0;

// 开始显示模板
get_header(); ?>
	<div id="content" class="site-content">
		<div id="primary" class="s-container">

			<div class="entry-content">

				<!-- 输出当前页面的标题和写在编辑器里的内容 -->
				<h1><?php echo esc_html($post_title); ?></h1>

				<?php echo $post_content;?>

				<!-- 输出文章列表 -->
				<?php
				if( is_array($post_list) && sizeof($post_list) ){

					foreach( $post_list as $year => $post_items ){

						echo '<h3 class="article-list__year">',esc_html($year),'</h3>';
						echo '<div class="article-list">';

						foreach( $post_items as $post_item ) {
							sola_render_post_item( $post_item, 'article-list__item' );
						}
						echo '</div>';

					}

				}
				?>
				
				<?php sola_pagination($paged, $max_page); ?>
				
			</div>
		</div>
	</div>

	<!-- 自定义样式 -->
	<style>
		.article-list__year {
		    border-bottom: 2px solid #000;
		}

		.article-list {
		    display: -webkit-box;
		    display: -ms-flexbox;
		    display: flex;
		    -ms-flex-wrap: wrap;
		        flex-wrap: wrap;
		    --spacing: 1em;
		    -webkit-box-pack: justify;
		        -ms-flex-pack: justify;
		            justify-content: space-between;
		}

		.article-list__item {
		    width: calc(50% - var(--spacing));
		    display: -webkit-box;
		    display: -ms-flexbox;
		    display: flex ;
		    margin-bottom: calc(var(--spacing ) * 1.5 );
		    -webkit-box-orient: vertical;
		    -webkit-box-direction: normal;
		        -ms-flex-direction: column;
		            flex-direction: column;
		}

		.article-list__item .post-title {
		    -webkit-box-ordinal-group: 3;
		        -ms-flex-order: 2;
		            order: 2;
		    line-height: 1.7;
		}

		.article-list__item .post-date {
		    color: #666;
		    font-size: 0.68em;
		}

		.page-numbers {
		    padding-left: 0;
		}

		.page-numbers li {
		    display: inline-block;
		    margin: 0 24px 12px 0;
		}
		@media (max-width: 481.9px){
			.article-list__item{
				width: 100%;
			}
		}
	</style>

<?php get_footer(); ?>

<?php
function sola_pagination( $paged = '', $max_page = '' ){
    $big = 999999999; // need an unlikely integer
    if( ! $paged )
        $paged = get_query_var('paged');
    if( ! $max_page )
        $max_page = $wp_query->max_num_pages;

    echo paginate_links( array(
        'base'       => str_replace($big, '%#%', esc_url(get_pagenum_link( $big ))),
        'format'     => '?paged=%#%',
        'current'    => max( 1, $paged ),
        'total'      => $max_page,
        'mid_size'   => 10,
        'prev_text'  => __('«'),
        'next_text'  => __('»'),
        'type'       => 'list'
    ) );
}


function sola_get_posts( $paged = 1, $posts_per_page = 20 ){
	/** 获取该页面的标题和内容 */
	global $post;
	$post_title = $post->post_title;
	$post_content = apply_filters('the_content', $post->post_content);

	/** 用WP_Query获取posts */
	$args = array(
		'posts_per_page'       => absint($posts_per_page),
		'paged'                => $paged,
		'post_type'            => array( 'post' ), 
		'post_status'          => array( 'publish'),
		'ignore_sticky_posts ' => false,
		'orderby'              => 'date',
		'order'                => 'DESC',
	);

	return new WP_Query( $args );
}


function sola_get_posts_by_year( $paged = 1, $posts_per_page = 20 ){

	$post_items = array();
	$post_list = sola_get_posts( $paged, $posts_per_page );
	$max_page = $post_list->max_num_pages;

	if ( $post_list->have_posts() ){
		while ( $post_list->have_posts() ) : $post_list->the_post();

			$year = date('Y', get_post_time());
			$post_item = array(
				'title'     => get_the_title(),
				'permalink' => get_permalink(),
				'year'      => $year,
				'datetime'  => get_the_date(),
			);
			
			$post_items[$year][] = $post_item;

		endwhile;
	}

	wp_reset_postdata();

	return [$post_items, $max_page];
}

function sola_render_post_item( $post_item , $item_class ){
	if( $item_class ){
		$item_class = 'class="'.esc_attr($item_class).'"';
	}
	?>
	<div <?php echo $item_class; ?>>
		<!-- 带连接的文章标题 -->
		<span class="post-title">
			<a href="<?php echo esc_url($post_item['permalink']) ?>" 
			   title="<?php printf( '%s发布于%s', esc_attr($post_item['title']), esc_html( $post_item['datetime']) ); ?>" 
			   target="_blank">
			   <?php echo esc_html($post_item['title']); ?>
			</a>
		</span>
		
		<!-- 显示发布日期 -->
		<span class="post-date"><?php echo esc_html( $post_item['datetime']); ?></span>

	</div>

	<?php
}

代码解释

将需要调用的php函数放到结尾,方便查阅模板主体逻辑。分组原理是按照时间由晚到早的顺序查询posts,每页查询数量由变量$posts_per_page决定,遍历查询结果时,提取文章的年份,并创建一个key为年份,value为属于该年的文章组成的数组,最后循环输出这个数组的内容即可。

效果展示

使用WordPress默认的Twenty Twenty-One模板测试。

带分页并按年份归档的文章列表

37条评论

    1. 在某个页面显示某个年份的文章列表,直接使用date archive页面就可以。请问你说的文章列表分开具体是什么样的功能?可否详细描述一下页面结构。

      1. 就是归档页面文章列表前加一个年份的总数,比如2022年共多少篇,然后以下是2022年的文章,2021年共多少,以下就是2021年的文章列表,可以把文章列表稍微区分开来,感谢TvT

        1. 想法很有趣,按照你的设计,似乎需要在一个页面显示所有post,如果post很多会有性能问题,关于分页怎么处理,是否有好的想法可以分享一下?

          我的一种想法是显示所有年份归档,但每个年份只显示几篇文章,后面带个到WordPress默认year archive的链接。也可以是load more 按钮,点击后就加载更多这个年份里的文章。

          如果post数量不多,一次全部显示页没问题。不知道你是怎么想的。

    1. 把上面的代码改成shortcode,再将shortcode插入文章即可。
      shortcode的用法参考文档https://codex.wordpress.org/Shortcode_API

      本文介绍的代码部分是跟模板相关的,需要去掉,具体来说从new WP_Query开始到wp_reset_query()之间的代码是你需要的。

  1. 谢谢分享!
    在每5篇文章中间加一条横线分割,列表页看起来更美观,该怎样实现?求指教

  2. 我这样写代码,调用的是所有分类的文章,分页不生效,是什么原因,请高人指点,

  3. 你好!
    确实蛮好用的,但是为什么只有第一页和第二页可以正常打开,后面的都的页面都是显示未找到页面。

  4. HI, sola, 能不能实现单击标题后出现下拉的 文章摘要,如果真的想详细阅读,再点 read more.. 才进入文章呢?

    1. 用jquery实现很简单啊,模版一般都会输出摘要吧,你用jquery把摘要隐藏了,给标题绑定click事件,点击的时候显示摘要就行了啊

      1. 弄了好久…不知道怎么隐藏摘要,在外部能用toggle()实现对某个标签隐藏,显示,但是wordpress里就不行了;
        Sola能不能留个邮箱不?求指教

        1. WordPress里的jquery要用jQuery来代替$符号,你用对了吗
          装firebug,用控制台看js报错

    1. 如果要显示所有页面,改一下WP Query的查询参数post_type即可,默认是post,页面的话就是page

      $post_list = new WP_Query(
          "posts_per_page=" . $posts_per_page .
          "post_type=page" .
          "&orderby=" . $order_by .
          "&order=" . $order .
          "&cat=" . $cat .
          "&paged=" . $paged
      );
    1. 有三种方法

      1. 用WP Query

      $total_posts = new WP_Query( "posts_per_page=-1&cat=-59,-58,-4");
      echo 'Total posts:'. $total_posts->post_count;
      wp_reset_postdata();

      -59,-58,-4就是要排除的分类ID,前加负号,用逗号分隔

      2. 用get_posts

      $total_posts = get_posts('posts_per_page=-1&cat=-59,-58,-4');
      echo 'Total posts:'. count($total_posts);

      ID使用方法同上

      3. 用$wpdb执行自定义查询

      global $wpdb;
      //$exclude_ids定义要排除的分类ID,用逗号分隔
      $exclude_ids = '59,58,4';
      $sql = <<<SQL
      SELECT   COUNT(*) 
      FROM  {$wpdb->posts} 
      WHERE 1=1
      	AND post_type = 'post'
      	AND ( post_status = 'publish' OR post_status = 'private') 
      	AND {$wpdb->posts}.ID NOT IN (
      	  SELECT object_id
      	  FROM $wpdb->term_relationships
      	  WHERE term_taxonomy_id IN (
      	  	SELECT term_taxonomy_id 
      		FROM $wpdb->term_taxonomy
      		WHERE taxonomy = 'category'
      		AND ( term_id IN( {$exclude_ids} ) OR parent IN ( {$exclude_ids} ) )
      	  )
      	)
      SQL;
      $numposts = $wpdb->get_var($sql);
      echo 'Total posts:'. $numposts;

      对比

      前两种方法虽然函数不同但其实都调用了WP Query,文章越多消耗的内存越大,如果文章非常多前两种方法会很耗资源。

      第三种方法直接执行了自定义的SQL语句,基本不消耗什么内存,速度较快

        1. 对了,忘了告诉你,如果你是在文章列表中排除了某些分类,那获取文章总数有更简单的方法,直接这样就可以

          $total_posts = $post_list->found_posts;

          WP Query在查询的时候会顺带查询总数,如果已经查询了带分页的文章列表,用这种方法比第三种更好

  5. 此文早些出炉就会免掉很多麻烦了,嗯,话说你的文章列表的文章热度效果不错,具体如何实现的呢?

留言

您的电子邮箱地址不会被公开。