Как работает мой сайт
Мой сайт работает на моём самописном движке на ПХП (единственное исключение — раздел «Блог», о нём в конце).
Файлы страниц сайта лежат в папках, соответствующих урлам разделов, например страница про Ангстрем лежит на сервере под именем .../www/projects/angstrom/angstrom.php. Задача этого файла — сгенерить ХТМЛ смысловой части этой страницы.
Метаданные
Рядом с файлом имя-папки.php должен лежать файл метаданных _имя-папки.php. Для Ангстрема он выглядит примерно так (выкинул часть полей для простоты):
<?php return array (
'logo' => 'angstrom',
'value' => '20140201',
'title' => 'Ангстрем',
'x-showcase-title' => 'Ангстрем, конвертер всего',
'x-copyright-years' => '2014...',
'languages' => array (
'english' => array (
'title' => 'Ångström',
'x-showcase-title' => 'Ångström, the converter',
),
),
) ?>
Задача движка — понять, на какой из моих многочисленных доменов и по какому адресу зашёл пользователь, определиться с языком, найти файл нужной страницы, выполнить его, пропустить через шаблонизатор и типограф и отдать наружу.
Там умная и гибкая система, которая позволяет делать отличия между сайтами на разных языках (ilyabirman.ru и ilyabirman.net) только там, где они нужны: домен, текст, правила типографики, твиттер-акаунт для шаринга; но всё остальное хранить в одном месте один раз.
Самое главное в файле метаданных — это поле logo. Это постоянный идентификатор страницы, который не поменяется, если я вдруг решу перенести её в другую папку. На нём завязаны многочисленные макросы. Например, на главной у меня есть этажик, где я показываю разные проекты в горизонтальной прокручиваемой полосе — «витрине».
Вот примерный код, который её рисует (подсветка синтаксиса глючит):
<?php $showcase_elements = array (
'angstrom',
'moscow-metro-multiplication',
'therules-2-for-ios',
'chelyabinsk-trams-2015',
'emcee',
'train-thirteen',
'wireless-dj',
'snooker-results-display',
'moscow-metro-poster-vdnh',
'forebruary',
'moscow-metro-nanomap',
); ?>
<?php foreach ($showcase_elements as $showcase_element) { ?>
<div class="b-showcase-element" style="width: 160px">
<div class="b-showcase-element-image-wrapper">
<div>
<a href="<?= HREF ($showcase_element) ?>" class="nu">
<img
src="<?= FOLDER ($showcase_element) ?>i/icon-160@2x.png"
alt="<?= strip_tags (TITLE ($showcase_element)) ?>"
width="160" height="160"
/>
</a>
</div>
</div>
<div class="b-showcase-element-title">
<a href="<?= HREF ($showcase_element) ?>">
<?= EX ('showcase-title', $showcase_element)?>
</a>
</div>
</div>
<?php } ?>
Макросы
Важно то, что этот код ничего не знает про урлы, названия и папки отдельных штук, на которые ссылается. Всё делают несколько умных макросов:
- HREF ($logo) возвращает полный урл страницы по её идентификатору;
- FOLDER ($logo) возвращает путь к папке, в которой лежит страница;
- TITLE ($logo) возвращает название страницы;
- EX ($what, $logo) возвращает значение поля x-something из файла метаданных.
Я, как видите, использую EX и поле x-showcase-title для того, чтобы показывать особые заголовки в «витрине». Если я вдруг решу переименовать один из проектов и перенести в другую папку, и ещё сделать про него страницу на французском, чтобы она была доступна по адресу ilyabirman.net/french/обычный-путь-к-проекту — это займёт пару минут, не считая времени написания французского текста. При этому создавать папку /french/ на сервере и копировать туда все файлы не придётся — языковые элементы урла обрабатываются отдельно и на структуру папок на сервере не влияют.
Есть и другие макросы. CHILDREN вернёт массив всех дочерних для данной страниц. Например, в разделе проектов их список автоматически дополнится новым, если я создам подпапку со страницей нового проекта в ней.
А ещё у меня на страницах бывают переключалки между связанными страницами, вот, например, такой переключалкой провязаны несколько рассказов про Лондон. Это работает, потому что эти страницы связаны в одну группу через поле group в файле метаданных. Они при этом могут лежать вообще по любым урлам, их просто вернёт GROUPLINGS. Если одна из страниц группы окажется недоступна на одном из языков — не беда, значит не попадёт в список. Движок не станет генерить мёртвые ссылки.
Или вот есть ещё WITHIN, определяется так:
function WITHIN ($what, $id = false) {
return AT ($what) or INSIDE ($what, $id);
}
Удобно использовать в меню, например, в котором плашку у текущего раздела надо поставить если мы в нём или любых его подразделах.
Есть макрос LANG, который возвращает текущий язык. Его удобно использовать, если страницы на разных языках отличаются двумя-тремя строками текста. Но чтобы не писать сто раз if (LANG == ’russian’) { ... }, можно просто положить в папке два файла — angstrom-english.php и angstrom-russian.php, тогда движок сразу возьмёт нужный из них.
Ещё есть TAIL, OFFSET, SIBLINGS, NEIGHBOURS и всякие другие, которые позволяют компактно и внятно выражаться в коде.
Я это называю макросами, а не функциями, потому что это точнее передаёт смысл, и ещё их можно вызывать без параметра $logo и без скобок (если других параметров нет), и тогда они сработают для текущей собираемой страницы:
<h1><?= TITLE ?></h1>
Шаблоны
У любой страницы в файле метаданных может быть поле apply-template — оно говорит движку, что надо пропустить страницу через определённый шаблон перед тем, как заворачивать в обёртку из меню и подвала.
Например, в подвале любого рассказа о поездке я даю ссылки на соседние. Их сколько нужно возвращает макрос SIBLINGS. Но я не копирую этот этаж из рассказа в рассказ — для этого у меня есть шаблон world-story, который применяется ко всем рассказам из поездок.
Шаблон может не просто завернуть страницу во что-то, но и как угодно её обработать перед использованием.
Вот начало файла .../www/world/london-2011-may/london-2011-may-russian.php:
Лондон — лучший город, где мне доводилось бывать.
IMG_0333.jpg Парламент и Биг-бен в ЛондонеДостопримечательностям здесь совершенно необязательно быть в поле зрения, чтобы было понятно, где ты находишься. Каждая деталь напоминает об этом:
IMG_0238.jpg Телефонная будка, почтовая машина и автобус в Лондоне
Похоже на текст из редактора Эгеи, правда? Потому что я тут использую Нисден — форматтер Эгеи. Шаблон world-story автоматически пропускает текст через него. Поэтому тут автоматически работает всякая резиновость картинок, фоторамы и всё остальное, и в результате сам собой получается рассказ про Лондон.
Блог
Теперь про блог. Блог работает на Эгее и живёт своей жизнью, несмотря на внешнее сходство с остальным сайтом. Эгея, в отличие от остального сайта, использует базу данных для хранения заметок, комментариев и прочего. Сайту никак не мешает, что в папке /meanwhile/ у него живёт что-то «неродное». Он не находит там файла _meanwhile.php и поэтому считает, что эта папка для него не представляет ценности.
Мне надо, чтобы в блоге у меня использовался ЦСС с основного сайта, но всё же в нём есть несколько своих особенностей, поэтому напрямую я не могу залинковать тот же самый файл. Чтобы не носить общие для сайта изменения из одного файла в другой, я использую Галп, который автоматически собирает нужную версии ЦСС-файла для блога.
Ещё, как вы знаете, у меня есть русский и английский блоги. На самом деле их выдаёт одна и та же копия Эгеи, которая в зависимости от домена использует разные таблицы в базе данных.
Это недокументированная функция, но по секрету скажу что там, где у вас в Эгее лежит папка /user/, у меня лежит папка /users/ с двумя подпапками. Да, Эгея умеет быть многопользовательской уже много лет! Только никому не говорите. Если серьёзно, это работает на костылях. Заранее говорю, что не буду отвечать на письма с вопросом «как мне сделать так же».