Как стать автором
Обновить

Создаём шаблон 1С-Битрикс на базе Bootstrap вёрстки

Время на прочтение 29 мин
Количество просмотров 154K

Введение


Уважаемый читатель, данная статья является по сути своей продолжением статьи «Как сверстать веб-страницу. Часть 2 — Bootstrap» и здесь мы отойдём от собственно вёрстки, занявшись интеграцией HTML шаблона в CMS 1С-Битрикс.

В предыдущей части Хабраюзер Mirantus сверстал шаблон Corporate Blue от студии Pcklaboratory с помощью Bootstrap 3.



image

Для данной статьи мы воспользуемся одним из форков репозитория на GitHub, приведённого в конце предыдущей статьи, поскольку в нём были исправлены некоторые баги.

Создание каркаса шаблона


Шаблон сайта с точки зрения 1С-Битрикс – это папка с набором определённых файлов внутри, поэтому шаблон может быть создан как через файловую структуру (инструментами 1С-Битрикс, по FTP или SSH), так и с помощью раздела.

  • Первым делом создадим в папке /bitrix/templates/ раздел, название которого в дальнейшем будет использоваться в качестве ID нашего шаблона, например whitesquare-bootstrap (в дальнейшем в рамках статьи мы будем всегда по умолчанию подставлять именно это значение в качестве ID шаблона).
  • Перенесём в папку шаблона общие ресурсы (JS, CSS, изображения, шрифты) из шаблона страницы:


  • Теперь наша задача создать HTML каркас шаблона. Фактически он состоит из 2 частей, каждая из которых будет лежать в отдельном файле в папке шаблона:

    • /bitrix/templates/whitesquare-bootstrap/header.php
    • /bitrix/templates/whitesquare-bootstrap/footer.php

    Если смотреть на шаблон через административный раздел 1С-Битрикс (Настройки>>Настройки продукта>>Сайты>>Шаблоны Сайтов), то мы увидим шаблон целиком, header.php будет отделён от footer.php с помощью тега #WORK_AREA#.

    Мы легко можем выделить на странице контент, который будем помещать в рабочую область (т.е. он будет уникальным для каждой страницы):

    Таким образом мы можем распределить код index.html из исходного статического шаблона по трём файлам:
    • /bitrix/templates/whitesquare-bootstrap/header.php
      <!DOCTYPE html>
      <html>
        <head>
          <title>Whitesquare</title>
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <link href="css/styles.css" rel="stylesheet">
      	<link href="http://fonts.googleapis.com/css?family=Oswald:400,300" rel="stylesheet">
          <!--[if lt IE 9]>
            <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
            <script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
          <![endif]-->
        </head>
        <body>
      	<div class="wrapper container">
      		<header>
      			<form name="search" action="#" method="get" class="form-inline form-search pull-right">
      				<div class="input-group">
      					<label class="sr-only" for="searchInput">Search</label>
      					<input class="form-control" id="searchInput" type="text" name="search" placeholder="Search">
      					<div class="input-group-btn">
      						<button type="submit" class="btn btn-primary">GO</button>
      					</div>
      				</div>
      			</form>
          		<a href="/"><img src="images/logo.png" alt="Whitesquare logo"></a>
      		</header>
      		<nav class="navbar navbar-default">
      			<ul class="nav navbar-nav">
      				<li><a href="/home/">Home</a></li>
      				<li class="active"><a href="/about/">About us</a></li>
      				<li><a href="/services/">Services</a></li>
      				<li><a href="/partners/">Partners</a></li>
      				<li><a href="/customers/">Customers</a></li>
      				<li><a href="/projects/">Projects</a></li>
      				<li><a href="/careers/">Careers</a></li>
      				<li><a href="/contact/">Contact</a></li>
      			</ul>
      		</nav>
      		<div class="heading">
      			<h1>About us</h1>
      		</div>
      		<div class="row">
      			<aside class="col-md-7">
      				<ul class="list-group submenu">
      					<li class="list-group-item active">Lorem ipsum</li>
      					<li class="list-group-item"><a href="/donec/">Donec tincidunt laoreet</a></li>
      					<li class="list-group-item"><a href="/vestibulum/">Vestibulum elit</a></li>
      					<li class="list-group-item"><a href="/etiam/">Etiam pharetra</a></li>
      					<li class="list-group-item"><a href="/phasellus/">Phasellus placerat</a></li>
      					<li class="list-group-item"><a href="/cras/">Cras et nisi vitae odio</a></li>
      				</ul>
      				<div class="panel panel-primary">
      					<div class="panel-heading">Our offices</div>
      					<div class="panel-body">
      						<img src="images/map.png" class="img-responsive" alt="Our offices">
      					</div>
      				</div>
      			</aside>
      			<section class="col-md-17">
      


    • /Index.php
      (это будет пример рабочей страницы на котором мы будем проверять работоспособность нашей рабочей области) в котором помимо Html разметки мы добавим вызов header’а и footer’а (они создадутся автоматически, если создавать страницу средствами 1С-Битрикс):
      <?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/header.php");?>
      
      
      				<div class="jumbotron">
      					<blockquote>
      						<p>
      							“Quisque in enim velit, at dignissim est. nulla ul corper, dolor ac pellentesque
      							placerat, justo tellus gravida erat, vel porttitor libero erat.”
      						</p>
      						<small>John Doe, Lorem Ipsum</small>
      					</blockquote>
      				</div>
      				<p>
      					Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean non neque ac sem accumsan rhoncus ut
      					ut turpis. In hac habitasse platea dictumst. Proin eget nisi erat, et feugiat arcu. Duis semper
      					porttitor lectus, ac pharetra erat imperdiet nec. Morbi interdum felis nulla. Aenean eros orci,
      					pellentesque sed egestas vitae, auctor aliquam nisi. Nulla nec libero eget sem rutrum iaculis.
      					Quisque in enim velit, at dignissim est. Nulla ullamcorper, dolor ac pellentesque placerat, justo
      					tellus gravida erat, vel porttitor libero erat condimentum metus. Donec sodales aliquam orci id
      					suscipit. Proin sed risus sit amet massa ultrices laoreet quis a erat. Aliquam et metus id erat
      					vulputate egestas. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus
      					mus.
      				</p>
      				<p>
      					Donec vel nisl nibh. Aenean quam tortor, tempus sit amet mattis dapibus, egestas tempor dui. Duis
      					vestibulum imperdiet risus pretium pretium. Nunc vitae porta ligula. Vestibulum sit amet nulla quam.
      					Aenean lacinia, ante vitae sodales sagittis, leo felis bibendum neque, mattis sagittis neque urna
      					vel magna. Sed at sem vitae lorem blandit feugiat.
      				</p>
      				<p>
      					Donec vel orci purus, ut ornare orci. Aenean rutrum pellentesque quam. Quisque gravida adipiscing
      					augue, eget commodo augue egestas varius. Integer volutpat, tellus porta tincidunt sodales, lacus
      					est tempus odio, fringilla blandit tortor lectus ut sem. Pellentesque nec sem lacus, sit amet
      					consequat neque. Etiam varius urna quis arcu cursus in consectetur dui tincidunt. Quisque arcu orci,
      					lacinia eget pretium vel, iaculis pellentesque nibh. Etiam cursus lacus eget neque viverra
      					vestibulum. Aliquam erat volutpat. Duis pulvinar tellus ut urna facilisis mollis. Maecenas ac
      					pharetra dui. Pellentesque neque ante, luctus eget congue eget, rhoncus vel mauris. Duis nisi magna,
      					aliquet a convallis non, venenatis at nisl. Nunc at quam eu magna malesuada dignissim. Duis bibendum
      					iaculis felis, eu venenatis risus sodales non. In ligula mi, faucibus eu tristique sed, vulputate
      					rutrum dolor.
      				</p>
      				<div class="row">
      					<div class="col-md-12">
      						<img src="images/about-1.png" alt="" class="thumbnail">
      					</div>
      					<div class="col-md-12">
      						<img src="images/about-2.png" alt="" class="thumbnail">
      					</div>
      				</div>
      				<h2>Our team</h2>
      				<div class="team">
      					<div class="row">
      						<div class="col col-md-4">
      							<img src="images/team/Doe.jpg" alt="John Doe" class="thumbnail">
      							<div class="caption">
      								<h3>John Doe</h3>
      								<p>ceo</p>
      							</div>
      						</div>
      						<div class="col col-md-4 col-md-offset-1">
      							<img src="images/team/Pittsley.jpg" alt="Saundra Pittsley" class="thumbnail">
      							<div class="caption">
      								<h3>Saundra Pittsley</h3>
      								<p>team leader</p>
      							</div>
      						</div>
      						<div class="col col-md-4 col-md-offset-1">
      							<img src="images/team/Simser.jpg" alt="Julio Simser" class="thumbnail">
      							<div class="caption">
      								<h3>Julio Simser</h3>
      								<p>senior developer</p>
      							</div>
      						</div>
      						<div class="col col-md-4 col-md-offset-1">
      							<img src="images/team/Venuti.jpg" alt="Margery Venuti" class="thumbnail">
      							<div class="caption">
      								<h3>Margery Venuti</h3>
      								<p>senior developer</p>
      							</div>
      						</div>
      						<div class="col col-md-4 col-md-offset-1">
      							<img src="images/team/Tondrea.jpg" alt="Fernando Tondrea" class="thumbnail">
      							<div class="caption">
      								<h3>Fernando Tondrea</h3>
      								<p>developer</p>
      							</div>
      						</div>
      					</div>
      					<div class="row">
      						<div class="col col-md-4">
      							<img src="images/team/Nobriga.jpg" alt="Ericka Nobriga" class="thumbnail">
      							<div class="caption">
      								<h3>Ericka Nobriga</h3>
      								<p>art director</p>
      							</div>
      						</div>
      						<div class="col col-md-4 col-md-offset-1">
      							<img src="images/team/Rousselle.jpg" alt="Cody Rousselle" class="thumbnail">
      							<div class="caption">
      								<h3>Cody Rousselle</h3>
      								<p>senior ui designer</p>
      							</div>
      						</div>
      						<div class="col col-md-4 col-md-offset-1">
      							<img src="images/team/Wollman.jpg" alt="Erik Wollman" class="thumbnail">
      							<div class="caption">
      								<h3>Erik Wollman</h3>
      								<p>senior ui designer</p>
      							</div>
      						</div>
      						<div class="col col-md-4 col-md-offset-1">
      							<img src="images/team/Shoff.jpg" alt="Dona Shoff" class="thumbnail">
      							<div class="caption">
      								<h3>Dona Shoff</h3>
      								<p>ux designer</p>
      							</div>
      						</div>
      						<div class="col col-md-4 col-md-offset-1">
      							<img src="images/team/Brunton.jpg" alt="Darryl Brunton" class="thumbnail">
      							<div class="caption">
      								<h3>Darryl Brunton</h3>
      								<p>ui designer</p>
      							</div>
      						</div>
      					</div>
      				</div>
      
      
      <?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/footer.php");?>
      


    • /bitrix/templates/whitesquare-bootstrap/footer.php
      			</section>
      		</div>
      	</div>
      	<footer>
      		<div class="container">
      			<div class="row">
      				<div class="col-md-8 twitter">
      					<h3>Twitter feed</h3>
      					<time datetime="2012-10-23"><a href="#">23 oct</a></time>
      					<p>
      						In ultricies pellentesque massa a porta. Aliquam ipsum enim, hendrerit ut porta nec, ullamcorper et nulla. In eget mi dui, sit amet scelerisque nunc. Aenean aug
      					</p>
      				</div>
      				<div class="col-md-4 sitemap">
      					<h3>Sitemap</h3>
      					<div class="row">
      						<div class="col-md-12">
      							<a href="/home/">Home</a>
      							<a href="/about/">About</a>
      							<a href="/services/">Services</a>
      						</div>
      						<div class="col-md-12">
      							<a href="/partners/">Partners</a>
      							<a href="/customers/">Support</a>
      							<a href="/contact/">Contact</a>
      						</div>
      					</div>
      				</div>
      				<div class="col-md-4 social">
      					<h3>Social networks</h3>
      					<a href="http://twitter.com/" class="social-icon twitter"></a>
      					<a href="http://facebook.com/" class="social-icon facebook"></a>
      					<a href="http://plus.google.com/" class="social-icon google-plus"></a>
      					<a href="http://vimeo.com/" class="social-icon-small vimeo"></a>
      					<a href="http://youtube.com/" class="social-icon-small youtube"></a>
      					<a href="http://flickr.com/" class="social-icon-small flickr"></a>
      					<a href="http://instagram.com/" class="social-icon-small instagram"></a>
      					<a href="/rss/" class="social-icon-small rss"></a>
      				</div>
      				<div class="col-md-8 footer-logo">
      					<a href="/"><img src="images/footer-logo.png" alt="Whitesquare logo"></a>
      					<p>
      						Copyright © 2012 Whitesquare. A
      						<a href="http://pcklab.com">pcklab</a> creation
      					</p>
      				</div>
      			</div>
      		</div>
      	</footer>
        </body>
      </html>
      




