Создание своего сайта на Processwire по шагам. Работа с категориями. Привязка статьи к категории с помощью поля типа Page Reference. Урок 10

Теперь, кажется, что у нас есть всё необходимое для того, чтобы вести свой блог. Однако со временем, по мере того как количество статей будет расти, рано или поздно возникнет необходимость в их тематизации. И для этих целей отлично подойдёт такая сущность как «Категории».

Создаём структуру

Давайте определимся, что нам для этого будет необходимо. Очевидно, что это будет страница, на которой будет выводиться весь список категорий и собственно страница самой категории, на которой будут отображаться статьи, привязанные к этой самой категории.

А это значит, что мы сделаем то, что уже делали много раз до этого – создадим файлы шаблонов, и привяжем к ним соответствующую сущность. У меня получились следующие файлы:

categories.php – шаблон со списком всех категорий;

category.php – шаблон категории со списком принадлежащих к ней статей.

Дальше я создал такую структуру из категорий:

К каждой странице соответственно привязываем соответствующие ей шаблоны. После проделанных операций, в верхнем меню должна появиться новая страница «Категории». Однако, если перейти на неё, то можно обнаружить, что она пуста. Что же, давайте на эту страницу выведем все категории, которые у нас есть - открываем шаблон categories.php для правки. По сути у нас в шаблоне уже есть объект текущей страницы page(), следовательно получить дочерние страницы можно так:

<div id="main-content">
  <ul class="list-group">
  <?php foreach(page()->children as $category): ?>
    <li class="list-group-item">
      <a href="<?=$category->url?>"><?=$category->title?></a>
    </li>
  <?php endforeach; ?>
  </ul>
</div>

Теперь если перейти на саму страницу, то её содержимое будет выглядеть так:

Итак, мы разобрались со структурой и даже создали главную страницу с категориями. Однако тут для нас ничего особенного нет, потому что схожие операции мы не раз проделывали ранее. А вот дальше, будет интереснее.

Создание поля с привязкой статьи к категории

В CMS Processwire есть поле, с помощью которого мы сможем связать текущую страницу с другими страницами (в нашем случае – с категориями). Тип данного поля называется Page Reference. Давайте перейдём к его созданию.

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

Дальше выбираем родителя страниц, к которым мы в дальнейшем будем осуществлять привязку - в нашем случае это будут «Категории».

Здесь указываем шаблон страниц, которые можно выбрать:

Ещё я рекомендую отметить такую галочку как «Разрешить создание новых страниц из поля?», с помощью которой можно создать новую страницу категории прямо из поля. То есть с помощью данной настройки можно сэкономить время.

Далее привязываем поле к шаблону и нажимаем «Сохранить».

Теперь, если перейти на страницу поста, то можно обнаружить, как выглядит данный тип поля:

Можно как выбрать существующую категорию, так и создать новую, с помощью кнопки «Добавить».

Выводим страницы, принадлежащие той или иной категории

Открываем на редактирование шаблон category.php Собственно, смысл всей процедуры сводится к тому, чтобы произвести выборку по страницам, у которых в качестве значения поля categories установлен ID текущей страницы (то есть категории).

Сделать это можно с помощью такого селектора:

<?php $posts = pages()->find("categories=$page, limit=1"); ?>

Здесь $page – это id текущей категории. Этот же id присваивается полю «categories», в момент привязки статьи к категории.

limit=1 я указал, чтобы протестировать пагинацию.

Дальнейший код, в котором происходит итерация и вывод постов, в принципе можно позаимствовать из шаблона главной страницы (что и было сделано):

<? foreach ($posts as $post): ?>
<div class="post-preview">
  <a href="<?=$post->url;?>">
    <h2 class="post-title">
      <?=$post->title;?>
    </h2>
    <h3 class="post-subtitle">
      <?=$post->annotation;?>
    </h3>
  </a>
  <p class="post-meta">
    <?=strftime("%d %B %Y г.", $post->created);?>
  </p>
</div>
<hr>
<? endforeach; ?>
<!-- Pager -->
<div class="clearfix">
  <div class="pager-nav pb-5">
    <nav aria-label="Page navigation example">
<?php
      echo $posts->renderPager(array(
        'nextItemLabel' => "Next",
        'previousItemLabel' => "Prev",
        'listMarkup' => "<ul class='pagination'>{out}</ul>",
        'itemMarkup' => "<li class='{class} page-item'>{out}</li>",
        'linkMarkup' => "<a href='{url}' class='page-link'>{out}</a>",
        'currentItemClass' => "active",
        'currentLinkMarkup' => "<a class='page-link' href='#'>{out}<span class='sr-only'>(current)</span></a>"
      ));
?>
    </nav>
  </div>
</div>

Чтобы пагинация корректно работала, не забываем в настройках шаблона категории указать необходимую опцию:

Размещение категорий в боковой колонке

Для более удобной навигации было бы неплохо, чтобы все категории были где-то на виду – этой цели хорошо послужит боковая колонка, в которой уже находится поиск. Вам наверняка приходилось такое видеть в других блогах. Не будем придумывать ничего нового - сделаем так же.

Открываем файл _main.php и в правую колонку, сразу после формы поиска пишем такой код:

<h3>Категории</h3>
<ul class="list-group">
<?php foreach($pages->get('/kategorii/')->children as $category): ?>
  <li class="list-group-item">
    <a href="<?=$category->url?>"><?=$category->title?></a>
  </li>
<?php endforeach; ?>
</ul>

Данный кусочек требует пояснения:

$pages->get('/kategorii/')->children

Сначала с помощью метода get получаем объект страницы по адресу /kategorii/, а затем её дочерние страницы.

К слову, раз уж мы находимся в этом файле, то заодно можно немного подправить отображение правой колонки – прописать заголовок к поиску и добавить отступы. В итоге, весь код выглядит так:

<div class="col-lg-3">
  <div class="mb-4">
    <h3>Поиск</h3>
    <form action="/search/">
      <div class="form-group">
        <input class="form-control" name="q" />
      </div>
      <button class="btn btn-info">Отправить</button>
    </form>
  </div>
  <h3>Категории</h3>
  <ul class="list-group">
  <?php foreach($pages->get('/kategorii/')->children as $category): ?>
    <li class="list-group-item">
      <a href="<?=$category->url?>"><?=$category->title?></a>
    </li>
  <?php endforeach; ?>
  </ul>
</div>

На всякий случай, прикладываю архив с новыми шаблонами и файлом _main.php