Разработка сайта на CMS Kirby
Kirby — файловая CMS на PHP без базы данных. Контент хранится в папках и текстовых файлах, шаблоны — чистый PHP, панель управления встроена и работает из коробки. Хорошо подходит для корпоративных сайтов, портфолио, блогов, небольших каталогов — там, где нужна простая эксплуатация без MySQL и миграций.
Структура проекта
site/
├── blueprints/ # схемы полей панели
│ ├── pages/
│ └── files/
├── collections/ # переиспользуемые наборы страниц
├── config/ # конфигурация, хуки, маршруты
├── models/ # расширенные модели страниц
├── plugins/ # сторонние и кастомные плагины
├── snippets/ # переиспользуемые части шаблонов
├── templates/ # шаблоны страниц
└── controllers/ # логика перед рендерингом
content/
├── home/
│ └── home.txt
├── about/
│ └── about.txt
└── blog/
├── blog.txt
├── 2024-01-15_first-post/
│ └── article.txt
└── 2024-02-20_second-post/
└── article.txt
Шаблонная система
Kirby сопоставляет шаблон по имени файла контента. Файл article.txt → шаблон templates/article.php:
<?php snippet('header') ?>
<article class="post">
<header>
<h1><?= $page->title()->html() ?></h1>
<time datetime="<?= $page->date()->toDate('Y-m-d') ?>">
<?= $page->date()->toDate('d.m.Y') ?>
</time>
</header>
<div class="content">
<?= $page->text()->kirbytext() ?>
</div>
<?php if ($page->tags()->isNotEmpty()): ?>
<footer class="tags">
<?php foreach ($page->tags()->split() as $tag): ?>
<a href="<?= $site->url() ?>/blog/tag:<?= $tag ?>">
<?= html($tag) ?>
</a>
<?php endforeach ?>
</footer>
<?php endif ?>
</article>
<?php snippet('footer') ?>
Blueprints — схемы полей
Blueprint описывает, какие поля доступны редактору для каждого типа страницы:
# site/blueprints/pages/article.yml
title: Статья
columns:
main:
width: 2/3
sections:
content:
type: fields
fields:
title:
type: text
label: Заголовок
required: true
text:
type: writer
label: Текст статьи
inline: false
marks:
- bold
- italic
- link
- code
cover:
type: files
label: Обложка
max: 1
query: page.images
sidebar:
width: 1/3
sections:
meta:
type: fields
fields:
date:
type: date
label: Дата публикации
default: today
tags:
type: tags
label: Теги
seo_description:
type: textarea
label: SEO-описание
maxlength: 160
Контроллеры
Контроллер отделяет логику от шаблона:
<?php
// site/controllers/blog.php
return function ($page, $site) {
$tag = param('tag');
$articles = $page->children()
->listed()
->when($tag, fn($pages) => $pages->filterBy('tags', $tag, ','))
->sortBy('date', 'desc')
->paginate(12);
return [
'articles' => $articles,
'pagination' => $articles->pagination(),
'activeTag' => $tag,
'allTags' => $page->children()->listed()->pluck('tags', ',', true),
];
};
Шаблон blog.php получает $articles, $pagination и $activeTag как готовые переменные.
Модели страниц
Когда нужно добавить методы к конкретному типу страниц:
<?php
// site/models/article.php
class ArticlePage extends Page
{
public function readingTime(): int
{
$words = str_word_count(strip_tags($this->text()->kirbytext()));
return (int) ceil($words / 200);
}
public function isNew(): bool
{
return $this->date()->toDate('U') > strtotime('-30 days');
}
public function relatedArticles(int $limit = 3): Pages
{
$tags = $this->tags()->split();
return $this->siblings()
->listed()
->not($this)
->filter(function ($article) use ($tags) {
return count(array_intersect(
$article->tags()->split(),
$tags
)) > 0;
})
->sortBy('date', 'desc')
->limit($limit);
}
}
В шаблоне: <?= $page->readingTime() ?> мин чтения.
API и безголовый режим
Kirby отдаёт JSON из коробки — достаточно добавить расширение к URL:
GET /blog.json
GET /blog/first-post.json
Или настроить кастомные маршруты:
// site/config/config.php
return [
'api' => true,
'routes' => [
[
'pattern' => 'api/articles',
'action' => function () {
$articles = page('blog')
->children()
->listed()
->sortBy('date', 'desc')
->limit(20);
return [
'data' => $articles->toArray(function ($article) {
return [
'id' => $article->id(),
'title' => $article->title()->value(),
'date' => $article->date()->toDate('Y-m-d'),
'excerpt' => $article->text()->excerpt(200),
'url' => $article->url(),
];
}),
];
},
],
],
];
Медиа и изображения
<?php if ($cover = $page->cover()->toFile()): ?>
<img
src="<?= $cover->crop(800, 450)->url() ?>"
srcset="
<?= $cover->crop(400, 225)->url() ?> 400w,
<?= $cover->crop(800, 450)->url() ?> 800w,
<?= $cover->crop(1200, 675)->url() ?> 1200w
"
sizes="(max-width: 768px) 100vw, 800px"
alt="<?= $cover->alt()->or($page->title())->html() ?>"
loading="lazy"
>
<?php endif ?>
Kirby генерирует производные изображения на лету и кэширует их в media/.
Производительность и кэш
// site/config/config.php
return [
'cache' => [
'pages' => [
'active' => true,
'type' => 'file',
'ignore' => fn($page) => $page->id() === 'search',
],
],
'content' => [
'locking' => false, // отключить блокировку файлов в prod
],
];
Для высоконагруженных сайтов кэш страниц выносится в Redis через сторонний драйвер.
Сроки
Корпоративный сайт 5–10 страниц с нестандартным дизайном: 2–3 недели. Блог или каталог с фильтрацией, поиском и кастомными полями: 3–5 недель. Если нужна интеграция с внешним API или безголовый режим для фронтенд-фреймворка — добавляется 3–7 дней.







