Постепенно мы подбираемся ко все более сложным и интересным моментам нашей работы. На этот раз мы сделаем вывод статей на сайте, используя только собственные разработки и API системы управления MODx. И да, мы не будем использовать Ditto ;).
Итак, рассмотрим наши статьи, как их нарисовал дизайнер, и выделим наиболее существенные части, которые должны быть запрограммированы и выведены на главной странице:
- Заголовок статьи
- Дата публикации
- Категория, к которой принадлежит данный документ
- Имя автора статьи
- Ссылка на комментарии к данной статье
- Вводное содержимое
- Ссылка "Читать далее" на полный текст статьи
Эти данные будут присутствовать всегда при появлении новой статьи на сайте. Кроме того, нам необходимо будет предусмотреть ситуацию, когда статей станет много и, следовательно, понадобится автоматически разбивать поток статей на страницы.
Итак, задачи ясны, дерзаем? :)
Начнем с того, что создадим несколько тестовых документов в системе управления, которые будем использовать в дальнейшем для тестирования работы нашей разработки. Эти документы будут дочерними для документа "Блог":
Каждый из этих документов содержит простой текст, что-то наподобие этого:
Теперь осталось дело за малым – сделать вывод этой информации на сайте :).
Логика вывода этой информации будет по большому счету несильно отличаться от вывода ссылок для верхнего меню: с помощью функций API мы получим список дочерних документов и затем выделим из полученного массива необходимые данные. Хотя есть и некоторые особенности:
- публикацию страниц блога с кратким описанием мы запланировали только на главной странице, и, значит, новый созданный сниппет будет вызываться только на главной странице, а не во всем шаблоне, как это было с верхним меню;
- будут задействованы некоторые другие поля БД, как например, “introtext”, “content” и другие;
- к каждой статье блога добавим комментарии;
- ну и разные другие мелочи, о которых подробнее поговорим ниже.
Рассмотрим HTML код одного блока статьи блога на главной странице:
<!-- Article --> <div class="article"> <h2><span><a href="#">Заголовок статьи</a></span></h2> <p class="info noprint"> <span class="date">2007-01-01 в 00:01</span><span class="noscreen">,</span> <span class="cat"><a href="#">Категория</a></span><span class="noscreen">,</span> <span class="user"><a href="#">Имя автора</a></span><span class="noscreen">,</span> <span class="comments"><a href="#">Комментарии</a></span> </p> <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam pellentesque enim blandit enim bibendum blandit. Integer eu leo ac est aliquet imperdiet. Quisque nec justo id augue posuere malesuada. Nullam ac metus. Cras non leo ut est placerat condimentum. Aliquam ut enim. Quisque non sapien in enim eleifend faucibus. Pellentesque sodales. Mauris auctor arcu sit amet felis. Donec eget enim ut lacus pharetra condimentum. Nulla in felis vel tortor imperdiet consectetuer. Sed id ante.</p> <p class="btn-more box noprint"><strong><a href="#">Читать далее</a></strong></p> </div> <!-- /article --> <hr class="noscreen" />
После тега <hr class="noscreen" /> блоки статей повторяются, поэтому дальше будем работать с приведенным выше кодом.
Разделим этот код на части и обсудим детально каждый момент:
- Заголовок статьи, который также будет ссылкой на полную статью.
Ну это мы легко получим, как делали уже с верхним меню.- <h2><span><a href="#">Заголовок статьи</a></span></h2>
- Дата создания статьи.
Тоже самое, дата создания любого документа хранится в БД MODx в таблице {PREFIX}site_content в поле "createdon", а, значит, легко нам доступна.- <span class="date">2007-01-01 в 00:01</span>
- <span class="noscreen">,</span>
- Категория, к которой автор отнесет статью (кстати, мы сделаем такие возможности, чтобы автор мог выбирать несколько категорий для одной статьи)
Да, здесь будет чуть сложнее – мы используем TV для вывода категорий. Все категории мы будем хранить как документы в папке "Категории":- <span class="cat"><a href="#">Категория</a></span>
- <span class="noscreen">,</span>
- Имя автора, который написал данную статью. Мы же помним о том, что теоретически у нас может быть несколько авторов?
В таблице {PREFIX}site_content есть указание на автора в поле ”createdby” для каждого документа в системе, но если посмотреть значения этого поля, то мы увидим только цифры (1, 2, 3 и т.д.). Эти цифры обозначают порядковые номера всех пользователей внутри системы управления. Ниже мы рассмотрим этот вопрос подробнее.- <span class="user"><a href="#">Имя автора</a></span>
- <span class="noscreen">,</span>
- Ссылка на комментарии к данной статье.
Нет ничего проще – это будет ссылка на полную статью плюс для удобства добавим якорь именно к комментариям на основе известного сниппета Jot. А, кстати, давайте еще добавим к этому тексту количество комментариев? :) Это будет несложно сделать, а наши авторы и посетители блога будут довольны такой возможностью. Таким образом, у нас должно получиться как-то так:- <span class="comments"><a href="#">Комментарии</a></span>
- Краткий вводный текст статьи.
Этот текст также нам будет легко доступен из поля "introtext" в БД (или по-русски в системе управления MODx он назван как "Аннотация"). Кстати, зададимся вопросом: а как быть, если автор при создании статьи не позаботился о заполнении этого поля? Откуда нам взять текст для аннотации в этом случае? По моему опыту это довольно часто случается. Ну что-ж, мы решим и эту проблему.- <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
- ...
- </p>
- Ссылка "Читать далее".
Элементарно, к тому же, при программировании пунктов выше мы уже решим этот вопрос.- <p class="btn-more box noprint">
- <strong><a href="#">Читать далее</a></strong>
- </p>
Ну вот как-бы и все, что касается вывода статей на главной странице. Хотя… нет, еще один вопрос остался нерешенным:
- Постраничное разбиение статей на главной странице.
Этого нет ни в базе данных, ни даже в выбранном дизайне (почему-то наш дизайнер поленился нарисовать эту навигацию). Честно говоря, на этом пункте мне хотелось остановиться поподробнее, размять мозги и поработать над хорошей "постраничной навигацией". Но, к сожалению, это займет наверняка не меньше времени (а скорее, даже больше), чем написание подобной статьи. Поэтому упростим навигацию до минимума ссылок "< Назад" и "Вперед >":
В main.css добавьте следующую строку
А также в документе “Блог” добавьте следующий HTML код сразу после всего остального кода- #pagination a{ margin:0 0 0 20px; }
Вполне возможно, что в будущем я все-таки вернусь к этому пункту и мы реализуем хорошую во всех смыслах навигацию. А на данном этапе пока пройдем далее.- <div id="pagination">
- <a href="#">< Назад</a>
- <a href="#">Вперед ></a>
- </div>
Итак, создадим новый сниппет с названием "Articles". Для начала пусть он выводит тот же самый HTML код одного блока и навигационный блок:
<?php $output = " <!-- Article --> <div class=\"article\"> <h2><span><a href=\"#\">Заголовок статьи</a></span></h2> <p class=\"info noprint\"> <span class=\"date\">2007-01-01 в 00:01</span><span class=\"noscreen\">,</span> <span class=\"cat\"><a href=\"#\">Категория</a></span><span class=\"noscreen\">,</span> <span class=\"user\"><a href=\"#\">Имя автора</a></span><span class=\"noscreen\">,</span> <span class=\"comments\"><a href=\"#\">Комментарии</a></span> </p> <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam pellentesque enim blandit enim bibendum blandit. Integer eu leo ac est aliquet imperdiet. Quisque nec justo id augue posuere malesuada. Nullam ac metus. Cras non leo ut est placerat condimentum. Aliquam ut enim. Quisque non sapien in enim eleifend faucibus. Pellentesque sodales. Mauris auctor arcu sit amet felis. Donec eget enim ut lacus pharetra condimentum. Nulla in felis vel tortor imperdiet consectetuer. Sed id ante.</p> <p class=\"btn-more box noprint\"><strong><a href=\"#\">Читать далее</a></strong></p> </div> <!-- /article --> <hr class=\"noscreen\" /> <div id=\"pagination\"> <a href=\"#\">< Назад</a> <a href=\"#\">Вперед ></a> </div> "; return $output; ?>
Вызывать этот сниппет будем на главной странице, а это значит, что в содержимом документа "Блог" нужно добавить следующую конструкцию [!Articles!]. Как видно из данной конструкции, сниппет будет некэшируемый. Задание на дом – почему? :) Весь остальной код из документа "Блог" можно смело удалить.
Теперь будем в нашем сниппете последовательно по списку заменять статичный код на динамический. Во многом нам будет полезна уже известная API функция getDocumentChildren():
<?php $results = $modx->getDocumentChildren( $id = 1, // ID родительского документа, а именно документа "Блог" $active = 1, // Выбираем только опубликованные документы $deleted = 0, // Выбираем только неудаленные документы 'id, pagetitle, published, introtext, content, menuindex, createdby, createdon, deleted, menutitle', // Выбираем поля из БД $where = '', // Дополнительные условия не требуются $sort='createdon', // Сортируем документы по полю createdon $dir='DESC', // Сортируем документы по убыванию $limit = '' // Ограничения не устанавливаем (параметр LIMIT в SQL запросе) ); foreach($results as $key => $value) { if ($value["menutitle"] != "") { $title = $value["menutitle"]; } else { $title = $value["pagetitle"]; } $items .= " <!-- Article --> <div class=\"article\"> <h2><span><a href=\"#\">Заголовок статьи</a></span></h2> <p class=\"info noprint\"> <span class=\"date\">2007-01-01 в 00:01</span><span class=\"noscreen\">,</span> <span class=\"cat\"><a href=\"#\">Категория</a></span><span class=\"noscreen\">,</span> <span class=\"user\"><a href=\"#\">Имя автора</a></span><span class=\"noscreen\">,</span> <span class=\"comments\"><a href=\"#\">Комментарии</a></span> </p> <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam pellentesque enim blandit enim bibendum blandit. Integer eu leo ac est aliquet imperdiet. Quisque nec justo id augue posuere malesuada. Nullam ac metus. Cras non leo ut est placerat condimentum. Aliquam ut enim. Quisque non sapien in enim eleifend faucibus. Pellentesque sodales. Mauris auctor arcu sit amet felis. Donec eget enim ut lacus pharetra condimentum. Nulla in felis vel tortor imperdiet consectetuer. Sed id ante.</p> <p class=\"btn-more box noprint\"><strong><a href=\"#\">Читать далее</a></strong></p> </div> <!-- /article --> <hr class=\"noscreen\" /> "; // Собираем блоки статей } $output = " <div id=\"pagination\"> <a href=\"#\">< Назад</a> <a href=\"#\">Вперед ></a> </div> "; return $items.$output; ?>
После выполнения этого кода мы получим несколько раз повторяющийся HTML код одного и того же блока, при этом количество повторений будет совпадать с количеством дочерних документов у документа с ID = 1. В моем случае код повторился 7 раз.
Теперь изменим код, используя некоторые результаты запроса функции getDocumentChildren:
<?php $results = $modx->getDocumentChildren( $id = 1, // ID родительского документа, а именно документа "Блог" $active = 1, // Выбираем только опубликованные документы $deleted = 0, // Выбираем только неудаленные документы 'id, pagetitle, published, introtext, content, menuindex, createdby, createdon, deleted, menutitle', // Выбираем поля из БД $where = '', // Дополнительные условия не требуются $sort='createdon', // Сортируем документы по полю createdon $dir='DESC', // Сортируем документы по убыванию $limit = '' // Ограничения не устанавливаем (параметр LIMIT в SQL запросе) ); foreach($results as $key => $value) { if ($value["menutitle"] != "") { $title = $value["menutitle"]; } else { $title = $value["pagetitle"]; } $items .= " <!-- Article --> <div class=\"article\"> <h2><span><a href=\"[~".$value["id"]."~]\">".$title."</a></span></h2> <p class=\"info noprint\"> <span class=\"date\">".$value["createdon"]."</span><span class=\"noscreen\">,</span> <span class=\"cat\"><a href=\"#\">Категория</a></span><span class=\"noscreen\">,</span> <span class=\"user\"><a href=\"#\">".$value["createdby"]."</a></span><span class=\"noscreen\">,</span> <span class=\"comments\"><a href=\"[~".$value["id"]."~]#comments\">Комментарии</a></span> </p> ".$value["introtext"]." <p class=\"btn-more box noprint\"><strong><a href=\"[~".$value["id"]."~]\">Читать далее</a></strong></p> </div> <!-- /article --> <hr class=\"noscreen\" /> "; // Собираем блоки статей } $output = " <div id=\"pagination\"> <a href=\"#\">< Назад</a> <a href=\"#\">Вперед ></a> </div> "; return $items.$output; ?>
В сниппете используются следующие переменные:
- $value["pagetitle"] – заголовок документа
- $value["menutitle"] – пункт меню, если он заполнен, то берем название документа из него
- $value["id"] – ID документа, при помощи конструкции MODx [~ID~] превращаем его в ссылку на данный документ (где ID – номер документа)
- $value["createdon"] – дата создания документа, хранится в базе данных в виде количества секунд, прошедших с начала Эпохи Unix
- $value["createdby"] – ID автора документа, в дальнейшем мы его превратим в нормальный текст
- $value["introtext"] – вводный текст статьи, аннотация
Сохраним сниппет и посмотрим результат его работы на главной странице сайта:
Как видно из рисунка, все записи расположились по убыванию в порядке добавления их в систему. Также мы видим, что все записи получили следующие данные:
- заголовок и ссылку на полную версию (кстати, ссылки уже работают),
- дату создания документа (еще не отформатированную в нормальный вид),
- категории мы пока не трогали (выводится просто HTML код),
- автор документа выводится как ID автора,
- ссылку на комментарии (сами комментарии подключим позже)
- и аннотацию.
Для форматирования даты используем стандартную функцию PHP date():
При этом дата будет выводиться в виде "19/01/2009 в 22:15", где, соответственно, 19 – день, 01 – номер месяца, 2009 – год, 22 – час и 15 – минута создания документа.
Замените в сниппете $value["createdon"] на date("d/m/Y в H:i", $value["createdon"]). Сохраните сниппет и обновите страницу. Этого будет достаточно, чтобы наша дата превратилась в нормальный вид.
Чтобы выводить нормальное имя автора, а не его ID, воспользуемся еще одной функцией MODx API getUserInfo(). Функция getUserInfo() получает только один параметр – ID пользователя, а возвращает результат в виде массива данных. В возвращаемом массиве есть ключ "fullname". Как и следует из названия, здесь хранится полное имя автора.
Откроем код сниппета, найдем в коде сниппета $items и выше перед переменной $items добавим следующую строку:
$author = $modx->getUserInfo($value["createdby"]);
Далее найдем $value["createdby"], заменим эту переменную на $author["fullname"], сохраним сниппет и обновим страницу. В итоге сниппет выведет что-то вроде этого:
"Default admin account" как-то не звучит, правда? :) Наверняка, у большинства будет тоже самое. А теперь зайдем в MODx, закладка "Пользователи" -> "Управление менеджерами", найдем своего пользователя и отредактируем имя. У меня получилось так:
Заключение
За сим пока остановимся, иначе эта статья расползется на километр :). Подведем некоторые итоги:
- сделали вывод статей блога на главной странице с помощью собственного сниппета (и, как ни странно, Ditto здесь совершенно ни при чем!);
- все необходимые первичные данные получили с помощью функции MODx API - getDocumentChildren() и обработали их так, как нам понадобилось в нашем дизайне;
- узнали об еще одной функции API – getUserInfo() и использовали ее по назначению в своем коде;
- если у вас что-то не получилось, скопируйте полный листинг нашего сниппета и замените у себя; я надеюсь, теперь все заработает :).
А в следующей статье мы научимся:
- подключать комментарии к статьям и изменять их внешний вид;
- подключать категории;
- разбивать блоки статей постранично;
- если хватит свободного времени и объема статьи, то в следующей же статье научимся сортировать все записи по автору публикации и категориям; если же нет, то это мы это обсудим сразу в новой статье;
- ну и скорее всего по ходу написания статьи будут появляться разные другие мелкие вкусности