Как я переносил свой блог с modx на grav

Когда-то давно я решил создать для себя сайт, на котором я бы выкладывал свои мысли, статьи и прочую ерунду, которая по большему счету полезна именно мне. В первую очередь мне хотелось писать все свои статьи на markdown. На тот момент самым лучшим решением для этой задачи я считал cms modx, она достаточно гибкая, мощная, позволяет достаточно быстро разработать полностью рабочий сайт, а в репозитории уже было готовое решение для написания контента на markdown. Больше, в принципе, мне и не надо было. Шли годы, писал я статьи не так часто, как думал, в modx появился шаблонизатор fenom, а мое видение того, как должен выглядеть мой сайт достаточно сильно изменилось, больше я не мог смотреть на то, как выглядит этот сайт изнутри и как происходит процесс публикации материалов. Пришло время переписывать сайт.

Вид статьи на cms modx

Переписывать снова сайт на modx я не хотел из-за того, что все ресурсы modx хранятся в mysql, а мне хотелось писать текст статьи в файле .md и сразу его выводить на сайт, плюс хотел попробовать на практике другую cms, надо же увеличивать свой кругозор🙂. В чате october cms я задал вопрос, есть ли в данной cms возможность комфортной работы с файловыми ресурсами, на это мне ответили, что мне лучше пересмотреть свою задачу, так как решение "всё хранить в файлах" достаточно глупое. Но мне всё равно кажется, что именно так должна выглядеть для меня идеальная cms для блога😄. Далее мой взор упал на генератор сайтов jekyll, достаточно крутая вещь и используя её можно было бы обойтись без хостинга, а хранить все ресурсы на github, но используя jekyll я не нашел решения, как считать просмотры страниц. Далее я просмотрел еще множество плоских систем управления сайтом (flat cms) и остановился на grav cms.

Вид статьи на cms grav

Grav CMS

Grav CMS - это то самое решение, как я представлял работу моего сайта, чтобы использовать эту cms не требуется mysql сервер, а бекап->перенос сайта с локальной машины на боевую занимает несколько действий:

  1. Перенести архив с бекапом на хостинг.
  2. Распаковать архив.

Все дополнения распространяются в виде плагинов, и даже административная панель представляет собой отдельный плагин, можно вообще не устанавливать админку для сайта и все настройки и установки производить через консоль.

В grav используется шаблонизатор twig, из коробки есть поддержка composer, шаблоны сайта представляют собой отдельные темы, что позволяет обновлять дизайн сайта кликом по нужной теме, также и кастомизация тем и работа с шаблонизатором не вызовут больших вопросов, тем более, если ранее уже был опыт с тем же fenom.

Файловая структура

Все настройки системы и плагинов хранятся в .yaml файлах, например, настройки безопасности находятся в /system/blueprints/config/security Файл настройки безопасности grav cms

Все страницы находятся в директории /user/pages, перейдя по этому пути можно увидеть список папок вида 01.home, 01 - это параметр сортировки, для отображения ссылок в меню home - это алиас для формирования ссылки, перейдя в директорию ресурса мы обнаружим список изображений и файл вида index.md, index - это название шаблона отображения страницы.

Процесс публикации

Например, добавим новую статью на сайт. Заходим в /user/pages/02.articles и создаем папку 99.new-article, переходим в нее, создаем в ней файл page.md и открываем его. Внутри этого файла для успешной публикации надо задать настройки, они имеют следующий вид:

---
title: 'Название статьи'
media_order: name.jpg
published: true
date: '13-01-2019 12:00'
publish_date: '13-01-2019 12:00'
metadata:
    keywords: 'ключ, ключ, ключ'
    description: 'текст текст текст'
---

Пройдемся по порядку:

  • title - Заголовок страницы;
  • media_order - список изображений, которые используются на данной странице и находятся в этой же директории;
  • published - статус публикации;
  • date - дата создания;
  • publish_date - дата публикации;
  • metadata - список мета-данных и их значений.

Можно также создавать ресурсы используя визуальный редактор:

Создание ресурса из админки grav cms

После заполнения всех данных пишем основной контент в формате markdown сразу после ---. Сохраняем полученную статью и теперь она доступна по адресу site-name.site/articles/new-article. Ура! 🎉🎉🎉