Элементы 1С-Битрикс



  • Добавим подключение пролога и языковых файлов. Это необходимо сделать как в header.php, так и в footer.php (т.е. в начале шаблона и сразу после #WORKAREA#)
    <?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
    IncludeTemplateLangFile(__FILE__);?>
  • Заменим текст внутри тега <title> на вызов функции:
    <title><? $APPLICATION->ShowTitle(false); ?></title>
  • Заменим текст внутри тега <h1> на вызов функции:
    <h1><?$APPLICATION->ShowTitle()?></h1>
    Как видите используютcя разные параметры для вызова одной отложенной функции, чтобы можно было задать разные значения для заголовка браузера и заголовка видимой части страницы, если это потребуется SEO специалистам.
  • Добавим вывод мета-данных (ключевых слов и описания для поисковых систем):
    <?$APPLICATION->ShowMeta("keywords")?>
    <?$APPLICATION->ShowMeta("description")?>
  • Зададим относительный путь ко всем файлам шаблона (картинка, CSS, JS, шрифтам) — <?=SITE_TEMPLATE_PATH?> — данная функция задаёт путь к шаблону относительно корня сайта (и позволяет не прописывать в явном виде идентификатор шаблона, что полезно при копировании или переименовании оного). В результате мы получим:
    <link href="<?=SITE_TEMPLATE_PATH?>/css/styles.css" rel="stylesheet">
    …
    <a href="/"><img src="<?=SITE_TEMPLATE_PATH?>/images/logo.png" alt="Whitesquare logo"></a>
    …
    <img src="<?=SITE_TEMPLATE_PATH?>/images/map.png" class="img-responsive" alt="Our offices">
    …
    <a href="/"><img src="<?=SITE_TEMPLATE_PATH?>/images/footer-logo.png" alt="Whitesquare logo"></a>
    Аналогичным образом мы можем использовать SITE_TEMPLATE_PATH и в index.php, однако следует помнить о том, что при смене шаблона в настройках сайта, применяемого к странице, изменится и этот путь!
  • <?$APPLICATION->ShowMeta("description")?>
    Добавим вызов функции $APPLICATION->ShowHead();, которая служит сразу нескольким целям (в частности динамическому подключению CSS и JS библиотек, объявленных в компонентах в теле страниц с помощью отложенных функций в заголовке, а так же объединяет и сжимает эти библиотеки, если используется соответствующая настройка 1С-Битрикс)
    С помощью отложенных функций SetAdditionalCSS и AddHeadScript мы можем всегда подключить CSS и JS в <header>, а так же избежать повторного подключения одинаковых библиотек (это особенно актуально, например для JQuery, если вы подключаете её не централизованно в шаблоне сайта, в соответствующих компонентах и таких компонентов окажется на странице несколько).
    Важно помнить, что мы не можем таким образом воспроизвести конструкции типа <!--[if lt IE 9]> для устаревших браузеров, поэтому целиком конструкция будет иметь вид:
    <?
    $APPLICATION->ShowHead();
    $APPLICATION->SetAdditionalCSS(SITE_TEMPLATE_PATH.'/css/styles.css');
    $APPLICATION->SetAdditionalCSS('http://fonts.googleapis.com/css?family=Oswald:400,300');
    ?>
        <!--[if lt IE 9]>
          <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
          <script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
        <![endif]-->

  • Добавляем панель инструментов 1С-Битрикс сразу после открытия тега <body> — <?$APPLICATION->ShowPanel();?>


Фактически мы создали статичный HTML каркас с минимальным набором элементов 1С-Битрикс, который уже работает.
Дальнейшая наша задача – перевод отдельных функциональных блоков на работу с компонентами 1С-Битрикс.

Компоненты 1С-Битрикс


В рамках данной статьи мы остановимся только на процессе интеграции вёрстки со стандартными компонентами 1С-Битрикс. Мы не будем создавать свои компоненты и не будем кастомизировать типовые.

Мы создадим отдельную страницу (например, 1.php) на которой будем размещать по 1 компоненту для упрощения работы средствами 1С-Битрикс.

Копирование шаблона компонента в шаблон сайта
Разместим компонента (например, форму поиска — bitrix:search.form) с помощью визуального редактора:

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

В появившемся диалоге нам необходимо указать имя шаблона компонента и выбрать шаблон сайта в котором будет хранится шаблон компонента (в нашем случае это whitesquare-bootstrap):

В результате наших действий в Шаблоне компонента /bitrix/templates/whitesquare-bootstrap/ появилась ещё одна папка – components – в ней будут находиться шаблоны всех компонентов, используемых в рамках шаблона сайта.
Первый появившийся шаблон компонента будет расположен по адресу /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.form/top/
Опытные разработчики могут сразу создавать шаблон компонента, копируя его в шаблон сайта из компонента.

Иногда для дальнейшей работы больше подходит один из шаблонов компонента, поставляемых вместе с системой. Тогда имеет смысл посмотреть каждый из них в работе. Это можно сделать в визуальном редакторе по нажатию на кнопку шестерёнки:



Включаемые области (лого, копирайт, соц сети)

Компонент включаемой области позволяет вложить внутрь себя любой текст, HTML или php код, а так же другие компоненты и вывести этот контент для определённой страницы, раздела или везде, где вызывается включаемая область.
Для всех указанных выше объектов мы считаем рациональным использование включаемой области с целью вынести эти блоки из шаблона. Т.е. для их редактирования по прежнему необходимо будет владеть минимумом познаний в HTML.
Профессионалы могут возразить, что для блока с кнопками соц сетей следовало бы сделать свой компонент, однако нам это кажется не рациональным. Проще загнать этот блок за 10 минут во включаемую область и отредактировать при необходимости, ведь адрес сообщества Facebook не меняется каждый день!

Все эти области будут выводиться на всём сайте, поэтому создадим в шаблоне новую папку include, где будем складывать файлы включаемых областей:
  • /bitrix/templates/whitesquare-bootstrap/include/bottom-logo.php
  • /bitrix/templates/whitesquare-bootstrap/include/copyright.php
  • /bitrix/templates/whitesquare-bootstrap/include/social-networks.php
  • /bitrix/templates/whitesquare-bootstrap/include/top_logo.php

Код вызова компонента включаемой области будет выглядеть в этом случае так:
<?$APPLICATION->IncludeComponent(
	"bitrix:main.include",
	"",
	Array(
		"AREA_FILE_SHOW" => "file",
		"PATH" => SITE_TEMPLATE_PATH."/include/bottom-logo.php",
		"EDIT_TEMPLATE" => ""
	),
false
);?>

Внутри файла включаемой области просто помещаем кусок HTML кода:
<a href="/"><img src="<?=SITE_TEMPLATE_PATH?>/images/footer-logo.png" alt="Whitesquare logo"></a>


Мы не будем в данной статье рассматривать вопрос интеграции Twitter Ленты, поскольку самое простое решение – положить виджет твиттера во включаемую область, аналогично описанным выше решениям.
Так же в Marketplace 1С-Битрикс хватает компонентов, выводящих твиттер ленту, которыми вы так же можете воспользоваться.

Форма поиска

Мы воспользовались компонентом bitrix:search.form и скопировали suggest шаблон компонента в шаблон сайта.
HTML код шаблона компонента находится в файле /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.form/top/template.php
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
<div class="search-form">
<form action="<?=$arResult["FORM_ACTION"]?>">
	<?$APPLICATION->IncludeComponent(
		"bitrix:search.suggest.input",
		"",
		array(
			"NAME" => "q",
			"VALUE" => "",
			"INPUT_SIZE" => 15,
			"DROPDOWN_SIZE" => 10,
		),
		$component, array("HIDE_ICONS" => "Y")
	);?> <input name="s" type="submit" value="<?=GetMessage("BSF_T_SEARCH_BUTTON");?>" />
</form>
</div>

Как видим, у нас не простой, а комплексный компонент (т.е. компонент в состав которого входят другие компоненты). В данном случае это сама форма в которую производится ввод поискового запроса.
Скопируем её шаблон в шаблон сайта.
К сожалению, это не очень красиво – в публичке мы используем 1 компонент, а шаблонов у нас 2. Воспользуемся обычной схемой для комплексных компонентов:
Комплексный компонент

  1. Создадим в папке /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.form/top/ папку bitrix
  2. Переместим шаблон компонента /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.suggest.input/ в /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.form/top/bitrix/. Таким образом получив:
    /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.form/top/bitrix/search.suggest.input/top/
  3. В параметрах компонента bitrix:search.suggest.input укажем шаблон top:
    <?$APPLICATION->IncludeComponent(
    		"bitrix:search.suggest.input",
    		"top",
    		array(
    			"NAME" => "q",
    			"VALUE" => "",
    			"INPUT_SIZE" => 15,
    			"DROPDOWN_SIZE" => 10,
    		),
    		$component, array("HIDE_ICONS" => "Y")
    );?>
    


Вернёмся к форме поиска

Итак, мы видим, что в отличие от цельного блока поиска в вёрстке в архитектуре 1С-Битрикс наша форма будет состоять из 2 вложенных шаблонов (комплексного и простого) компонентов.
  • /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.form/top/template.php
    <?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>
    
    <form name="search" action="<?=$arResult["FORM_ACTION"]?>" method="get" class="form-inline form-search pull-right">
    <div class="input-group">
    	<?$APPLICATION->IncludeComponent(
    		"bitrix:search.suggest.input",
    		"top",
    		array(
    			"NAME" => "q",
    			"VALUE" => "",
    			"INPUT_SIZE" => 15,
    			"DROPDOWN_SIZE" => 10,
    		),
    		$component, array("HIDE_ICONS" => "Y")
    	);?><div class="input-group-btn"><input name="s" class="btn btn-primary" type="submit" value="<?=GetMessage("BSF_T_SEARCH_BUTTON");?>" /></div>
    </div>
    </form>
    
  • /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.form/top/bitrix/search.suggest.input/top/template.php
    <?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
    CJSCore::Init(array("ajax"));
    ?>
    <script type="text/javascript">
    if (!window.oObject || typeof oObject != "object")
    	window.oObject = {};
    
    window.<?= $arResult["ID"]?>_CheckThis = document.<?= $arResult["ID"]?>_CheckThis = function(oObj)
    {
    	try
    	{
    		if(SuggestLoaded)
    		{
    			if (typeof window.oObject[oObj.id] != 'object')
    				window.oObject[oObj.id] = new JsSuggest(oObj, '<?echo $arResult["ADDITIONAL_VALUES"]?>');
    			return;
    		}
    		else
    		{
    			setTimeout(<?echo $arResult["ID"]?>_CheckThis(oObj), 10);
    		}
    	}
    	catch(e)
    	{
    		setTimeout(<?echo $arResult["ID"]?>_CheckThis(oObj), 10);
    	}
    }
    </script>
    
    
    <IFRAME style="width:0px; height:0px; border: 0px;" src="javascript:''" name="<?echo $arResult["ID"]?>_div_frame" id="<?echo $arResult["ID"]?>_div_frame"></IFRAME>
    <label class="sr-only" for="searchInput">Search</label>
    <input class="form-control" id="searchInput" type="text" name="search" placeholder="<?=GetMessage("BSF_T_SEARCH_FORM");?>" <?if($arParams["INPUT_SIZE"] > 0):?> size="<?echo $arParams["INPUT_SIZE"]?>"<?endif?>  value="<?echo $arParams["VALUE"]?>" autocomplete="off" onfocus="<?echo $arResult["ID"]?>_CheckThis(this);" />
    
  • Как вы можете видеть, мы заменили фразы “GO” и “Search” в компонентах на вызов GetMessage – таким образом, мы вынесли фразы в языковые файлы и можем задать разные значения для русского и английского сайтов, использующих общий шаблон и общий компонент.
    Про языковые файлы
    Языковые файлы хранятся в той же папке, что и шаблон (или шаблон компонента) в подпапке /lang/ID_языка/ в файле с тем же именем, что и оригинальный файл в котором вызывается GetMessage.
    Языковой файл представляет из себя массив с ключами и значениями языковых фраз.
    В нашем случае это:
    • /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.form/top/bitrix/search.suggest.input/top/lang/ru/template.php
      <?$MESS ['BSF_T_SEARCH_FORM'] = "Запрос";?>
    • /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.form/top/bitrix/search.suggest.input/top/lang/en/template.php
      <?$MESS ['BSF_T_SEARCH_FORM'] = "Search";?>
    • /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.form/top/lang/ru/template.php
      <?$MESS ['BSF_T_SEARCH_BUTTON'] = "ИСКАТЬ";?>
    • /bitrix/templates/whitesquare-bootstrap/components/bitrix/search.form/top/lang/en/template.php
      <?$MESS ['BSF_T_SEARCH_BUTTON'] = "GO";?>

    На наш взгляд русские версии очень «корявые», однако мы создали их лишь для демонстрации механизма языковых файлов. При желании в них можно разместить английский текст или оставить пустыми.

Теперь осталось лишь разместить код вызов компонента вместо вёрстки в шаблоне:
<form name="search" action="#" method="get" class="form-inline form-search pull-right">
	<div class="input-group">
		<label class="sr-only" for="searchInput">Search</label>
		<input class="form-control" id="searchInput" type="text" name="search" placeholder="Search">
		<div class="input-group-btn">
			<button type="submit" class="btn btn-primary">GO</button>
		</div>
	</div>
</form>


Верхнее меню

Для упрощения работы над сайтом перед началом работы над каждым меню мы будем создавать файл меню с актуальным контентом для упрощения работы.
Например, верхнее меню будет задаваться в файле .top.menu.php со следующим содержимым
<?
$aMenuLinks = Array(
	Array(
		"Home", 
		"/", 
		Array(), 
		Array(), 
		"" 
	),
	Array(
		"About us", 
		"/about/", 
		Array(), 
		Array(), 
		"" 
	),
	Array(
		"Services", 
		"", 
		Array(), 
		Array(), 
		"" 
	),
	Array(
		"Partners", 
		"", 
		Array(), 
		Array(), 
		"" 
	),
	Array(
		"Customers", 
		"", 
		Array(), 
		Array(), 
		"" 
	),
	Array(
		"Projects", 
		"", 
		Array(), 
		Array(), 
		"" 
	),
	Array(
		"Careers", 
		"", 
		Array(), 
		Array(), 
		"" 
	),
	Array(
		"Contact", 
		"", 
		Array(), 
		Array(), 
		"" 
	)
);
?>

Для создания верхнего меню воспользуемся компонентом bitrix:menu. Скопируем шаблон .default этого компонента в шаблон нашего сайта под именем top. Он практически не содержит ничего лишнего, поэтому мы легко адаптируем его под нашу вёрстку:
<?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>

<?if (!empty($arResult)):?>
		<nav class="navbar navbar-default">
			<ul class="nav navbar-nav">
<?
foreach($arResult as $arItem):
	if($arParams["MAX_LEVEL"] == 1 && $arItem["DEPTH_LEVEL"] > 1) 
		continue;
?>
	<?if($arItem["SELECTED"]):?>
		<li class="active"><a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a></li>
	<?else:?>
		<li><a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a></li>
	<?endif?>
	
<?endforeach?>
			</ul>
		</nav>
<?endif?>

Теперь заменим блок верхнего меню в шаблоне на вызов компонента меню:
<?$APPLICATION->IncludeComponent("bitrix:menu", "top", Array(
	"ROOT_MENU_TYPE" => "top",
	"MENU_CACHE_TYPE" => "A",
	"MENU_CACHE_TIME" => "3600",
	"MENU_CACHE_USE_GROUPS" => "Y",
	"MENU_CACHE_GET_VARS" => "",
	"MAX_LEVEL" => "1",	
	"CHILD_MENU_TYPE" => "left",	
	"USE_EXT" => "N",	
	"DELAY" => "N",	
	"ALLOW_MULTI_SELECT" => "N",
	),
	false
);?>


Левое меню

Аналогично верхнему меню возьмём за основу компонент компонентом bitrix:menu. Скопируем шаблон .default этого компонента в шаблон нашего сайта под именем left.
После правки шаблона получим:
<?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>

<?if (!empty($arResult)):?>
<ul class="list-group submenu">

<?
foreach($arResult as $arItem):
	if($arParams["MAX_LEVEL"] == 1 && $arItem["DEPTH_LEVEL"] > 1) 
		continue;
?>
	<?if($arItem["SELECTED"]):?>
		<li class="list-group-item active"><?=$arItem["TEXT"]?></li>
	<?else:?>
		<li class="list-group-item"><a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a></li>
	<?endif?>
	
<?endforeach?>

</ul>
<?endif?>

Заменим блок левого меню в шаблоне вызовом компонента:
<?$APPLICATION->IncludeComponent("bitrix:menu", "left", Array(
	"ROOT_MENU_TYPE" => "left",	
	"MENU_CACHE_TYPE" => "A",	
	"MENU_CACHE_TIME" => "3600",
	"MENU_CACHE_USE_GROUPS" => "Y",	
	"MENU_CACHE_GET_VARS" => "",
	"MAX_LEVEL" => "1",	
	"CHILD_MENU_TYPE" => "left",
	"USE_EXT" => "N",
	"DELAY" => "N",	
	"ALLOW_MULTI_SELECT" => "N",
	),
	false
);?>

Пользуясь тем, что в 1С-Битрикс меню наследуется мы можем положить файлы левого меню .left.menu.php во все разделы, где они нужны с разным содержимым, а в корне, например, вовсе убрать. Вёрстка не пострадает, а меню будет отображаться лишь там, где это необходимо.

Нижнее меню

Нижнее меню (в разделе SiteMap) отображается в 2 колонки. Можно конечно сделать универсальный компонент меню в шаблоне которого пункты будут делиться по столбцам (автоматически, либо по наличию какого-либо параметра, установленного для пунктов в режиме расширенного редактирования меню).
Однако, мы понимаем, что подвал – не самая часто редактируемая часть и нет смысла тратить значительные усилия на его разработку.
Поэтому мы пойдём по простому пути (за который любители идеального кода, вероятно, нас проклянут) – мы создадим 2 меню: bottomL и bottomR.
Несмотря на то, что меню будет 2 шаблон мы для них будем использовать 1.

Вновь возьмём за основу компонент компонентом bitrix:menu. Скопируем шаблон .default этого компонента в шаблон нашего сайта под именем bottom.
Шаблон:
<?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?>

<?if (!empty($arResult)):?>
<div class="col-md-12">

<?
foreach($arResult as $arItem):
	if($arParams["MAX_LEVEL"] == 1 && $arItem["DEPTH_LEVEL"] > 1) 
		continue;
?>

<a href="<?=$arItem["LINK"]?>"><?=$arItem["TEXT"]?></a>

<?endforeach?>

</div>
<?endif?>


Сайдбар – наши офисы

Честно говоря без демо контента не понятно какую функцию оный сайдбар выполняет. Рискнём предположить, что всё-таки в нём показывается не картинка (уж больно несовременно), а полноценная карта Google. Наверное она маловата, чтобы располагать на ней элементы управления, так что она будет манималистичной.
Если же я не прав, то пожалуй один из самых простых способов реализации сайдбара – включаемая область, о которых мы уже говорили.
Возьмём компонент bitrix:map.google.view и скопируем шаблон .default в шаблон сайта, переименовав в sidebar-map.
Мы весь сайдбар сделаем частью компонента, включая заголовок. А значит, чтобы упростить работу редакторов необходимо вынести текст заголовка в параметры компонента.
Создадим в шаблоне компонента файл .parameters.php следующего содержания:
<?
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();

$arTemplateParameters = array(
	"SIDEBAR_MAP_NAME" => Array(
		"NAME" => GetMessage("SIDEBAR_MAP_NAME"),
		"TYPE" => "HTML",
		"DEFAULT" => "Our offices",
	),
);
?>

И языковые файлы по аналогии с языковыми файлами компонента формы поиска:
  • RU (/bitrix/templates/whitesquare-bootstrap/components/bitrix/map.google.view/sidebar-map/lang/ru/.parameters.php):
    <?$MESS ['SIDEBAR_MAP_NAME'] = "Название карты";?>
  • EN (/bitrix/templates/whitesquare-bootstrap/components/bitrix/map.google.view/sidebar-map/lang/en/.parameters.php):
    <?$MESS ['SIDEBAR_MAP_NAME'] = "Sidebar Map Name";?>



Шаблон компонента в таком случае модифицируется совсем незначительно (поместим карту внутрь сайдбара и добавим заголовок):
<?
if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true) die();

