Чому стандартні плагіни jekyll далекі від ідеалу

У цій статті я не буду наводити повний код для всіх компонентів, тільки дам сніпети та підказки, на що варто звернути увагу при складанні сайту на jekyll.

Jekyll Structured Data and sitemap.xml 1535x697 jekyll-structured-data-sitemap-and-nginx.png
Jekyll Structured Data and sitemap.xml

Час модифікації файла

Кожна сторінка має щонайменше три точки відображення позначки часу в різних файлах, елементах сторінки або відповіді сервера, і всі вони повинні бути однаковими.

  • ld+json "dateModified": "2025-03-07T15:43:42+00:00"
  • sitemap <lastmod>2025-03-07T15:43:42+00:00</lastmod>
  • headres last-modified: Fri, 07 Mar 2025 15:43:42 GMT

Почнемо з sitemap.xml, у стандартному jekyll-sitemap, для сторінок page, які на цьому сайті використовуються для виведення collections, час зміни береться з часу зміни файлу.
Тобто для сторінки https://webart4.me/en/linux/blog/
буде встановлено час зміни файлу /categories/en/blog.md:
{{ page.last_modified_at | date_to_xmlschema }}, а це не зовсім правильно.

Тому що, при модифікації, а головне при додаванні нової публікації в цій категорії (колекції), час зміни так і залишиться незмінним, хоча на сторінці буде новий контент.

Тому, вибираємо всі публікації для даної локалі, потім ті, які відносяться до цієї категорії, сортуємо за датою, вибираємо найновішу.

1
2
3
4
5
6
{% assign new_posts = site.posts | where_exp:"post", "post.locale == 'en'" | where_exp:"post", "post.categories contains 'blog'" | sort: "last_modified_at" | reverse | first | default: "notfound" %}
{% if new_posts != "notfound" %}
    <lastmod>{{ new_posts.last_modified_at | date_to_xmlschema }}</lastmod>
{% else %}
    <lastmod>{{ page.last_modified_at }}</lastmod>
{% endif %}

Відповідно, для генерації Structured Data буде така сама логіка.

Відповідь сервера Last-Modified

Тут вже цікавіше.

При пересборі сайту jekyll build --destination файли будуть оновлені. Навіть якщо використовувати --incremental, все одно не вдасться перенести коректні атрибути файлів, враховуючи, що для деяких файлів вони повинні мати генеровані значення.

Для цього використовуємо витончений та простий скрипт, який має запускатися після кожного деплою на сервері.

nano touch_files.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/bin/bash

OPTS=`getopt -o D: --long dir: -n 'parse-options' -- "$@"`
if [ $? != 0 ] ; then
  echo "Failed parsing options." >&2
  exit 1
fi
eval set -- "$OPTS"
while true; do
  case "$1" in
    -D | --dir )                DIR="$2"; shift 2 ;;
    -- ) shift; break ;;
    * ) break ;;
  esac
done

domain="https://webart4.me"

if [[ -f "${DIR}/sitemap.xml" ]]; then
    I=`cat ${DIR}/sitemap.xml | grep -E "<loc>" | wc -l`
    for ((i = 1; i <= "${I}"; i++)) ; do
        location=`/usr/bin/xmllint --xpath "string(//*[local-name()='url'][${i}]/*[local-name()='loc'])" ${DIR}/sitemap.xml`
        ifile="${location##$domain}"
        is_html="${ifile##*html}"
        if [[ ! -z "$is_html" ]]; then
                ifile="${ifile}index.html"
        fi
        ds=`/usr/bin/xmllint --xpath "string(//*[local-name()='url'][${i}]/*[local-name()='lastmod'])" ${DIR}/sitemap.xml`
        if [[ -f "${DIR}${ifile}" ]]; then
                printf '%s\n' "${i}   ${DIR}${ifile}"
                touch --date="${ds}" ${DIR}${ifile}
        else
                printf '%s\n' "file error   ${DIR}${ifile}"
        fi
    done
else
    printf '%s\n' "No sitemap.xml"
    exit 0
fi
1
2
/bin/bash ${path_to_script}/touch_files.sh --dir ${site_root_dir_with_sitemapxml}
  

Скрипт парсить sitemap.xml, і для всіх файлів з <loc> встановлює <lastmod>.