Макеты, секции и части шаблонов
У страниц сайта общая рамка: шапка, меню, подвал. Чтобы не повторять её в каждом шаблоне, рамку описывают один раз в макете. Страница объявляет, какой макет использует, и заполняет его секции — именованные места для содержимого.
Макет
Создайте вручную файл app/Views/layouts/main.php:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title><?= esc($title ?? 'Блог') ?></title>
</head>
<body>
<main>
<?= $this->renderSection('content') ?>
</main>
</body>
</html>Метод renderSection('content') отмечает место, куда страница подставит своё содержимое. Имя секции может быть любым.
Страница на основе макета
Теперь шаблон списка статей содержит только свою часть:
<!-- app/Views/posts/index.php -->
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<h1>Статьи</h1>
<p>Здесь будет список статей.</p>
<?= $this->endSection() ?>extend() называет макет, а всё между section('content') и endSection() попадает на место renderSection('content'). Контроллер не меняется: он по-прежнему вызывает view('posts/index'). Откройте /posts и посмотрите исходный код страницы — заголовок окажется внутри тега main.
Несколько секций
Макет может содержать несколько мест. Добавьте перед закрывающим тегом body строку <?= $this->renderSection('scripts') ?>, и страница сможет заполнить вторую секцию:
<!-- app/Views/posts/index.php -->
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<h1>Статьи</h1>
<?= $this->endSection() ?>
<?= $this->section('scripts') ?>
<script src="<?= base_url('js/posts.js') ?>"></script>
<?= $this->endSection() ?>Секцию, которую страница не заполнила, макет выводит пустой.
Части шаблонов
Повторяющийся фрагмент — меню, подвал — выносят в отдельный файл. Создайте app/Views/partials/nav.php:
<!-- app/Views/partials/nav.php -->
<nav>
<a href="/">Главная</a>
<a href="/posts">Статьи</a>
</nav>В макете его подключает метод include() — добавьте строку сразу после открывающего тега body:
<body>
<?= $this->include('partials/nav') ?>Меню появится на всех страницах, использующих макет.
Часть со своими данными
Чтобы передать во фрагмент отдельные данные, например одну статью в цикле, вызывают функцию view():
<div class="cards">
<?php foreach ($posts as $post): ?>
<?= view('posts/_card', ['post' => $post]) ?>
<?php endforeach ?>
</div>Файл app/Views/posts/_card.php получит переменную $post. Подчёркивание в начале имени — принятый способ отличать части от целых страниц.
Частая ошибка
В шаблоне, который расширяет макет, выводится только то, что находится внутри секций. Разметка, написанная после extend() вне section() и endSection(), на страницу не попадёт. Если часть страницы пропала, проверьте, что она лежит внутри секции и что имя секции совпадает с именем в renderSection().