$arTransParams = array(
	'INIT_MAP_TYPE' => $arParams['INIT_MAP_TYPE'],
	'INIT_MAP_LON' => $arResult['POSITION']['google_lon'],
	'INIT_MAP_LAT' => $arResult['POSITION']['google_lat'],
	'INIT_MAP_SCALE' => $arResult['POSITION']['google_scale'],
	'MAP_WIDTH' => $arParams['MAP_WIDTH'],
	'MAP_HEIGHT' => $arParams['MAP_HEIGHT'],
	'CONTROLS' => $arParams['CONTROLS'],
	'OPTIONS' => $arParams['OPTIONS'],
	'MAP_ID' => $arParams['MAP_ID'],
);

if ($arParams['DEV_MODE'] == 'Y')
{
	$arTransParams['DEV_MODE'] = 'Y';
	if ($arParams['WAIT_FOR_EVENT'])
		$arTransParams['WAIT_FOR_EVENT'] = $arParams['WAIT_FOR_EVENT'];
}
?>
				<div class="panel panel-primary">
					<div class="panel-heading"><?=$arParams['SIDEBAR_MAP_NAME']?></div>
					<div class="panel-body">
<div class="bx-yandex-view-layout">
	<div class="bx-yandex-view-map">
<?
//echo '<pre>'; print_r($arResult['POSITION']); echo '</pre>';