Как видите, всё достаточно просто))

Перенос сайта с modx на grav 👨‍🚀

Теперь опишу немного сам процесс переноса сайта. Так как в основном необходимо было создать файлы в нужной форме, которые бы стразу понял grav, мне потребовалось написать в modx сниппет, который создает папки с именем-алиасом ресурса, внутри них добавляет .md файлы с названием шаблонов страниц, внутри которых помещает контент ресурсы и спарсит все необходимые поля. Реализовал я это следующим способом (кстати, при должной сноровки данный код можно оптимизировать на перенос сайта с modx и в другую cms):

<?php
$id_parent = 2;                                                                 // id родителя
$name_file = 'page.md';                                                         // имя файла, это имя шаблона в grav
$path_base = MODX_BASE_PATH.'/assets/articles/';                                // путь до папки куда делать экспорт
$tpl = $modx->getOption('tpl', $scriptProperties, 'tpl_to_grav');               // tpl_to_grav - имя чанка для формирования содержания файла
$resources = $modx->getCollection('modResource',[ 'parent' => $id_parent ]);    // получаем коллекцию ресурсов

foreach ($resources as $k => $res) {
    $name_dir = $res->id.'.'.$res->alias;                   // устанавливаем имя папки, по типу id.alias
    $path_dir = $path_base.$name_dir;                       // путь к папке
    $path_file = $path_dir.'/'.$name_file;                  // путь к файлу с контентом
    
    mkdir($path_dir, 0755);                                 // создаем папку
    
    $arr_out = $res->toArray();                             // переводим значения в массив
    $tv_img = MODX_BASE_PATH.$res->getTVValue('img');       // получаем полный путь к изображению превью (тв img)

    // копируем превью в папку
    if (!copy($tv_img, $path_dir.'/'.basename($tv_img))) {
        $arr_out['img'] = '';
    } else {
        $arr_out['img'] = basename($tv_img);
    }

    // получаем тв, которые нужно перенести
    $arr_out['keywords'] = $res->getTVValue('seo_key');
    $arr_out['description'] = $res->getTVValue('seo_desc');
    
    // получаем выходные значения контента из чанка
    $content_file = $modx->getChunk($tpl, $arr_out);
    
    // создаем и записываем данные в файл
    if (!file_exists($path_file)) {
        $fp = fopen($path_file, "w");
        fwrite($fp, $content_file);
        fclose($fp);
    }
}
?>

А чанк самой страницы выглядит вот так:

---
title: [[+pagetitle]]
media_order: [[+img]]
published: true
date: [[+publishedon:strtotime:date=`%d-%m-%Y %R`]]
publish_date: [[+publishedon:strtotime:date=`%d-%m-%Y %R`]]
metadata:
    keywords: '[[+keywords]]'
    description: '[[+description]]'
---

[[+content]]

Далее остается только перенести полученные данные в директорию /user/pages/02.articles, открыть страницы в браузере и проверить, что всё корректно перенеслось и что какая-нибудь картинка, про которую давно забыл, не лежит в совершенно другой папке))).

Затем нужно было разработать тему для сайта, мне понравилась стандартная тема Quark, откопировал её и переделал под тот вид, который можете наблюдать прямо сейчас💣.

Плагины 🛠

В процессе настройки я нашел в официальном репозитории все плагины, которые мне нужны:

  • Count Views - Подсчет просмотров страницы (кстати, все просмотры, которые были в modx на тиккетах, очень просто было перенести в yaml разметку).
  • Anchors - Добавляет якори к заголовкам на странице, что позволяет отправлять ссылку на нужную часть статьи.
  • Highlight - Подсветка кода.
  • Pagination - Для пагинации страниц.
  • Image Captions - Добавляет подписи к картинкам.
  • Markdown Font Awesome - Для вставки Font Awesome иконок используя markdown.
  • Sitemap - Генерация sitemap.xml.

Пару слов в конце статьи 🙊

Опыт в работе с Grav CMS мне очень понравился, система молниеносно-быстрая, современная, постоянно развивается сообществом. Надеюсь кто-то всёже дочитает данную статью до конца и она ему будет полезной🤓.