[EVO] Смена шаблона на лету на мобильный

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

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

Первый плагин ChangeTemplateStep1

global $modx;

$phoneversion = 0;

session_start();

if (isset($_SESSION['phoneversion'])){
	$phoneversion = $_SESSION['phoneversion'];
} else {
	require_once $_SERVER['DOCUMENT_ROOT'].'/assets/libs/mobiledetect/Mobile_Detect.php';
	$detect = new Mobile_Detect;
	if (($detect->isMobile())&&(!$detect->isTablet())){
		$phoneversion = 1;			
	}
	$_SESSION['phoneversion'] = $phoneversion;
}

if ($phoneversion == 1){
	$_GET['mobile'] = 'true';
}


Небольшое описание:

При загрузке страницы проверяем сессию, содержится ли там флаг мобильного/не мобильного устройства.
Если флага нет, то проверяем, чем пользователь зашел на сайт. Я для этого использовал библиотеку Mobile_Detect.
В моем случае нужны были только телефоны, для планшетов использовался стандартный шаблон. Ставим флаг в сессии. Далее, если у нас телефон — то добавляем в GET дополнительный параметр.
Теперь модикс будет создвать два кеш файла, для мобильной и обычной версии.
(В настройках способ кеширования страниц должен быть выбран с учетом GET параметров)

Второй плагин подменяет шаблон при загрузке страницы. Вешается на событие OnLoadDocumentObject. Данное событие вызывается только при первоначальной загрузке страницы из базы, а при загрузке из кеша не срабатывает. Но нам достаточно вызвать его только один раз. Страницы кешируются отдельно, в зависимости от типа устройства.

Второй плагин ChangeTemplateStep2

global $modx;

$tempalteArray = array(4 => 16, 7 => 18, 8 => 19, 9 => 20, 11 => 21, 12 => 22);

$templateId = $modx->documentObject['template'];

if (isset($tempalteArray[$templateId])){
	
	session_start();
	
	if (isset($_SESSION['phoneversion'])){
		if ($_SESSION['phoneversion'] == 1){
			$templateNewId = $tempalteArray[$templateId];
			$modx->documentObject['template'] = $templateNewId;			
		}
	}	
	
}


Небольшие пояснения:
Массив tempalteArray содержит связку стандартных шаблонов с мобильными. Ключи — ИД стандартных шаблонов, значение — мобильных.
Первым делом проверяем, есть ли шаблон на подмену, если есть, то мобильная ли версия нужна, и если она, то подменяем шаблон. Создастся мобильная страничка, сохранится в кеш. И потом уже будет тянуться из него.

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

P.S. Есть один момент, который надо учесть TV-шки должны быть привязаны к обоим шаблонам и обычному и мобильному.

Коментарии и отзывы приветствуются.

22 комментария

avatar
Достойно жизни однозначно.
А как сказывается на производительности на больших сайтах?
avatar
По факту только дублируются кеш файлы, т.е их будет в 2 раза больше, на каждый шаблон свой. Запросов в плагинах нет и на производительность они особо не повлияют.
avatar
Немножко рефакторинга:

/*
Плагин: ChangeTemplate
Описание: Смена шаблона на мобильный при загрузке страницы
События: OnWebPageInit, OnLoadDocumentObject
Конфигурация: &originalTemplates=Стандартные шаблоны;string; &mobileTemplates=Мобильные шаблоны;string;
Параметры конфигурации: Списки оригинальных и мобильных шаблонов через запятую.
Используемые библиотеки: MobileDetect - http://mobiledetect.net/ нужно разместить файл Mobile_Detect.php в папке /assets/libs/mobiledetect/
*/

global $modx;

if ($modx->event->name == 'OnWebPageInit'){
	
	$mobileversion = 0;
	
	if (isset($_SESSION['mobileversion'])){
		$mobileversion = $_SESSION['mobileversion'];
	} else {
		require_once $_SERVER['DOCUMENT_ROOT'].'/assets/libs/mobiledetect/Mobile_Detect.php';
		$detect = new Mobile_Detect;
		if (($detect->isMobile())&&(!$detect->isTablet())){
			$mobileversion = 1;
		}
		$_SESSION['mobileversion'] = $mobileversion;
	}	

	if ($mobileversion == 1){
		$_GET['mobileversion'] = 1;
	}	

}