$APPLICATION->IncludeComponent('bitrix:map.google.system', '.default', $arTransParams, false, array('HIDE_ICONS' => 'Y'));
?>
	</div>
</div>
<?if (is_array($arResult['POSITION']['PLACEMARKS']) && ($cnt = count($arResult['POSITION']['PLACEMARKS']))):?>
<script type="text/javascript">
function BX_SetPlacemarks_<?echo $arParams['MAP_ID']?>()
{
<?
	for($i = 0; $i < $cnt; $i++):
?>
	BX_GMapAddPlacemark(<?echo CUtil::PhpToJsObject($arResult['POSITION']['PLACEMARKS'][$i])?>, '<?echo $arParams['MAP_ID']?>');
<?
	endfor;
?>
}

function BXShowMap_<?echo $arParams['MAP_ID']?>() {BXWaitForMap_view('<?echo $arParams['MAP_ID']?>');}

BX.ready(BXShowMap_<?echo $arParams['MAP_ID']?>);
</script>
					</div>
				</div>
<?endif;?>

Теперь можно поместить вызов компонента сайдбара в шаблон сайта (если он должен выводиться на всём сайте, а лишь в определённых разделах, то достаточно обернуть его во включаемую область):
<?$APPLICATION->IncludeComponent("bitrix:map.google.view", "sidebar-map", array(
	"INIT_MAP_TYPE" => "ROADMAP",
	"MAP_DATA" => "a:4:{s:10:\"google_lat\";d:55.7383;s:10:\"google_lon\";d:37.5946;s:12:\"google_scale\";i:13;s:10:\"PLACEMARKS\";a:1:{i:0;a:3:{s:4:\"TEXT\";s:10:\"Test point\";s:3:\"LON\";d:37.593626976013184;s:3:\"LAT\";d:55.736905609230966;}}}",
	"MAP_WIDTH" => "235",
	"MAP_HEIGHT" => "180",
	"CONTROLS" => array(
	),
	"OPTIONS" => array(
		0 => "ENABLE_SCROLL_ZOOM",
		1 => "ENABLE_DBLCLICK_ZOOM",
		2 => "ENABLE_DRAGGING",
		3 => "ENABLE_KEYBOARD",
	),
	"MAP_ID" => "",
	"SIDEBAR_MAP_NAME" => "Our offices"
	),
	false
);?>

