Jekyll/Liquid 模板:如何按年份对博客文章进行分组?

Posted

技术标签:

【中文标题】Jekyll/Liquid 模板:如何按年份对博客文章进行分组?【英文标题】:Jekyll/Liquid Templating: How to group blog posts by year? 【发布时间】:2013-10-05 20:20:56 【问题描述】:

我正在重写我的博客以使用 Jekyll。 Jekyll 使用 Liquid 模板语言,因此学习如何自定义变得更加困难。

我想按年份对我的博客文章列表进行分组。我将如何编写 Liquid 代码才能做到这一点?

% for post in site.posts %
  <li><!-- display post year here (but only once, per year) --></li>
  <li>
    <a href=" post.url "> post.title </a>
  </li>
% endfor %

【问题讨论】:

它涉及或涉及捕获,非常可怕。 mikerowecode.com/2010/08/jekyll_archives_grouped_by_year.html 【参考方案1】:

它可以用比现有答案少得多的 Liquid 代码来完成:

% for post in site.posts %
  % assign currentdate = post.date | date: "%Y" %
  % if currentdate != date %
    <li id="ycurrentdate"> currentdate </li>
    % assign date = currentdate % 
  % endif %
    <li><a href=" post.url "> post.title </a></li>
% endfor %

这将完全返回您问题中指定的 HTML:

<li id="y2013">2013</li>
<li><a href="/2013/01/01/foo/">foo</a></li>
<li id="y2012">2012</li>
<li><a href="/2012/02/01/bar/">bar</a></li>
<li><a href="/2012/01/01/baz/">baz</a></li>

但是,这不是最佳解决方案,因为年份数字也是“唯一”列表项。 将年份放入标题并为每年的帖子开始一个新的&lt;ul&gt; 的 Liquid 代码并不多:

% for post in site.posts %
  % assign currentdate = post.date | date: "%Y" %
  % if currentdate != date %
    % unless forloop.first %</ul>% endunless %
    <h1 id="ypost.date | date: "%Y""> currentdate </h1>
    <ul>
    % assign date = currentdate %
  % endif %
    <li><a href=" post.url "> post.title </a></li>
  % if forloop.last %</ul>% endif %
% endfor %

生成的 HTML:

<h1 id="y2013">2013</h1>
<ul>
<li><a href="/2013/01/01/foo/">foo</a></li>
</ul>
<h1 id="y2012">2012</h1>
<ul>
<li><a href="/2012/02/01/bar/">bar</a></li>
<li><a href="/2012/01/01/baz/">baz</a></li>
</ul>

您也可以改为按月和年分组(因此标题为February 2012January 2012 等)。

为此,您只需将date: "%Y"(在上述两个示例的第二行)替换为date: "%B %Y"%B 是完整的月份名称,见documentation)

【讨论】:

这太好了,谢谢!需要注意的是,您不会为最后一组创建最终的 。因此,在 for 循环之后,您需要在 for 循环之后执行 % if site.posts.size != 0 %% endif % 之类的操作。 或者就在循环结束之前,% if forloop.last %% endif %。 我想补充一点,其他解决方案对我不起作用,因为我的帖子不一定按日期排序,但是这个解决方案可以!谢谢! 这篇文章很棒。我设法使它适应我的情况。我对它的工作原理感到困惑 - 任何人都可以用 Liquid 代码中的 cmets 更新这个答案吗? 除了年月外,还能显示发帖数吗?【参考方案2】:

如果你想按年份细分,代码如下:

% for post in site.posts  %
    % capture this_year % post.date | date: "%Y" % endcapture %
    % capture next_year % post.previous.date | date: "%Y" % endcapture %

    % if forloop.first %
    <h2 id=" this_year -ref">this_year</h2>
    <ul>
    % endif %

    <li><a href=" post.url "> post.title </a></li>

    % if forloop.last %
    </ul>
    % else %
        % if this_year != next_year %
        </ul>
        <h2 id=" next_year -ref">next_year</h2>
        <ul>
        % endif %
    % endif %
% endfor %

如果您想将其分解为年和月,可以这样实现:

% for post in site.posts  %
    % capture this_year % post.date | date: "%Y" % endcapture %
    % capture this_month % post.date | date: "%B" % endcapture %
    % capture next_year % post.previous.date | date: "%Y" % endcapture %
    % capture next_month % post.previous.date | date: "%B" % endcapture %

    % if forloop.first %
    <h2 id=" this_year -ref">this_year</h2>
    <h3 id=" this_year - this_month -ref"> this_month </h3>
    <ul>
    % endif %

    <li><a href=" post.url "> post.title </a></li>

    % if forloop.last %
    </ul>
    % else %
        % if this_year != next_year %
        </ul>
        <h2 id=" next_year -ref">next_year</h2>
        <h3 id=" next_year - next_month -ref"> next_month </h3>
        <ul>
        % else %    
            % if this_month != next_month %
            </ul>
            <h3 id=" this_year - next_month -ref"> next_month </h3>
            <ul>
            % endif %
        % endif %
    % endif %