if ($modx->event->name == 'OnLoadDocumentObject'){
	
	if ((!isset($originalTemplates))||($originalTemplates == '')||(!isset($mobileTemplates))||($mobileTemplates == '')){ return ; }	
	
	$originalArray = explode(',',$originalTemplates);
	$mobileArray = explode(',',$mobileTemplates);
	
	$templatesArray = array_combine($originalArray,$mobileArray);
	
	$templateId = $modx->documentObject['template'];

	if (isset($templatesArray[$templateId])){

		if (isset($_GET['mobileversion'])){
			$templateNewId = $templatesArray[$templateId];
			$modx->documentObject['template'] = $templateNewId;
		}

	}

}


Все совмещено в один плагин, настройки шаблонов вынесены в конфигурацию плагина. Убрано лишнее)
avatar
что то у меня никак не получается запустить этот плагин. Что я могу сделать не так?
в конфигурациях указал ID шаблона для обычной версии и мобильной.
События повесил.
Файл Mobile_Detect.php скачал и загрузил. Что я мог сделать не так?
avatar
У меня не работает даже упрощенная версия плагина из 2х строчек

global $modx;
$modx->documentObject['template'] = 29;
Комментарий отредактирован 2016-05-14 14:21:05 пользователем hplg
avatar
После долгого изучения вопроса выяснил — это бага в новых версиях движка на событие OnLoadDocumentObject.
avatar
Из плагина нужно вернуть измененный массив documentObject.
avatar
Дело в том что даже если создать пустой плагин на событие documentObject, то мы получаем белый лист, или надпись [*content*] вместо сайта.
Я вернул код от рабочего парсера предыдущих версий и все заработало как надо. Сейчас Диме напишу.
avatar
А ну я понял вроде. Значит это фича такая в новых версиях, и многие плагины надо переписывать. Не есть хорошо. Предупреждать надо :)
avatar
Вообще ничего не пашет на последних версия сборки от Дмитрия. Автор отзовись!
avatar
Короче, надо еще вот так в конце одну строчку добавить для новых версий движка.

$modx->documentObject['template'] = $templateNewId;
$e->output(documentObject());
Комментарий отредактирован 2016-05-19 11:58:40 пользователем Grinyaha
avatar
Что-то все равно не пашет :D Я уже запутался.
avatar

$documentObject['template'] = $templateNewId;
$e->_output = $documentObject;
avatar
И так тоже не пашет, к сожалению.
avatar
$modx->documentObject['template'] = $templateNewId;
$modx->event->output($modx->documentObject);
Комментарий отредактирован 2016-05-19 13:10:55 пользователем webber
avatar
Тоже самое. Выдает надпись [*content*] на белом листе.
avatar
Обычно это значит, что нет шаблона. Сделайте перед output

print_r($modx->documentObject);
— есть ли там вообще объект :)
avatar
И заодно
echo '<hr>' . $templateNewId . '<hr>';
— что это вообще такое, может там пусто? Поставьте вместо этого любой существующий id шаблона.
avatar
Ну как ни странно. Я в парсере вернул код от более ранней версии, и все нормально переключается что с мобильного что с компа.
avatar
Глянул код — раньше было

if($isPrepareResponse==='prepareResponse') $this->documentObject = & $documentObject;
$this->invokeEvent('OnLoadDocumentObject');
if ($documentObject['template']) {...}


потом стало


if($isPrepareResponse==='prepareResponse') $this->documentObject = & $documentObject;
$out = $this->invokeEvent('OnLoadDocumentObject', compact('method', 'identifier', 'documentObject'));
if(is_array($out)){
    $documentObject = $out;
}
if ($documentObject['template']) {...}


т.е. теперь надо возвращать объект, чтобы он изменился, а раньше он менялся без возвращения :)
avatar
Да, и выше все что предлагали комрады не заработало в итоге :)
avatar
Похоже OnLoadDocumentObject не работает до сих пор :(
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.