Теперь пришла пора взяться за рабочую область!

Список членов команды

Для начала создадим инфоблок в котором будет хранить информацию о персонах. Из имеющегося макета видно, что нужны как минимум 4 поля:
  • Имя
  • Фото (миниатюра)
  • Должность
  • Порядок относительно других членов команды

Для единственного нестандартного поля (должность) следует завести свойство в настройках инфоблока.
Для универсальности решения мы будем оперировать не ID, а символьными кодами инфоблоков (это очень здорово помогает при переносе компонентов и шаблонов с тестового сервера на боевой, если там разное количество или разный порядок создания инфоблоков и их ID не совпадают).
  • Символьный код инфоблока – TEAM
  • Символьный код свойства «Должность» — POSITION


Может показаться, что на этом этапе нам подойдёт компонент catalog.section с шаблоном board (этот шаблон генерирует таблицу с заданным количеством столбцов), однако в процессе эксплуатации такое решение весьма вероятно окажется сложнее. Поэтому мы всё же воспользуемся bitrix:news.list (скопировав шаблон .default в шаблон сайта под именем team-list) и допишем немного собственного кода.
Добавим в .parameters.php нашего шаблона новое значение:
$arTemplateParameters = array(
	"LIST_NAME" => Array(
		"NAME" => GetMessage("LIST_NAME"),
		"TYPE" => "HTML",
		"DEFAULT" => "Our Team",
	),
);

