Еще раз повторюсь, что с revolution я до этих пор никогда не работал, а растягивать проект особо не хотелось, поэтому все решения были сделаны впопыхах. Скорее всего, я что-то делал не так. А что именно — хотелось бы узнать в комментариях.
Для начала поставим задачу. Итак, имеется несколько доменов. Каждый домен это набор страниц независимых друг от друга, т. к. нет меню, списка статей, авторизации и т. п. Стандартных решений. т. е. 1 страница это конкретное описание чего-либо: подписка на рассылку, описание товара, письма которые получают подписчики и т.п. Но есть одно существенное НО — на этих самых самостоятельных страницах по принципу кольца предлагается какой-либо товар характеризующийся таким параметрами, как: цена, ссылка на оформление заказа, фотография товара. Периодически значения данных параметров меняются (цена по акции, новая версия товара, цена для сплит-теста и т. д.).
Сразу же приходит на ум следующее решение
Решение 1. Выделяется один основной домен (акцептор) на котором создается каталог товаров. Акцептор не обязательно, афишировать. Он может быть и техническим. В нужных местах с доноров вставить запрос данных с акцептора. PROFIT.
Это стандартное решение, которые приходит на ум, но т. к. у нас все-же речь идет про MODX и я очень хотел попробовать мультисайтовость в revolution ветке, то продумал следующее решение:
Решение 2. Создам базу в которой буду хранить свой mini каталог товаров. А далее, банальным select … from … where … достану в нужный момент данные. По сути это решение производное от первого решения, но все-же немного другое. Помимо всего прочего, при мультисайтовости в revolution можно было использовать одни и картинки/шаблоны многократно.
Начало реализации 2 решения стандартное: контексты → параметры контекстов → создание часто используемых шаблонов → загрузка картинок и создание документов.
Когда дело дошло до создания той самой базы пришло понимание — с наскоку свой компонент я не напишу. Тем более, для решения этой задачи у меня было всего пару часов. Поэтому немного нервно покурив решил воспользоваться наборами параметров.
Стандартный и «правильный» подход тут следующий: для товара Х создается набор Х с параметрами A,B,C. Затем создается сниппет GetParam следующего содержания
<?php if(isset($$key)){ return $$key; }
к которому добавляется тот самый набор Х. Затем, в нужном месте страницы вставляется вызов [[!GetParam@X? &key=`A`]]
Все работает как нужно, но т. к. проект делается для себя. И в будущем, когда будет готов компонент не хочется тратить время на переделывание таких вызовов для работы со своей базой. Поэтому я набросал сниппет извлекающий данные через объекты. Таким образом вызов у меня теперь выглядит так:
<?php $id=isset($id)?$id:''; $param=isset($param)?$param:''; if($id!='' && $param!=''){ $propSet = $modx->getObject('modPropertySet',array('name'=>$id)); if($propSet!==NULL){ $value = $propSet->getProperties(); return isset($value[$param])?$value[$param]:''; } } return '';
Пока я разбирался с этой основной задачей нашел «элегантный» способ организовать сплит-тест 2 страниц средствами движка. Знатоки revolution уже наверное догадались, что речь пойдет про документы типа «символическая ссылка». И как можно догадаться, в то поле, куда вписывается ID страницы я вставил вызов сниппета.
<?php $list=isset($list)?explode(',',$list):array(); $id=''; if(isset($cookie) && isset($_COOKIE[$cookie])){ $id=$_COOKIE[$cookie]; } if($id==''){ $id=array_rand($list); if(isset($cookie)){ setcookie($cookie,$id,time()+365*24*3600); } } return $list[$id];
Все бы здорово, но данный подход приемлем только в случае, если у нас шаблон «символической ссылки» совпадает с шаблоном реального документа. А это невозможно, если сравниваются 2 документа абсолютно разные по дизайну. Поэтому в некоторых случаях приходилось обходиться всем известным типом ресурса «ссылка». Соответственно вызов сниппета меняется на [[~[[!Random? &list=`86,49` &cookie=`vsapns`]]]]
Но тут есть маленькая хитрость. На вкладке настройки у документа типа «ссылка» появляется поле в котором указан header отправляемый при запросе этого документа. По умолчанию там написано HTTP/1.1 301 Moved Permanently. Меняем его на HTTP/1.1 307 Temporary Redirect. Это необходимо для того, чтобы по завершению сплита пользователь принял участие в новом сплите. А не редиректился на старую оттестированную страницу.
Статья получается длинная, а практических советов мало. Поэтому без лирики перейдем сразу к favicon.ico. Всем известно, что если на странице html коде явно не указан адрес иконки, то браузер ее попытается загрузить по адресу /favicon.ico Есть решение, если не хочется отдавать 404 ошибку или одну и ту же иконку для всех сайтов.
Алгоритм следующий
- Создаем в админке новый тип содержимого ICO с расширением файла .ico и MIME типом image/x-icon
- В нужном контексте создаем новый статический ресурс
-
- Местонахождение содержимого: встроенный
- Тип содержимого: ICO
- Тип ресурса: статичный ресурс
- Псевдоним: favicon
- Статический ресурс: указываем путь к нужной favicon
Таким образом, по адресам test1.example.com/favicon.ico и test2.example.com/favicon.ico мы получаем разное содержимое. Аналогично делается и с robots.txt. Только там тип ресурса выбирается text.
т. к. шаблонов для страниц и картинок у нас не много и они используются на всех доменах в данной инсталляции было решено грузить всю статику с определенного домена. Для этого я набросал небольшой плагин к которому необходимо создать параметр StaticNewUrl со значением домена с которого будем грузить статику.
if($modx->event->name=='OnWebPagePrerender'){ $html = &$modx->resource->_output; $replaceD=array(); preg_match_all('#src=(?:"|\')(.*?)>#',$html,$matches); foreach($matches[1] as $item){ if(substr($item,0,1)!='/'){ continue; } if(substr($item,0,2)!='//'){ $replaceD[md5($item)]=$item; } } preg_match_all('#<link.*?href=(?:"|\')(.*?)>#',$html,$matches); foreach($matches[1] as $item){ if(substr($item,0,1)!='/'){ continue; } if(substr($item,0,2)!='//' && substr($item,0,12)!='/favicon.ico'){ $replaceD[md5($item)]=$item; } } array_unique($replaceD); foreach($replaceD as $item){ $html=str_replace($item,$StaticNewUrl.substr($item,1),$html); } }
Ну а раз взялись за оптимизацию загрузки статики, то грех не перенести с evolution ветки
if($modx->event->name=='OnWebPagePrerender'){ $flag=true; if(isset($tvHtmlInLine) && (int)$tvHtmlInLine>0){ $id = $modx->resource->get('id'); $tvs = $modx->getObject('modTemplateVarResource',array('tmplvarid'=>(int)$tvHtmlInLine, 'contentid'=>$id)); if($tvs && 0==$tvs->get('value')){ $flag=false; } } if($flag){ $html = &$modx->resource->_output; $html = preg_replace('|\s+|', ' ', $html); $html = str_replace('> <','><',$html); } }
Правда с установкой тут все немного сложнее, т. к. придется создать TV параметр. Хочу обратить внимание, что плагин вытягивает контент и на страницах с шаблоном blank. Поэтому для целей, где используется данный шаблон и нельзя вытягивать контент в 1 строку (файл robots.txt, например) я создаю новый одноименный шаблон с содержимым [[*content]]. В общем кому интересны подробности — велком в личку или спрашивайте прямо в комментариях.
В заключении хочу поделиться небольшим сниппетом для тех, кто любит на сайте вставлять копирайты с текущей датой.
<?php //Example: [[Copyright? &date=`2010` &sep=`-`]] if(!isset($time)){ $time=time(); } $now=date($format,$time); $out=''; if(isset($date) && $date!=$now){ $out.=$date; if(isset($sep)){ $out.=$sep; } } $out.=$now; return $out;
ссылка на оригинал статьи http://habrahabr.ru/post/156643/
Добавить комментарий