Как сделать AMP всего сайта на Битрикс

Задача - сделать AMP версию всего сайта на базе 1С-Битрикс и соблюсти следующие требования:

  1. Содержание AMP страниц должно изменяться вместе с изменением оригинальных и соответствовать оригинальным;
  2. Визуально страницы, чтобы повторяли оригинальный дизайн хоть и в облегченном виде;
  3. В AMP нужно превратить как динамические страницы , генерирующиеся компонентами из инфоблоков (например: новости), так и статические страницы с контентом в теле страницы.

1. Автоматический парсинг

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

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

2. Автономные AMP страницы

Следующий вариант, чтобы формально соблюсти требования поисковых систем по наличию AMP, сделать их как отдельный продукт. Они могут быть как полностью статичные, так и с использованием механизмов битрикса.

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

Для реализации проделал следующие шаги.

1. Обеспечил обработку URL с префиксом /amp/.

Для каждого URL должен быть аналог AMP, например: domain.com/about/ и domain.com/amp/about/, но вести эти оба URL должны на одну папку - /about/.

Реализую с помощью mod_rewrite в .htaccess, в случае обращения к URL с /amp/ делаю rewrite к соответствующим папкам без AMP и добавляю переменную HTML_TYPE=AMP , которую дальше буду использовать в init.php.

Пример .htaccess для обработки AMP

    <IfModule mod_rewrite.c>
        RewriteEngine On
        
        # Google AMP
        
        # Правило для URL вида /amp/about/delivery.php
        RewriteRule ^amp/(.+)/(.+)\.(php|html)$ $1/$2.$3?HTML_TYPE=AMP [L,QSA]

        # Правило для URL вида /amp/about/
        RewriteRule ^amp/(.+)/?$ $1/index.php?HTML_TYPE=AMP [L,QSA]

        # Правило для главной
        RewriteRule ^amp/?$ index.php?HTML_TYPE=AMP [L,QSA]
    </IfModule>

2. Научил битрикс понимать и работать с AMP страницам

Две основные проблемы, которые нужно решить:

  • весь CSS сделать inline в <head>
  • удалить весь Javascript

Объявляю две константы в init.php, которые дальше буду использовать в шаблоне и компонентах: HTML_TYPE и URL_PREFIX.

    <?php
    // Если в URL есть AMP, то объявляю две константы, чтобы по первой делать условие в шаблонах, а вторую подставлять в ссылки в шаблонах и страницах

    if ($_REQUEST["HTML_TYPE"] == "AMP")
    {
      define("HTML_TYPE",$_REQUEST["HTML_TYPE"]);
      define("URL_PREFIX","/amp");
    }

    if (!defined("HTML_TYPE"))
    {
      define("HTML_TYPE","");
      define("URL_PREFIX","");
    }
    ?>

Перенёс CSS в inline

Для переноса CSS в inline делаю функцию AMP_CSS на событие OnEpilog, которую дальше буду использовать в шаблоне.

    <?php
    AddEventHandler("main","OnEpilog","AMP_CSS");

    function AMP_CSS()
    {
    	global $APPLICATION;
    				
    	if (defined("HTML_TYPE") and HTML_TYPE == "AMP")
    	{
    		// Получаю все подключенные стандартами методами битрикса CSS, для этого использую не документированную функцию GetCSS;

    		$CSS_FILE = $APPLICATION->GetCSS();

    		if (!empty($CSS_FILE))
    		{
    			// Извлекаю адрес из href и получаю их содержимое
    			preg_match_all('/href="(.+?)\?.+?"/isu',$CSS_FILE,$CSS_FILE_MATCHES);

    			if (sizeof($CSS_FILE_MATCHES[1]) > 0)
    			{
    				foreach($CSS_FILE_MATCHES[1] as $CSS_FILE_MATCHES_VAL)
    				{
    					$CSS .= file_get_contents($_SERVER['DOCUMENT_ROOT'].$CSS_FILE_MATCHES_VAL);
    				}
    			}

    			if (!empty($CSS))
    			{
    				$CSS_TMP = str_replace(array('!important'),'',$CSS);

    				if (!empty($CSS_TMP))
    				{
    					$CSS = $CSS_TMP;
    				}
    			}
    		}


    		// Считаю размер CSS для отладки верстальщику,
				// тк есть лимиты на стороне гугла в 70 кб

    		if (!empty($CSS))
    		{            
    			$CSS =
    			'
    				<style amp-custom>
    				/*'.mb_strlen($CSS).'*/
    				'.$CSS.'
    				</style>
    			';
    		}
    				
    		return $CSS;
    	}
    }
    ?>

Удалил Javascript

Собственный Javascript в AMP версии подключать не буду ни в шаблоне ни в компонентах, а служебные "прилетающие" из ядра битрикса - удаляю на событии OnEndBufferContent.

    <?php
    AddEventHandler("main","OnEndBufferContent","OnEndBufferContentHandler");

    function OnEndBufferContentHandler(&$content)
    {
    	$content = OnEndBufferContentParse($content);
    }

    function OnEndBufferContentParse($HTML)
    {
    	if (defined("HTML_TYPE") and HTML_TYPE == "AMP")
    	{
      		$HTML_TMP = preg_replace('/(<script type="text\/javascript".*?<\/script>|<script>.*?<\/script>)/isu',"",$HTML);
    		if (!empty($HTML_TMP)) {$HTML = $HTML_TMP;}
    	}

    	return $HTML;
    }
    ?>