Не забудем добавить значения в языковые файлы!

Теперь возьмёмся за шаблон компонента. Тут нам понадобится простенький счётчик, который будет закрывать строчные блоки row и ставить отступ для 2,3,4 и 5 блоков в одной строке.

<?
$i++;
if ($i >= 5) {
   $i = 0;
?>
   </div><div class="row">
<?
}
?>
<?endforeach;?>

<?
if ($i > 0) {
?>
   </div>
<?
}
?>

Не забудьте обнулить счётчик перед началом цикла на всякий пожарный.


Помимо счётчика нам понадобится вывести значение нашего свойства «Должность», для которого мы задали код POSITION. В массиве с данными, которые отдаёт компонент это свойство хранится в $arResult[«ITEMS»][«PROPERTIES»][«POSITION»][«VALUE»], поскольку мы будем выводить свойство в перебираемом по ITEMS элементам, то это будет выглядеть:
<?=$arItem["PROPERTIES"]["POSITION"]["VALUE"]?>

Сам шаблон тогда будет выглядеть так:
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
$i=0;?>
<h2><?=$arParams['LIST_NAME']?></h2>

<div class="team">
	<div class="row">
<?if($arParams["DISPLAY_TOP_PAGER"]):?>
	<?=$arResult["NAV_STRING"]?><br />