% endfor %

这只是你在哪里进行循环切割的问题。

【讨论】:

这可以与 site.categories.xxx 一起使用吗?【参考方案3】:

这些以前的解决方案非常棒,但幸运的是,在 2016 年末,Jekyll added a group_by_exp 过滤器可以更干净地做到这一点。

% assign postsByYear =
    site.posts | group_by_exp:"post", "post.date | date: '%Y'" %
% for year in postsByYear %
  <h1> year.name </h1>
    <ul>
      % for post in year.items %
        <li><a href=" post.url "> post.title - post.date </a></li>
      % endfor %
    </ul>
% endfor %

可以在Jekyll Templates page 上找到文档。

【讨论】:

是否可以使用 site.data 而不是帖子来做到这一点?例如,我有 10 组数据,所有数据都包含一个数据变量,它们位于我想像这样循环的 3 个日期内。还是只有嵌套的液体循环才有可能?谢谢! 是的,您可以使用相同的技术对任何数组进行分组:% assign groupedData = site.data | group_by_exp: "data", "data.yourVariable" % 感谢您的出色回答。如果您使用的是较新版本的 Jekyll,这绝对是您的必经之路。【参考方案4】:

上面的一些解决方案非常复杂,但正如 @Trevor 指出的那样,我们可以利用 Jekyll 的 group_by_exp 过滤器。我也喜欢这个解决方案,但我需要的是按年分组,然后在按月分组的列表中。所以,我稍微调整了一下。

% assign postsByYear = site.posts | group_by_exp:"post", "post.date | date: '%Y'" %
    % for year in postsByYear %
      <h1> year.name </h1>
      % assign postsByMonth = year.items | group_by_exp:"post", "post.date | date: '%B'" %

      % for month in postsByMonth %
        <h2> month.name </h2>
        <ul>
          % for post in month.items %
            <li><a href=" post.url "> post.title - post.date </a></li>
          % endfor %
        </ul>

      % endfor %
    % endfor %

【讨论】:

【参考方案5】:

试试:

% for post in site.posts  %
  % capture this_year % post.date | date: "%Y" % endcapture %

  % if forloop.first %
  <h2 id=" this_year -ref">this_year</h2>
  <ul class="posts">
  % else %
      % if this_year != last_year %
      </ul>
      <h2 id=" this_year -ref">this_year</h2>
      <ul class="posts">
      % endif %
  % endif %

    <li>
      <span class="post-date"> post.date | date_to_string  &raquo;</span>
      <a href=" post.url "> post.title </a>
    </li>

  % if forloop.last %
    </ul>
  % endif %

  % capture last_year % this_year % endcapture %
% endfor %

【讨论】:

【参考方案6】:
<ul>
  % for post in site.posts %
      % assign year = post.date | date: "%Y" %

      % if year != prev_year %
        <h3>year</h3>
      % endif %

      <li>
        <span> post.date | date: "%B %e, %Y" </span>
        <a href=" post.url "> post.title </a>
      </li>
      % assign prev_year = year %
  % endfor %
</ul>

【讨论】:

【参考方案7】:

不太喜欢其他答案,所以这里有一个替代方案。基本逻辑:只有“新”时才显示年/月:

% assign var currentYear = 0 %
% assign var currentMonth = 0 %
% for post in site.posts  %
% capture year % post.date | date: "%Y" % endcapture %
% capture month % post.date | date: "%B" % endcapture %

% if currentYear != year %
<div>
  <h2> year </h2>
</div>
% assign var currentYear = year %
% endif %
% if currentMonth != month %
<div>
  <h3> month </h3>
</div>
% assign var currentMonth = month %
% endif %
<p> post.title </p>
% endfor %

【讨论】:

【参考方案8】:

Ankit R Gadiya 的 answer 的变体。内部的for 循环正在显示html 代码。我需要取消缩进以使其正确呈现标记。我还添加了帖子的摘录:

% assign postsByYear = site.posts | group_by_exp:"post", "post.date | date: '%Y'" %
% for year in postsByYear %
  <h1> year.name </h1>
  % assign postsByMonth = year.items | group_by_exp:"post", "post.date | date: '%B'" %

% for month in postsByMonth %
<h2> month.name </h2>
<ul>
  % for post in month.items %
    <li>
      <a href=" post.url "> post.title </a>
      <br> post.excerpt 
    </li>
  % endfor %
</ul>

% endfor %
% endfor %

例子:

【讨论】:

以上是关于Jekyll/Liquid 模板:如何按年份对博客文章进行分组?的主要内容,如果未能解决你的问题,请参考以下文章

Jekyll/Liquid - 如何将大块文本添加到 YAML 前端?

html 条形图Jekyll LIquid for JSON

在 Jekyll/Liquid 和 pygments 的 html 问题中突出显示

检查带有/ Jekyll Liquid 的页面上是不是存在带有/ class x 的 div

生成 Jekyll Liquid 内容而不包含它(仅来自 JQuery 加载函数)

如何按年份进行分组?