Отключаю композитный кеш для AMP версии, т.к. для его корректной работы нужен Javascript, а он в AMP не поддерживается и выше удалён.

Дополнительно делаю свойство AMP_ENABLE в "Структуре сайта", его буду использовать на переработанных страницах для включения ссылки на AMP страницу в <head>.

Данное свойство обрабатываю на событии OnEpilog.

    <?php
    AddEventHandler("main","OnEpilog","META_AMP");

    function META_AMP()
    {
    	global $APPLICATION;

    	$URL_CANONICAL = $_SERVER['REQUEST_URI'];

    	$AMP_ENABLE = $APPLICATION->GetProperty("AMP_ENABLE");

    	// Для AMP страниц указываю canonical на НЕ AMP
    	if (defined("HTML_TYPE") and HTML_TYPE == "AMP")
    	{
    		$APPLICATION->SetPageProperty("canonical",'https://'.SITE_SERVER_NAME.str_replace('/amp','',$URL_CANONICAL));
    	}
    	else
    	{
    		// Для НЕ AMP страниц, если они включены, указываю ссылку на AMP
    		if ($AMP_ENABLE == "Y")
    		{
    			$APPLICATION->AddHeadString('<link rel="amphtml" href="https://'.SITE_SERVER_NAME.'/amp'.$URL_CANONICAL.'" />',true);
    		}
    	}
    }
    ?>

3. Переработал шаблон сайта

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

В шаблоне сайта делаю условие для AMP и обычных страниц. Условие для AMP Условие для обычных страниц

Основное отличие шаблонов с технической стороны, в функциях в <head>.

В обычном использую общую функцию, которая отображает всю мету:

<? $APPLICATION->ShowHead(); ?>

В AMP использую отдельные и плюс сделанную выше AMP_CSS:

    <? $APPLICATION->ShowMeta("robots"); ?>
    <? $APPLICATION->ShowMeta("keywords"); ?>
    <? $APPLICATION->ShowMeta("description"); ?>
    <? $APPLICATION->ShowLink("canonical"); ?>
    <? $APPLICATION->ShowHeadStrings(); ?>
    <? $APPLICATION->AddBufferContent("AMP_CSS"); ?>

ShowHead в AMP использовать нельзя, т.к. в ней "придут" не валидные для AMP элементы: <script> и ссылки на CSS.

Дальше подключаю необходимые Javascript и CSS для обычной версии: Подключение Javascript и CSS для обычной версии

Для AMP версии - CSS и разрешённые AMP JS-компоненты: Подключение CSS и JS-компонентов в AMP шаблоне

У AMP есть компоненты отвечающие за разные действия, например, за работу форм (компонент: amp-form), подключаю их с параметром data-skip-moving="true", чтобы они оставались в <head>, а не ушли вниз при объединении (если данная опция включена в настройках битрикса).

4. Переработал компоненты

Приведу пример на базе стандартного компонента Списка статей.

Копирую компонент в папку с шаблоном, добавляю файл .parameters.php и в него параметр HTML_AMP: Параметр HTML_TYPE для кеширования AMP страниц

Данный параметр нужен для корректной работы кеша, без него будет закеширован либо один либо другой вариант. Параметр HTML_TYPE для кеширования AMP страниц

В шаблоне компонента делаю условия, как и выше в шаблоне сайта. Переработанный компонент Список статей для поддержки AMP

В таком ключе необходимо переработать все компоненты сайта.

5. Переработал страницы

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

Для страниц, где есть текст в теле страниц, делаю компонент "Произвольный HTML" в котором должно быть 2 обязательных параметра HTML и HTML для AMP. Параметры компонента "Произвольный HTML"

Внутри он выглядит так: Код компонента "Произвольный HTML

Вместо любых текстов в теле страницы нужно использовать его. При этом можно как убрать весь текст сразу, либо собрать страницу из нескольких таких блоков. Не обязательно полностью дублировать всё содержимое обычной версии в AMP, для последней можно сделать сокращенный вариант.

Если страницы имеют сложную структуру, и использование одного компонента "Произвольный HTML" не очень удобно, то нужно сделать набор статичных компонентов со стандартными html-блоками в дизайне сайта, которые можно использовать по сайту повсеместно. Они также должны иметь 2 версии внутри.

6. Включил AMP

Готовые AMP страницы включаю через параметр AMP_ENABLE:

У них в <head> появляется ссылка на AMP: Ссылка в указывающая на наличие AMP страницы

При этом на AMP страницах появляется ссылка на основную: Canonical ссылка с AMP на основную страницу

На выходе любая страница собранная таким образом страница будет иметь актуальный контент.

Дальше страницы начнут индексироваться гуглом.

AMP поддерживает почти всё в CSS, за исключением ряда моментов (можно найти в официальной документации) и общего ограничения в объёме в 70 Кб на страницу.

По реализации, можно использовать общие стили для обеих версий. Можно для ряда стилей сделать классы с префиксом amp-. Можно на AMP версии подключать отдельные стили. Зависит от потребностей.

Javascript соответственно использую только на основной версии. На AMP использую JS-компоненты для форм, меню, увеличение картинок.

В ссылках (например, в меню в шаблоне) можно использовать объявленную выше константу URL_PREFIX:

Сайт Telegram