<?endif;?>
<?foreach($arResult["ITEMS"] as $arItem):?>
	<?
	$this->AddEditAction($arItem['ID'], $arItem['EDIT_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_EDIT"));
	$this->AddDeleteAction($arItem['ID'], $arItem['DELETE_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_DELETE"), array("CONFIRM" => GetMessage('CT_BNL_ELEMENT_DELETE_CONFIRM')));
	?>
		<div class="col col-md-4 <?if($i > 0){?>col-md-offset-1<?} ?>" id="<?=$this->GetEditAreaId($arItem['ID']);?>">
		<img src=""PREVIEW_PICTURE"]["SRC"]?>" alt=""PREVIEW_PICTURE"]["ALT"]?>" title=""PREVIEW_PICTURE"]["TITLE"]?>" class="thumbnail">
			<div class="caption">
			<h3><?echo $arItem["NAME"]?></h3>
			<P><?=$arItem["PROPERTIES"]["POSITION"]["VALUE"]?></P>
			</div>
		</div>

<?
$i++;
if ($i >= 5) {
   $i = 0;
?>
   </div><div class="row">
<?
}
?>
<?endforeach;?>

<?
if ($i > 0) {
?>
   </div>
<?
}
?>
<?if($arParams["DISPLAY_BOTTOM_PAGER"]):?>
	<br /><?=$arResult["NAV_STRING"]?>
<?endif;?>
</div>

Мы не стали заморачиваться с выносом кода свойства в параметры, а так же с настройкой количества элементов в строке, чтобы не усложнять шаблон компонента.
Как видите, в нём практически ничего не осталось от первоначального шаблона списка новостей (и он гораздо легче громоздкого компонента каталога).

Не забудьте удалить ненужную более папку /bitrix/templates/whitesquare-bootstrap/images/team/ с картинками в шаблоне после перевода блока с персонами на инфоблок!

Текст страницы ABOUT

Поскольку у нас нет понимания какие функции выполняют остальные элементы страницы, должна ли появляться случайная цитата или, скажем, должны ли картинки вести в фотогалерею, мы пойдём по простому пути.
Весь контент останется статичным, мы лишь добавим несколько стилей, чтобы будущие редакторы могли работать со страницей с большим удобством.
Для этого воспользуемся файлом стилей сайта, приложенном к нашему шаблону /bitrix/templates/whitesquare-bootstrap/styles.css (или административным разделом):
Поскольку этот файл используется для применения CSS к контенту в том числе в визуальном редакторе, нам придётся «забыть» о каскадности CSS и прописать стили без учёта вложенности элементов.
Например, цитата станет выглядеть так:
.jumbotron {
            border-radius: 0;
              	padding: 0;
            margin: 0;
font-size: 18px;
font-weight: 200;
background-color: #29c5e6;
box-sizing: border-box;
color: #ffffff;
line-height: 2.1428571435;
display: block;
box-sizing: border-box;
font-family: Tahoma, sans-serif;

            blockquote {
                border-left: none;

                p {
                    font: 300 italic 33px @brand-font;
                    text-transform: uppercase;
                    margin-bottom: 0;
                    color: #ffffff;
                }

                small {
                    display: block;
                    text-align: right;
                    color: #1D8EA6;
                    color: #1D8EA6;
                    font: 300 20px @brand-font;

                    &:before {
                        content: '';
                    }
                }
            }
        }


Для того, чтобы редакторы могли сами применить этот стиль с помощью виз редактор необходимо добавить в файл .styles.php в корне шаблона массив стилей:
<?
return array(
	"jumbotron" => "цитата",
);
?>

Или через инструмент редактирования шаблона (вкладка «стили сайта»):


Наводим марафет


С целью немного облегчить работу редакторов можно создать в шаблоне сайта папку /page_templates/, где будут находиться шаблоны страниц, которые можно создавать ан проекте по умолчанию.
Шаблон страницы представляет из себя обычный php файл, идентичный странице в публичной части.
Помимо шаблонов необходимо так же разместить файл .content.php с массивом всех возможных шаблонов страниц. В нашем случае это будет:
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?><?
IncludeTemplateLangFile(__FILE__);
$TEMPLATE["about.php"] = Array("name"=>GetMessage("about"), "sort"=>1);
?>

Не забудем создать языковые файлы!
  • /bitrix/templates/whitesquare-bootstrap/lang/ru/page_templates/.content.php
  • /bitrix/templates/whitesquare-bootstrap/lang/ru/page_templates/.content.php


Для того чтобы шаблон не был неопознанным объектом для имеющих доступ к административному разделу оформим файл описания и приложим скриншот! Они подхватятся автоматически:
  • Описание — description.php в корне шаблона
    <?$arTemplate = array(
    	"NAME" => "Шаблон 1 страницы для ХабраХабр",
    	"DESCRIPTION" => "Шаблон на основе Bootstrap вёрстки в светло-синих тонах",
    	"SORT" => 100,
    );
    ?>
    
  • Скриншот — screen.gif в корне шаблона


Вот собственно и всё!


Мы натянули готовую HTML вёрстку Bootstrap на 1С-Битрикс, сверстали страницу и получили полноценный шаблон!

Послесловие



Статья получилась очень длинная, поэтому очень непросто вычитать все неточности и опечатки. Если вы нашли ошибку – напишите мне в личку, и я с удовольствием её исправлю!
Огромное спасибо Mirantus за оригинальную статью и готовую вёрстку, которую я смог взять за основу!
В качестве небольшого бонуса в GitHub проекте помимо собственно шаблона и страниц я разместил папку IMPORT_DATA, в которой содержится дамп демо-данных для единственного инфоблока с членами команды, фигурировавшего в статье. Вы можете импортировать его как XML на странице /bitrix/admin/iblock_xml_import.php?lang=ru

Полезные ссылки:

Теги:
Хабы:
+11
Комментарии 8
Комментарии Комментарии 8

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн