Различные сайдбары для разделов сайта в Yii
На официальном форуме Yii Framework встретил вопрос об организации работы с сайдбарами на сайте. Вопрос возник в связи с требованиями автора выводить разное содержимое панелей в разных разделах сайта. Автор пробует выделить место для сайдбара в главном шаблоне views/layouts/main.php и генерировать содержимое сайдбаров в самих конкретных представлениях. Поделюсь своей организацией шаблонов.
Вариант автора мне показался избыточным необходимостью собирать сайдбар в каждом представлении.
По умолчанию в папке /views/layouts/ создаются шаблон main.php и подшаблоны column_1.php и column_2.php, наследуюемые от main.php. В главном шаблоне main.php мы оставим каркас.
Главный шаблон layouts/main.php:
<!doctype html> <html> <head>...<head> <body> <header>...<header> <div id="container"> <?php echo $content; </div> <footer>...</footer> </body> </html>
Теперь просто соберём в отдельную папку /views/layouts/page/, раскопируем и переименуем невразумительные column_1.php и column_2.php во что-то вроде default.php, blog.php, shop.php, portfolio.php и т.д. Вот код нескольких из таких подшаблонов:
Шаблон layouts/page/default.php в две колонки:
<?php $this->beginContent('//layouts/main'); <aside class='sidebar left_sidebar'> $this->renderPartial('//layouts/sidebar/default'); </aside> <section class='main right_main'> echo $content; </section> $this->endContent();
Шаблон layouts/page/blog.php в две колонки:
<?php $this->beginContent('//layouts/main'); <aside class='sidebar left_sidebar'> $this->renderPartial('//layouts/sidebar/blog'); </aside> <section class='main center_main'> <!-- В блоге перед постами можно поместить красивый слайдер --> $this->widget('application.widgets.BlogSliderWidget'); echo $content; </section> $this->endContent();
Шаблон layouts/page/fullpage.php на всю ширину:
<?php $this->beginContent('//layouts/main'); <section class='main'> echo $content; </section> $this->endContent();
Код подшаблонов минимален, поэтому копипаст не страшен.
Как можно заметить, нужно добавить папку /views/layouts/sidebar/ и сделать внутри несколько файлов сайдбаров. Повторяющиеся виджеты можно либо вписать вручную в каждый файл, либо отнаследовать сайдбары друг от друга. Например, сайдбар для блога упрощённо выглядит так:
Сайдбар для блога layouts/sidebar/blog.php:
<?php $this->beginWidget('СPortlet', array('title'=>'Следите за мной')); $this->widget('application.widgets.FollowWidget'); $this->endWidget(); $this->beginWidget('СPortlet', array('title'=>'Разделы блога')); $this->widget('zii.widgets.CMenu', array('items' =>BlogCategory::model()->getMenuArray())); $this->endWidget(); $this->beginWidget('СPortlet', array('title'=>'Метки')); $this->widget('application.widgets.TagCloudWidget'); $this->endWidget(); $this->beginWidget('СPortlet'); $this->widget('application.widgets.CalendarWidget'); $this->endWidget(); $this->beginWidget('СPortlet', array('title'=>'Профиль')); $this->widget('application.widgets.LoginFormWidget'); $this->endWidget();
В итоге получаем коллекцию лёгких подшаблонов для разных разделов сайта и коллекцию сайдбаров со своими виджетами.
Шаблон по умолчанию указываем в базовом контроллере:
class Controller extends СController { // по умолчанию для всего сайта public $layout = '//layouts/page/default'; // ... }
Потом просто выставляем специфические шаблоны в нужных контроллерах или экшенах:
class BlogController extends Controller { // у раздела Блог шаблон другой, поэтому укажем его public $layout = '//layouts/page/blog'; // экшен вывода поста public function actionView($id) { // пост мы выведем с немного другим шаблоном без фотогалереи, // имеющим другой сайдбар с виджетом популярных постов $this->layout = '//layouts/page/blogpost'; $post = $this->loadModel(); // ... } }
Таким образом, процесс переключения сайдбаров мы повысили до процесса переключением шаблонов, что избавило нас от рутинной генерации сайдбара в контроллере или его представлении, а также дало дополнительную гибкость изменения шаблонов для различных разделов сайта. При необходимости для любого раздела достаточно сделать новый сайдбар и новый подшаблон, в котором через renderPartial
этот сайдбар будет включён.
Уважаемый Дмитрий!
Спасибо за статью. Скажите Вы не рассматривали реализацию вывода виджетов, как это реализовано в joomla.
Вы имеете в виду динамическое распределение виджетов по зонам шаблона с указанием в админке на каких страницах какой выводить? Такой способ не реализовывал, так как не было необходимости в разработке полноценного конструктора для расстановки виджетов.
В классических самописных проектах (на фреймворках или без) каждый модуль живёт своей жизнью, а все виджеты и связи конструируются прямо в программном коде. Для перехода к визуальной схеме как в Joomla! нужно весь сайт делать на статических страницах и все модули переделывать в виджеты для привязки к страницам (а это мало кому нужно). Или, как вариант, можно привязывать виджеты по маске к URL.
В вопросе (по ссылке в статье) автор и намекает на динамический сбор наборов виджетов для всех зон (клипов) каждый раз в каждом действии контроллера, но это решение весьма избыточное и не очень удобное, так как для добавления каждого виджета в несколько разделов нужно изменить списки виджетов в десятках действий.
Ну это если я правильно понял ваш вопрос.
Спасибо за ответ.
Если не сложно расскажите как у вас организовано кеширование, используете ли тегирование кеша?
Использую простое кэширование. Кеширую запросы find(), findAll() и т.д., каждый виджет оборачиваю в конструкцию
Я упоминал о ней раньше. Полную очистку кэша произвожу в админке.
Тегирование, конечно, удобнее, но пока легко обхожусь без него.
Подскажите, а как реализовать (в плане шаблонов) вывод определенной части контента или виджета, только для определенных пользователей. Грубо говоря необходимо, чтоб на какой то странице не зарегистрированный пользователь мог просматривать урезанный контент. А в идеале, что бы зарегистрированный мог просматривать контент весь, но за исключением каких то блоков доступных только для модератора например.
Отлично. Большое спасибо за статью и вклад в развитие программирования. Хотелось бы видеть подобную реализацию теперь уже на Yii2.
Даешь примеры для yii2 !
а как для второй версии сделать?
Также через $this->render(...).
А как же из контроллер передать переменную в сайдбар (для вывода там меню, например)?
Можно через $this->params.
А также можно в layout передать переменную из контроллера с помощью $this->context->yourVar ,а в контроллере свойство должно быть обьявлено публичным
Дмитрий, а Вы бы не могли обновить статью с учетом Yii2?
Столкнулся с таким вопросом.
Боковую панель подключал как вы описывали. Все хорошо, проблема решена. Однако, понадобилось показывать слайдер не на каждой странице. Как слайдер подключать выборочно?
Также можно создавать событие и вызывать его в шаблоне, чтобы формировать сайдбар или отключать его.Таким образом можно формировать различные шаблоны для разных действий или даже для одного действия формировать различные шаблоны в зависимости от условий.
А я сделал так. В базовом контроллере, от которого наследуются все контроллеры указал
а в нужном экшене, где надо выводить слайдер - устанавливаю
Ну и конечно в layout