Как сделать закрепленную запись в Jekyll
Закрепленное сообщение – это специальная опция, позволяющая выдернуть запись из хронологического порядка и разместить её выше всех остальных. В этой заметке я со всей серьезностью расскажу, как это можно сделать без плагинов. Большим (ударение на первую гласную) издевательством над здравым смыслом могла бы стать только статья о том, как нечто подобное реализовать при помощи плагинов, которые, как не странно, существуют. Я начинаю. Надеюсь, поисковым роботам понравится.
В водной части поста нам потребуется переменная, которая будет служить указателем (флагом) для сборщика проекта. Я бы назвал эту переменную pinned_post. Логично предположить, что значением это переменной будет либо true, либо false. Т.е., отображать пост в качестве закрепленного сообщения, либо вернуть его на свое законное место с точки зрения хронологии.
В качестве примера:
---
title: Заголовок, который отображается во вкладке браузера
description: Описание для поискового робота
header: Заголовок поста
category: [Название категории]
tags: [тэг1, тэг2 и т.д.]
pinned_post: true
---
Здесь, соответственно, текст вашей статьи…
...
...
Сейчас наше сообщение помечено, как «закрепленное». Приступим к реализации функционала, который каждое такое сообщение отобразит поверх других сообщений.
Нам нужно найти основной цикл, отвечающий за вывод постов. Чаще всего он находится в корне проекта в index.html.
Выглядит он приблизительно так:
---
layout: default
---
<ul id="posts">
{% for post in paginator.posts %}
<li class="post">
<h2 class="main-heading">
<a href="{% if site.baseurl == "/" %}{{ post.url }}{% else %}{{ post.url | prepend: site.baseurl }}{% endif %}">
{%if post.header %}{{ post.header }}{% else %}{{ post.title }}{% endif %}
</a>
</h2>
<time datetime="{% include date.html date=post.date %}" class="by-line"><i>{% include date.html date=post.date %}</i></time>
<p>
{% if post.content contains '<!--section.start-->' and post.content contains '<!--section.end-->' %}
{{ ((post.content | split:'<!--section.start-->' | last) | split: '<!--section.end-->' | first) | strip_html | truncatewords: 50 }}
{% else %}
{{ post.content | strip_html | truncatewords: 50 }}
{% endif %}
</p>
<span>{% if post.excerpt != post.content %}<a href="{{ site.baseurl }}{{ post.url }}" class="more">Читать далее →</a>{% endif %}</span>
</li>
{% endfor %}
</ul>
Для удобства предлагаю основную часть разметки перенести в отдельный файл, закинуть его в каталог _includes и при помощи стандартной Liquid конструкции подключить её (разметку) в наш цикл.
Вот что я имею ввиду:
---
layout: default
---
<ul id="posts">
{% for post in paginator.posts %}
<li class="post">
{% include post_preview.html %}
</li>
{% endfor %}
</ul>
Согласитесь, что так гораздо нагляднее.
Немного теории: небольшие фрагменты кода мы можем выносить в отдельные файлы, для того чтобы вместо огромной портянки работать с одной строкой. Делается это при помощи стандартного оператора include, встроенного шаблонизатора Liquid. Это очень удобно, особенно если один и тот же фрагмент необходимо использовать в разных местах сайта.
Все подключаемые файлы должны находится в каталоге _includes. Jekyll именно там их и будет искать.
Следующий шаг:
---
layout: default
---
<ul id="posts">
{% for post in site.posts %}
{% if post.pinned_post == true %}
<li class="post">
<span class="pinned_post">Закрепленное сообщение</span>
{% include post_preview.html %}
</li>
{% endif %}
{% endfor %}
{% for post in paginator.posts %}
{% unless post.pinned_post == true %}
<li class="post">
{% include post_preview.html %}
</li>
{% endunless %}
{% endfor %}
</ul>
Делаем копию нашего основного цикла и помещаем её сверху. Внутри этого цикла добавляем проверку и какой-нибудь HTML элемент сообщающий читателю о том, что данное сообщение закреплено. В нижнем цикле (в основном) при помощи оператора unless мы избавляемся от выбранной в качестве прикрепленного сообщения заметки. Потому что две копии одного и того же материала нам на сайте ни к чему.
И снова немного теории: на if и for я останавливаться не буду, т.к. что смысл этих операторов вам разумеется известен. А вот про предопределенные переменные немного напишу. Дело в том, что список всех постов нашего блога хранится в переменной site.posts. Поэтому будьте внимательнее, верхний цикл у нас должен быть: {% for post in site.posts %}, нижний: {% for post in paginator.posts %} В paginator.posts попадают посты доступные конкретно этой странице из всей пагинации.
Оператор unless – это логическая конструкция шаблонизатора Liquid. Данный оператор предусмотрен для проверки условия на отрицание. Т.е., если post.pinned_post НЕ является true, условие будет выполнено. И наоборот.
В самом конце желательно добавить дополнительную проверку, при помощи которой мы убедимся, что работаем с первой страницей списка. Если этого не сделать, то на каждом листе сайта, сформированных пагинатором, будет висеть материал выбранный в качестве закрепленного сообщения.
В итоге должно получиться:
---
layout: default
---
<ul id="posts">
{% if paginator.previous_page == nil %}
{% for post in site.posts %}
{% if post.pinned_post == true %}
<li class="post">
<span class="pinned_post">Закрепленное сообщение</span>
{% include post_preview.html %}
</li>
{% endif %}
{% endfor %}
{% endif %}
{% for post in paginator.posts %}
{% unless post.pinned_post == true %}
<li class="post">
{% include post_preview.html %}
</li>
{% endunless %}
{% endfor %}
</ul>
Я сделал эту проверку привычным для себя способом. Наверное, её можно сделать как-то иначе. Например, так: {% if page.url == “/” %} Если честно, я этот вариант не проверял. Думаю, что будет работать. Куда-ж оно денется? ))
Задача решена. Как видите, всё оказалось довольно просто и никакие плагины здесь ни к чему.
Издевательством над здравым смыслом законченно. Удачного блоггинга!