<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
			<channel>
			<title>Alto CMS/Alto CMS inside - как это устроено и работает</title>
			<link>https://altocms.ru/blog/inside/</link>
			<description><![CDATA[О том, как движок устроен изнутри, о его функционале, тонких настройках и особенностях]]></description>
			<language>ru</language>
			<managingEditor>vshemarov@gmail.com</managingEditor>
			<webMaster>noreply@altocms.ru</webMaster>
			<generator>Alto CMS v.1.5.0b1</generator>
							<item>
					<title>Как правильно модифицировать шаблон (скин) для себя</title>
					<guid isPermaLink="true">https://altocms.ru/t/1741/</guid>
					<link>https://altocms.ru/1741.html</link>
					<author>vshemarov@gmail.com</author>
					<description><![CDATA[По умолчанию в движке идет три скина: <strong>start-kit</strong>, <strong>expirience</strong>, <strong>exprience-simple</strong>.<br>
<br>
Все скины в той или иной степени можно модифицировать, не влезая особенно в код. Но иногда этого бывает мало. Если немного понимаешь в верстке, если понимаешь, как работает шаблонизатор <strong>Smarty</strong>, то нередко возникает соблазн где-то что-то подправить — в файлах шаблона, в стилях, в js-скриптах. И уж если это делать, то делать нужно так, чтоб при обновлении движка не убить все свои правки. И тут я расскажу именно об этом.<br>
<br>
Если кратко, то нужно создать свой скин и все правки выполнять в нем. Например, вы решили создать свой модифицированный скин на базе, скажем, <strong>experience</strong>.<br>
<br>
1) Придумайте название своему скину, скажем, <strong>myskin</strong>.<br>
2) Создайте директорию <strong>/common/templates/skin/myskin</strong> и скопируйте в нее файлы исходного скина (в нашем примере это <strong>/common/templates/skin/experience</strong>.<br>
3) В файле <strong>common/templates/skin/myskin/skin.xml</strong> в узле <strong>&#60;skin&#62;&#60;name&#62;&#60;lang&#62;</strong> задайте имя вашего скина — <strong>myskin</strong>.<br>
<br>
Теперь этот скин нужно задать для вашего сайта (либо в админке, либо в файле конфигурации <strong>app/config/config.local.php</strong>), и можно смело обновлять движок, не опасаясь, что обновления затрут ваши изменения в скине вашего сайта.<br>
<br>
UPD. Важное замечание: по умолчанию файлы стилей (.css) и скриптов (.ja) объединяются для ускорения загрузки, и может получиться так, что вы их меняете в шаблоне, а результата не видите. Чтобы этого избежать, на этапе активной разработки нужно отключить слияние .css/.js файлов и включить их принудительную обработку. Делается это в админке в настройках сайта:<br>
<img src="https://altocms.ru/uploads/images/00/00/02/2016/12/22/0u28289e9d-2caecc19-1a9b4bc1.jpg">]]></description>
					<pubDate>Fri, 18 Nov 2016 00:30:11 +0300</pubDate>
									</item>
							<item>
					<title>Про секретную админку, поддомены и прочие тонкости маршрутизации в Alto CMS</title>
					<guid isPermaLink="true">https://altocms.ru/t/1739/</guid>
					<link>https://altocms.ru/1739.html</link>
					<author>vshemarov@gmail.com</author>
					<description><![CDATA[<img src="https://altocms.ru/uploads/images/00/00/02/2016/11/13/0u14532463-7186738d-1d2e071f.png" align="right">Довольно часто встречаются такие вопросы:<br>
А как сделать, чтобы админка работала не по адресу <strong>site.com/admin</strong>, а по секретному адресу, который знаю только я? Или вопрос из этой же серии: как сделать, чтоб блоги открывались не по адресу <strong>site.com/blog/blabla</strong>, а, например, по адресу <strong>site.com/section/blabla</strong>?<br>
<br>
Все эти вопросы — из области настроек маршрутизации движка. И эта статья для тех, кто хочет лучше узнать, как работают эти настройки, чтоб извлечь из них мксимум пользы.<br>
<br>
В общих чертах, полагаю, большинство из вас понимает, как работает маршрутизатор (роутер): берет запрашиваемый URL, разбирает его на составляющие и вызывает нужный экшен. При этом обработка URL проходит через несколько наборов правил, которые могут задаваться в конфиг-файле (причем, именно в таком порядке):<br>
<ul><li>проверка правил внешнего редиректа</li><li>правила обработки доменов</li><li>обработка переопределения запроса («внутренний реврайтинг»)</li><li>внутренний редирект контроллеров (экшенов)</li><li>определение класса контроллера (экшена)</li></ul>
Теперь обо всем этом по порядку.<br>
<br>
<h5>Правила внешнего редиректа</h5>
О внешнем редиректе средствами движка, кстати, есть <a href="https://altocms.ru/1115.html">отдельная статья</a>, но раз уж пишем о настройках маршрутизации, то не будет лишним напомнить об этом и здесь.<br>
<br>
Вообще-то, эти правила лучше всего задавать в настройках хоста — в конфиге apache или nginx, либо в файле <strong>.htaccess</strong>. Но если по каким-то причинам вы не можете этого сделать (например, конфигурационные файлы не доступны вам для редактирования или просто боитесь трогать их, дабы не сломать все по неопытности), то вы можете настроить эти правила в конфигурационном файле движка. Обратите внимание, что здесь анализируется <strong>полный URL, включая протокол</strong>. Например:<br>
<pre class="prettyprint"><code>$config[&#39;router&#39;][&#39;redirect&#39;] = array(
    // проверка протокола и редирект с HTTP на HTTPS
    &#39;http://*&#39; =&#62; &#39;https://*&#39;,
    // редирект с одно адреса на другой с кодом 302 (по умолчанию используется код 301)
    &#39;http://site.com/perm-path/*.html&#39; =&#62; array(&#39;http://site.com/temp-path/*.html&#39;, 302),
    // задание редиректа с помощью регулярного выражения
    &#39;[~(.+/)blabla/(\d+).html$~]&#39; =&#62; &#39;$1$2.html&#39;,
);</code></pre>Как видите, правила для роутера можно задавать либо в простой форме (при этом можно использовать символ «*»), либо в виде регулярного выражения, но тогда нужно его обязательно поместить в квадратные скобки.<br>
<br>
<h5>Правила обработки доменов</h5>
При обработке этих правил анализируется <strong>только доменное имя</strong>, без протокола и без полного пути. Сразу приведем пример, из которого будет все ясно:<br>
<pre class="prettyprint"><code>$config[&#39;router&#39;][&#39;domain&#39;] = array(
    &#39;*.site.com&#39; =&#62; &#39;blog/*&#39;,
);
</code></pre>Думаем, особо не надо объяснять, что тут в качестве поддоменов работают блоги. Если нужно в поддомены поставить профили юзеров, то, соответственно:<br>
<pre class="prettyprint"><code>$config[&#39;router&#39;][&#39;domain&#39;] = array(
    &#39;*.site.com&#39; =&#62; &#39;profile/*&#39;,
);
</code></pre>Но если требуется, то можно и явно задавать правило для конкретного поддомена, например, так:<br>
<pre class="prettyprint"><code>$config[&#39;router&#39;][&#39;domain&#39;] = array(
    &#39;wiki.site.com&#39; =&#62; &#39;blog/wiki&#39;,
);</code></pre><br>
Но при работе с поддоменами есть несколько важных деталей:<br>
1) Альто-сайт обязательно должен быть в корне, т.е. именно site.com, но не site.com/alto<br>
2) URL для runtime-файлов должен быть относительным, а URL сайта должен задаваться явно:<br>
<pre class="prettyprint"><code>$config[&#39;path&#39;][&#39;root&#39;][&#39;url&#39;] = &#39;https://site.com/&#39;;
$config[&#39;path&#39;][&#39;runtime&#39;][&#39;url&#39;] = &#39;/_run/&#39;;
</code></pre>3) В шаблонах нужно правильно задавать адреса профилей юзеров и блогов. Т.е. вот так:<br>
<pre class="prettyprint"><code>&#60;a href=&#34;{$oUser-&#62;getProfileUrl()}&#34;&#62;Ссылка на профиль&#60;/a&#62;
&#60;a href=&#34;{route page=&#34;profile/username&#34;}&#34;&#62;Другой вариант ссылки на профиль&#60;/a&#62;
&#60;a href=&#34;{R::GetPath(&#34;profile/username&#34;)&#34;}&#62;Третий вариант ссылки на профиль&#60;/a&#62;
&#60;a href=&#34;{route page=&#34;profile&#34;}username&#34;&#62;А это НЕВЕРНЫЙ вариант&#60;/a&#62;</code></pre><br>
Аналогично для блогов:<br>
<pre class="prettyprint"><code>&#60;a href=&#34;{$oBlog-&#62;getLink()}&#34;&#62;Ссылка на блог&#60;/a&#62;
&#60;a href=&#34;{$oBlog-&#62;getUrlFull()}&#34;&#62;Синоним предыдущего варианта&#60;/a&#62;
&#60;a href=&#34;{route page=&#34;blog/blogname&#34;}&#34;&#62;Другой вариант ссылки на блог&#60;/a&#62;
&#60;a href=&#34;{R::GetPath(&#34;blog/blogname&#34;)&#34;}&#62;Еще вариант ссылки на блог&#60;/a&#62;
&#60;a href=&#34;{route page=&#34;blog&#34;}blogname&#34;&#62;А это НЕВЕРНЫЙ вариант ссылки&#60;/a&#62;</code></pre>Хоть это и очевидно, но на вмякий случай уточним, что если вы задумали обрабатывать домены/поддомены на уровне движка, то сервер у вас должен быть настроен так, чтобы эти доменны/поддомены были алиасами основного домена.<br>
<br>
<h5>Правила переопределения запроса или «внутренний реврайтинг»</h5>
Обычно этот набор правил используется для довольно тонкого тюннига маршрутизации. И анализируется только путь запроса. Например, для URL <strong>site.com/some-action/other-event/foo/bar/</strong> будет анализироваться <strong>some-action/other-event/foo/bar/</strong>. Например, с помощью такого правила в конфиге по умолчанию отсекается обработка движком несуществующих статических файлов:<br>
<pre class="prettyprint"><code>$config[&#39;router&#39;][&#39;uri&#39;] = array(
    // запрет обработки статичных файлов с заданными расширениями
    /* допустимые значения:
     *  - @ignore   - запрос игнорируется и его обработка прекращается
     *  - @die(msg) - обработка запроса прекращается с выдачей сообщения msg
     *  - @404      - обработка прекращается с выдачей кода 404
     */
    &#39;[~.+\.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)\/?$~i]&#39; =&#62; &#39;@404&#39;,
);</code></pre><br>
<h5>Внутренний редирект контроллеров</h5>
Это довольно простой вид правил, который используется чаще всего. Он указывает, с какого контроллера на какой нужно адресовать запрос. Например, мы хотим, чтобы на нашем сайте «блоги» назывались «разделами». И логично, если адрес раздела будет выглядеть не <strong>site.com/blog/blabla/</strong>, а, скажем, <strong>site.com/section/blabla/</strong>. Для этого задается очень простая настройка:<br>
<pre class="prettyprint"><code>$config[&#39;router&#39;][&#39;rewrite&#39;] = array(
    &#39;section&#39; =&#62; &#39;blog&#39;, // все, что запрашивается по адресу /section перенаправляется на обработчик /blog
);</code></pre>Другой пример: мы хотим, чтобы админка сайта вызывалась не по <strong>site.com/admin</strong>, а по секретному адресу, о котором никто не знает, например, <strong>site.com/secret-admin</strong>. Делаем так:<br>
<pre class="prettyprint"><code>$config[&#39;router&#39;][&#39;rewrite&#39;] = array(
    &#39;secret-admin&#39; =&#62; &#39;admin&#39;,
);</code></pre><br>
Но ведь эта переадресация не отменяет работу и по стандартному адресу — <strong>site.com/admin</strong>. Чтобы ее отменить, нужно добавить в конфиг следующее:<br>
<pre class="prettyprint"><code>$config[&#39;router&#39;][&#39;uri&#39;] = array(
    &#39;admin/*&#39; =&#62; &#39;@404&#39;,
);</code></pre><br>
Эта настройка говорит о том, что все обращения по старому адресу админки должны выдавать ошибку 404.<br>
<br>
<h5>Определение класса контроллера (экшена)</h5>
Ну, и, наконец, последний набор правил, который обрабатывается роутером, если запрос все же прошел через все предыдущие — мы можем для каждого контроллера задать класс, который будет его обрабатывать. Этот набор правил задается в секции <strong>router.page</strong> конфига нашего сайта. И по умолчанию запрос контроллера <strong>&#39;error&#39;</strong> обрабатывается классом <strong>ActionError</strong>, запрос <strong>registration</strong> — классом <strong>ActionRegistration</strong>, и т.д. Но если вы разработчик и пишете расширения для сайта, то вы вполне можете задать собственные обработчики контроллеров.<br>
<br>
И, в заключение, напомню еще раз порядок обработки правил:<br>
<ul><li>сначала обрабатываются правила внешнего редиректа (и это единственный набор правил, который может направить браузер по другому адресу, все остальные правила работают внутри движка, незаметно для глаз посетителя сайта)</li><li>затем проверяются правила обработки доменов (можем назначить соответствующий контролер любому домену или поддомену)</li><li>потом идет «внутренний реврайтинг» — внутри маршрутизатора перенаправляем что угодно куда угодно</li><li>внутренний редирект контроллеров — самый простой способ внутренней переадресации</li><li>определение класса контроллера — задаем, какой Action-класс будет непосредственно обрабатывать запрос</li></ul>]]></description>
					<pubDate>Sun, 13 Nov 2016 14:09:32 +0300</pubDate>
									</item>
							<item>
					<title>Принцип работы Alto CMS в картинках</title>
					<guid isPermaLink="true">https://altocms.ru/t/1568/</guid>
					<link>https://altocms.ru/1568.html</link>
					<author>vshemarov@gmail.com</author>
					<description><![CDATA[<img src="https://altocms.ru/uploads/images/00/00/02/2016/03/08/0u7f78c252-4c29511e-2b94c650.jpg"><br>
Каждый запрос, который получает движок, сначала обрабатывается <strong>роутером</strong> (Router). Примерно так же, как каждого посетителя в крупных компаниях встречает девушка на ресепшен, которая узнает, чего надо посетителю, какой у него вопрос, и затем направляет его к тому нужному менеджеру, так и <strong>роутер</strong> направляет запрос нужному <strong>экшену</strong> (Action). <strong>Экшен</strong>, приняв <s>посетителя</s> запрос, выясняет все подробности, проверяет права и проч., и, выполнив все необходимые формальности, делает запрос в «отдел комплектации» — в компонент <strong>модуль</strong> (Module). Далее, по запросу из модуля <strong>маппер</strong> (Mapper) находит и отгружает требуемые <strong>сущности</strong> (Entity). <strong>Модуль</strong>, если нужно, может несколько раз получить необходимые данные от <strong>маппера</strong>, скомпоновать их, как требуется и отдать <strong>экшену</strong>. Но и <strong>экшен</strong> может обратиться к разным <strong>модулям</strong> несколько раз с разными запросами.<br>
<br>
Получив все, что нужно, <strong>экшен</strong> поручает <strong>вьюеру</strong> (Viewer) доставить результат запроса посетителю сайта в красивой упаковке.<br>
<br>
Хоть сам роутер очень программно очень наворочен, его принцип, по сути, довольно прост. Чтоб не писать слишком много букв, вот картинка, которая многое проясняет:<br>
<img src="https://altocms.ru/uploads/images/00/00/02/2016/03/08/0u539d2000-78edea3c-717c9636.jpg"><br>
Т.е. нужный экшен по умолчанию определяется по той части URL, которая идет после имени домена. Конечно, есть возможность многое перенастроить и переопределить, но ключевой принцип остается неизменным: любой адрес любой страницы, в итоге, должен указывать на <strong>экшен</strong>, который будет обрабатывать эту страницу.<br>
<br>
Есть еще один очень важный компонент ядра движка — Engine. Фактически, все взаимодействие между разными компонентами (вызов модулей, формирование сущностей и проч.) — это все выполняется через Engine.<br>
<br>
Вот как можно это представить более схематично:<br>
<img src="https://altocms.ru/uploads/images/00/00/02/2016/03/08/0u55e4b3dd-476887fe-2fa5ba0e.jpg"><br>
Здесь Router, Engine, Action, Module, Mapper, Entity — это все компоненты движка.]]></description>
					<pubDate>Wed, 09 Mar 2016 00:11:14 +0300</pubDate>
									</item>
							<item>
					<title>Отслеживание ошибок — копаем глубже</title>
					<guid isPermaLink="true">https://altocms.ru/t/1386/</guid>
					<link>https://altocms.ru/1386.html</link>
					<author>vshemarov@gmail.com</author>
					<description><![CDATA[<img src="https://altocms.ru/uploads/images/00/00/02/2015/10/12/0u4b25ef0a-76f1ee0a-605e8603.png" align="right">Один из законов Мерфи гласит: все, что может сломаться, ломается. Поэтому иногда случается так, что на сайте, где все работало без проблем, вдруг возникают ошибки. А уж когда ведется активная работа над изменением сайта, то это и вовсе неизбежно.<br>
<br>
Поэтому всем, кто делает сайты на Альто очень полезно будет почитать статью <a href="https://altocms.ru/573.html">«Работа над ошибками» в Alto CMS</a>.<br>
<br>
Но с момента написания той статьи в движок были добавлены новые возможности, позволяющие еще лучше находить и понимать возникающие на сайте ошибки (эта статья пишется для версии 1.1.13). Для начала важно учесть, что дополнительный механизм отслеживания ошибок включается заданием константы <strong>DEBUG=1</strong>. Это можно сделать двумя способами:<br>
<br>
1) Добавить файл <strong>engine/config.defines.php</strong> такого содержания:<br>
<pre class="prettyprint"><code>&#60;?php
define(&#39;DEBUG&#39;, 1);</code></pre>2) В файл /index.php сразу после первой строки с <strong>&#60;?php</strong> добавить строчку:<br>
<pre class="prettyprint"><code>define(&#39;DEBUG&#39;, 1);</code></pre>Оба варианта работают совершенно одинаково, выбирайте, какой из них вам больше нравится.<br>
<br>
После этого движок будет работать в режиме отладки. Что вам это дает:<br>
<br>
<h5>Дополнительная информация в логах SQL-запросов</h5>
Если у вас включено логгирование SQL-запросов (конфиг-параметр <strong>sys.logs.sql_query=true</strong>), то в него дополнительно будет записываться информация, в каком конкретно месте движка вызывается SQL-запрос. Ведь ошибки в логике работы сайта могут заключаться и в том. что где-то неверно формируется запрос к базе данных. И эта опция поможет быстрее найти источник ошибочного запроса.<br>
<br>
<h5>Проверка подключаемых файлов на «UTF-8 without BOM»</h5>
Помните — все файлы движка должны быть в формате «UTF-8 without BOM». Очень распространенная ошибка (особенно среди новичков) — правка файлов в стандартном Блокноте Windows и запись в неверном формате. И эти файлы при подключении могут давать самый непредсказуемый эффект. Чтобы это обнаружить, нужно добавить в конфиг-файл <strong>app/config/config.local.php</strong> такую строку:<br>
<pre class="prettyprint"><code>$config[&#39;sys&#39;][&#39;include&#39;][&#39;check_file&#39;] = true;</code></pre>И тогда все подключаемые файлы будут предварительно проверяться, и в случае обнаружения проблем информация об этом будет записываться в файл ошибок <strong>error.log</strong>. Правда, тут есть нюанс: эта проверка будет выполняться, только если файл подключается средствами движка, т.к. одной из следующих функций: <strong>F::IncludeFile(...)</strong> или <strong>F::IncludeLib(...)</strong> (или через их аналоги — <strong>F::File_IncludeFile(...)</strong> или <strong>F::File_IncludeLib(...)</strong>).<br>
<br>
<h5>Проверка установки кук</h5>
Известно, что если до момента установки куки в PHP-скрипте был какой-то вывод, то кука не установится. И если включен отладочный режим, то движок, если кука не установлена, сделает соответствующую запись в лог ошибок. Более того, постарается определить, где именно (в каком файле и в какой строке) был вывод до установки куки и запишет соответствующую информацию в лог-файл.]]></description>
					<pubDate>Mon, 12 Oct 2015 13:17:41 +0300</pubDate>
									</item>
							<item>
					<title>Alto CMS и SEO — возможности «из коробки» и из плагинов</title>
					<guid isPermaLink="true">https://altocms.ru/t/1186/</guid>
					<link>https://altocms.ru/1186.html</link>
					<author>vshemarov@gmail.com</author>
					<description><![CDATA[Есть у меня подозрение, что многие админы сайтов, создаваемых на базе <a href="https://altocms.ru/871.html" title="<strong>Alto&nbsp;</strong><br>Если вы собираетесь создавать сайт и выбираете для этой цели CMS (или «движок», как еще говорят), то наверняка у вас возникает вопрос: «А чем же Alto лучше других CMS? И годится ли для моих задач?»&lt;br/&gt;
&lt;br/&gt;
Выбирая Alto CMS, вы получаете «из коробки» функционал, который в других движках достигается установкой множества плагинов:" class="term">Alto</a> CMS, просто не знают всех возможностей СЕО-оптимизации, которые заложены в функционал движка или дополняются бесплатными плагинами. Вот и решил я об этом рассказать. <h5>Файл robots.txt</h5>
Файл robots.txt идет прямо в комплекте с движком. Не стану утверждать, что это идеальный вариант, но рискну предположить, что он подойдет для большинства сайтов на <a href="https://altocms.ru/871.html" title="<strong>Alto&nbsp;</strong><br>Если вы собираетесь создавать сайт и выбираете для этой цели CMS (или «движок», как еще говорят), то наверняка у вас возникает вопрос: «А чем же Alto лучше других CMS? И годится ли для моих задач?»&lt;br/&gt;
&lt;br/&gt;
Выбирая Alto CMS, вы получаете «из коробки» функционал, который в других движках достигается установкой множества плагинов:" class="term">Alto</a> CMS. Но вы, разумеется, можете всегда отредактировать его, как посчитаете нужным.<br>
<br>
<h5>Тег &#60;title&#62;</h5>
По умолчанию значение тега &#60;title&#62; состоит из нескольких частей, разделенных знаком слеш — «/». Но в конфигурации движка можно задать правила, по которым формируется это значение.<br>
<pre class="prettyprint"><code>// максимальное число частей, из которых состоит тег &#38;lt;title&#38;gt;
$config[&#39;view&#39;][&#39;html&#39;][&#39;title_max&#39;]   = 0;       

// разделитель между частями тега &#38;lt;title&#38;gt;
$config[&#39;view&#39;][&#39;html&#39;][&#39;title_sep&#39;]   = &#39; / &#39;;   

// строка, которая всегда добавляется в конец значения тега &#38;lt;title&#38;gt;
$config[&#39;view&#39;][&#39;html&#39;][&#39;title&#39;]       = &#39;___view.name___&#39;;</code></pre><br>
<h5>Мета-тег &#60;description&#62;</h5>
По умолчанию значение мета-тег &#60;description&#62; для статей формируется из нескольких начальных слов текста. Число слов задается в конфиг-файле:<br>
<pre class="prettyprint"><code>// количество слов из статьи для вывода в мета-тег &#38;lt;description&#38;gt;
$config[&#39;view&#39;][&#39;html&#39;][&#39;description_max_words&#39;] = 20;</code></pre><br>
<h5>Структура URL статей и ЧПУ</h5>
Вид URL статей задается в админке. Подробнее об этом можно прочитать в статье <a href="https://altocms.ru/41.html">ЧПУ в Alto CMS — в стиле Livestreet, Wordpress, NiceURL и вообще как угодно</a>.<br>
<br>
<h5>Редирект на новые адреса</h5>
Если вы переехали на Альто с другого движка, где была иная структура адресов, или решили на сайте изменить правила формирования URL, либо еще по каким причинам у вашего сайта изменились адреса, то вы можете задать правила редиректа со старых адресов на новые, используя настройки, описанные в статье <a href="https://altocms.ru/1115.html">Внешний редирект средствами движка</a><br>
<br>
Это то, что вы можете использовать в <a href="https://altocms.ru/871.html" title="<strong>Alto&nbsp;</strong><br>Если вы собираетесь создавать сайт и выбираете для этой цели CMS (или «движок», как еще говорят), то наверняка у вас возникает вопрос: «А чем же Alto лучше других CMS? И годится ли для моих задач?»&lt;br/&gt;
&lt;br/&gt;
Выбирая Alto CMS, вы получаете «из коробки» функционал, который в других движках достигается установкой множества плагинов:" class="term">Alto</a> CMS прямо «из коробки» без каких-либо дополнительных плагинов. Но есть еще несколько <strong>бесплатных</strong> плагинов, о которых, как минимум, стоит знать.<br>
<br>
<h5>Плагин sitemap</h5>
Формирует карту сайта, позволяет указать, какие разделы стоит включать в карту, задать такие параметры, как частоту обновления, приоритет индексирования и т.д.<br>
<iframe src="https://altocms.ru/addons/frame/85/?width=800" width="800" height="200"></iframe>
<h5>Плагин Seopack — Управление SEO-параметрами страниц</h5>
Для любой страницы сайта вы можете задать совершенно произвольное значение тега &#60;title&#62;, а также мета-тегов &#60;description&#62; и &#60;keywords&#62;. Эти значения привязываются к URL страницы и при ее отображении выводятся в HTML вместо стандартных.<br>
<iframe src="https://altocms.ru/addons/frame/50/?width=800" width="800" height="200"></iframe>
<h5>Плагин Похожие статьи</h5>
Этот плагин, конечно, в первую очередь для людей создан, чтобы им проще было находить нужную информацию, но есть мнение, что поисковики тоже любят перекрестные ссылки между релевантными страницами.<br>
<iframe src="https://altocms.ru/addons/frame/86/?width=800" width="800" height="200"></iframe>
<br>
А в заключение — цитата из <strong>Руководства по поисковой оптимизации для начинающих</strong> от компании Google:<br>
<blockquote>...мы хотели бы еще раз привлечь ваше внимание к тому, что в первую очередь оптимизация вашего сайта должна быть рассчитана на пользователей. Именно они являются целевой аудиторией вашего сайта. Излишняя увлеченность специфическими трюками для достижения максимума в топе может не принести желаемых результатов. Оптимизация для поисковых систем – всего лишь способ немного вырваться вперед, в том, что касается видимости для поисковых роботов, но вашей целевой аудиторией являются пользователи интернета, а не поисковые системы.</blockquote>]]></description>
					<pubDate>Tue, 02 Jun 2015 02:29:12 +0300</pubDate>
									</item>
							<item>
					<title>Быстрая установка Alto CMS «для чайников»</title>
					<guid isPermaLink="true">https://altocms.ru/t/1140/</guid>
					<link>https://altocms.ru/1140.html</link>
					<author>vshemarov@gmail.com</author>
					<description><![CDATA[Для того, чтобы установить Alto CMS на своем сайте, надо сначала залить туда файлы движка. Люди опытные, да, к тому же, имеющие консольный доступ к серверу, могут сделать это быстро: скопировать на сервер архив, распаковать его прямо там и запустить саму установку.<br/>
<br/>
Но если у вас нет консольного доступа или вы не умеете работать с сервером напрямую, то процесс выглядит так: вы распаковываете архив локально у себя на компьютере (возможно, выполняете какие-то настройки), а потом уже копируете папку с файлами движка в директорию вашего сайта на удаленном сервере (как правило, с помощью FTP-клиента).<br/>
<br/>
А т.к. в распакованном виде файлов в движке весьма приличное количество, то процесс «заливки» движка на сайт может занимать приличное время. Это нудно и долго. И чтоб ускорить и упростить этот процесс, создан скрипт <strong>altocms-installer</strong>. <a name="cut" rel="nofollow"></a> <br/>
<br/>
Работает это так:<br/>
<ol><li>Берете скрипт (т.е. файл <strong>altocms-installer.php</strong>) <a href="https://github.com/altocms/altocms-installer" rel="nofollow" >отсюда</a> и копируете на свой сайт.</li><li>Копируете туда же нужный вам zip-архив движка. Причем, это может быть как «чистый» архив движка, так и уже подготовленный и настроенный локально (просто создаете zip-архив папки с подготовленным и настроенным локально сайтом).</li><li>Запускаете распаковщик, набрав в браузере адрес <strong>site.com/altocms-installer.php</strong>. Если устанавливать нужно не в корень сайта, а в какую-то папку, то адрес нужно указать такой:<br/>
<strong>site.com/altocms-installer.php?file=altocms-1.0.10.2.zip&target=alto</strong><br/>
Здесь <strong>altocms-1.0.10.2.zip</strong> — это имя архивного файла, который нужно распаковать, а <strong>alto</strong> — это папка в корне сайта, куда будет установлен движок. Как видите, название самого архива не имеет никакого значения, распаковщик сам определит корневую папку архива и коррекетно скопирует всю структуру.</li></ol><br/>
После этого архив будет распакован в нужную папку и покажет ссылку, по которой нужно перейти для запуска процесса установки.<br/>
<br/>
<strong>Важно!</strong> После установки <strong>ОБЯЗАТЕЛЬНО</strong> нужно удалить файл <strong>altocms-installer.php</strong>.]]></description>
					<pubDate>Sat, 09 May 2015 15:45:41 +0300</pubDate>
									</item>
							<item>
					<title>[dev] Переопределение сортировки топиков</title>
					<guid isPermaLink="true">https://altocms.ru/t/1127/</guid>
					<link>https://altocms.ru/1127.html</link>
					<author>vshemarov@gmail.com</author>
					<description><![CDATA[Статья предназначена для разработчиков плагинов и рассказывает о некоторых новых возможностях, появившихся в версии 1.1. Если быть более точным, то коммит с изменениями был залит в текущую ветку менее суток назад. Но так как это <a href="https://altocms.ru/.html" title="<strong>обновление&nbsp;</strong><br>&lt;h5&gt;Подготовка к обновлению&lt;/h5&gt;
&lt;br&gt;
Этот шаг не обязательный, но желательный, если вы его еще не делали — скопировать файлы конфигурации сайта и все файлы конфигурации всех плагинов и скинов в папку /app вашего сайта.&lt;br&gt;
&lt;br&gt;
Если вы что-то меняли в файле &lt;strong&gt;/common/config/config.php&lt;/strong&gt;, то перенесите эти изменения в файл &lt;strong&gt;/app/config/config.local.php&lt;/strong&gt;, и в дальнейшем менять нужно только его. То же касается файлов &lt;strong&gt;menu.php&lt;/strong&gt;, &lt;strong&gt;widgets.php&lt;/strong&gt; и прочих из &lt;strong&gt;/common/config/&lt;/strong&gt; — не нужно их трогать, делайте копию в &lt;strong&gt;/app/config/&lt;/strong&gt; и там уже меняйте, все, что нужно.&lt;br&gt;
&lt;br&gt;
То же касается и конфигурации плагинов и скинов: например, конфигурацию плагина &lt;strong&gt;Topicintro&lt;/strong&gt;, который вы настраиваете для себя, можно держать в файле &lt;strong&gt;/app/plugins/topicintro/config/config.php&lt;/strong&gt;. А измененную под себя конфигурацию скина &lt;strong&gt;Experience&lt;/strong&gt; — в файле &lt;strong&gt;/app/templates/skin/experience/settings/config/config.php&lt;/strong&gt;. И т.д., и т.п.&lt;br&gt;
&lt;br&gt;
Конечно, это не обязательное условие, просто имея копии конфиг-фалов в папке &lt;strong&gt;/app/&lt;/strong&gt; вы исключаете вероятность того, что однажды случайно их затрете во время очередного обновления движка, плагинов или шаблонов.&lt;br&gt;
&lt;br&gt;
&lt;h5&gt;Само обновление&lt;/h5&gt;
&lt;br&gt;
1) Скачиваем свежую версию Alto CMS и распаковываем ее.&lt;br&gt;
2) Копируем папки &lt;strong&gt;/engine/&lt;/strong&gt; и &lt;strong&gt;/common/&lt;/strong&gt; прямо поверх старых&lt;br&gt;
3) Удаляем содержимое папок &lt;strong&gt;/_run/&lt;/strong&gt; и &lt;strong&gt;/_tmp/&lt;/strong&gt;&lt;br&gt;
4) И... это все! А вы ждали чего-то большего? ;)" class="term">обновление</a> решает важные застарелые проблемы, то решил написать об этом практически сразу же. Итак, известно, что прародителем Альто был движок Livestreet, и, соответственно, наш движок унаследовал, в числе прочего, множество методов для получения выборки топиков под конкретные случаи. Например:<br>
<pre class="prettyprint"><code>public function GetTopicsGood($iPage, $iPerPage, $bAddAccessible = true) {
    // Список &#34;хороших&#34; топиков
}

public function GetTopicsDiscussed($iPage, $iPerPage, $sPeriod = null, $bAddAccessible = true) {
    // Список самых обсуждаемых топиков
}</code></pre>Ну, и так далее.<br>
<br>
Такие методы, как правило, работают по одному алгоритму: формируется фильтр, где задаются параметры отбора и порядок сортировки, а потом вызывается метод получения списка топиков через метод <strong>GetTopicsByFilter(...)</strong>.<br>
<br>
Серьезным недостатком такого подхода было то, что для всех этих узкоспециализированных методов фильтры задавались жестко в самом методе. И если разработчик хотел их изменить, ему приходилось полностью переписывать эти методы.<br>
<br>
Как это работает сейчас.<br>
<br>
Введено такое понятие, как «именованные фильтры». И теперь в этих узкоспециализированных методах фильтр задается через вызов метода <strong>GetNamedFilter()</strong>, куда передаются имя фильтра и дополнительные параметры. Т.е. было так:<br>
<pre class="prettyprint"><code>public function GetTopicsNew($iPage, $iPerPage, $bAddAccessible = true) {
    $aFilter = array();
    // Здесь формируется фильтр ...
    return $this-&#62;GetTopicsByFilter($aFilter, $iPage, $iPerPage);
}</code></pre>А теперь это так:<br>
<pre class="prettyprint"><code>public function GetTopicsNew($iPage, $iPerPage, $bAddAccessible = true) {
    // Получаем именованный фильтр &#39;new&#39; с доп.параметром &#39;accessible&#39;
    $aFilter = $this-&#62;GetNamedFilter(&#39;new&#39;, array(&#39;accessible&#39; =&#62; $bAddAccessible));
    return $this-&#62;GetTopicsByFilter($aFilter, $iPage, $iPerPage);
}</code></pre>И теперь, если разработчик хочет изменить фильтр для метода <strong>GetTopicsNew()</strong>, он должен переопределить метод <strong>GetNamedFilter()</strong>:<br>
<pre class="prettyprint"><code>class PluginMine_ModuleTopic extends PluginMine_Inherits_ModuleTopic {

    public function GetNamedFilter($sFilterName, $aParams = array()) {
        // Получаем фильтр, заданный по умолчанию
        $aFilter = parent::GetNamedFilter($sFilterName, $aParams);
        if ($sFilterName == &#39;new&#39;) {
            $aFilter[&#39;order&#39;] = &#39;...&#39;; // задаем свой порядок сортировки
        }
        return $aFilter;
    }
}</code></pre>И стандартный метод <strong>GetTopicsNew()</strong> будет получать фильтр &#39;new&#39;, измененный плагином. Кроме того, можно задать настройки фильтра по умолчанию:<br>
<pre class="prettyprint"><code>class PluginMine_ModuleTopic extends PluginMine_Inherits_ModuleTopic {

    public function Init() {
        parent::Init();
        $aFilter = array( /* новый фильтр по умолчанию */ );
        $this-&#62;SetTopicsFilter($aFilter); // задаем свой фильтр
    }
}</code></pre>Разработчикам надо также иметь ввиду, что, если задаются какие-то свои специфические параметры фильтра, то, возможно, придется еще и переопределить метод <strong>buildFilter()</strong> в маппере модуля:<br>
<pre class="prettyprint"><code>class PluginMine_ModuleTopic_MapperTopic extends PluginMine_Inherits_ModuleTopic_MapperTopic {

    protected function buildFilter($aFilter) {
        $sWhere = parent::buildFilter($aFilter);
        if (!empty($aFilter[&#39;...&#39;])) {
            // здесь добавляем условия в $sWhere по своим параметрам
        }
        retuen $sWhere;
    }
}</code></pre>Надеюсь, эти фичи облегчат жизнь сторонним разработчикам.]]></description>
					<pubDate>Mon, 04 May 2015 12:24:35 +0300</pubDate>
									</item>
							<item>
					<title>Внешний редирект средствами движка</title>
					<guid isPermaLink="true">https://altocms.ru/t/1115/</guid>
					<link>https://altocms.ru/1115.html</link>
					<author>vshemarov@gmail.com</author>
					<description><![CDATA[В версии 1.1 появилась интересная (а для каких-то случаев и весьма полезная) возможность — внешний редирект.<br>
<br>
Вообще-то, этот функционал, в какой-то степени, является аналогом механизма rewrite, который активно используется при настройке сайтов на веб-сервере apache. Но есть немало случаев, когда использование серверного редиректа невозможно или нежелательно, и вот тут-то нам придет на помощь внешний редирект средствами самого движка. <h5>Кратко, как это работает</h5>
<br>
За внешний редирект отвечает секция конфигурации <strong>&#39;<a href="https://altocms.ru/909.html" title="<strong>router&nbsp;</strong><br>Роутер, это &lt;strong&gt;синглетон&lt;/strong&gt;, основным назначением которого является разбор url, который запрашивает пользователь и запуск соответствующего &lt;strong&gt;экшена&lt;/strong&gt; на исполнение. &lt;br/&gt;
Роутер является единственной точкой вхождения в приложение и только он определяет что сам движок и его плагины будут делать.&lt;br/&gt;
&lt;br/&gt;
Первое с чего начинает свою работу роутер, это разбирает url на составляющие, а как он это делает покажу на примере разбора адреса страницы &lt;em&gt;&lt;a href=&quot;http://example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&quot; rel=&quot;nofollow&quot; &gt;example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&lt;/a&gt;)&lt;/em&gt;&lt;br/&gt;
" class="term">router</a>.redirect&#39;</strong>. Там мы задаем шаблон для URL и адрес, куда нужно перенаправить этот запрос. Дополнительно можно задать код ответа сервера. И браузер (или поисковый бот) при соответствующем запросе будет перенаправлен на другой адрес.<br>
<br>
Эта секция проверяется <a href="https://altocms.ru/909.html" title="<strong>роутером&nbsp;</strong><br>Роутер, это &lt;strong&gt;синглетон&lt;/strong&gt;, основным назначением которого является разбор url, который запрашивает пользователь и запуск соответствующего &lt;strong&gt;экшена&lt;/strong&gt; на исполнение. &lt;br/&gt;
Роутер является единственной точкой вхождения в приложение и только он определяет что сам движок и его плагины будут делать.&lt;br/&gt;
&lt;br/&gt;
Первое с чего начинает свою работу роутер, это разбирает url на составляющие, а как он это делает покажу на примере разбора адреса страницы &lt;em&gt;&lt;a href=&quot;http://example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&quot; rel=&quot;nofollow&quot; &gt;example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&lt;/a&gt;)&lt;/em&gt;&lt;br/&gt;
" class="term">роутером</a> движка сразу после разбора URL и до запуска каких-либо экшенов. И, замечу, проверяется полный URL, включая протокол.<br>
<br>
Более подробно работу этого функционала лучше рассмотреть на конкретных примерах.<br>
<br>
<h5>Пример 1. Перенаправление с HTTP на HTTPS</h5>
Я знаю, что такие вещи лучше делать в файле .htaccess, но вот реальный случай: если на сервере установлена панель ISPmanager версии ниже 5.2, то в .htaccess это работать не будет (там возникает циклический редирект). Но мы можем решить эту проблему, задав такие настройки:<br>
<pre class="prettyprint"><code>$config[&#39;<a href="https://altocms.ru/909.html" title="<strong>router&nbsp;</strong><br>Роутер, это &lt;strong&gt;синглетон&lt;/strong&gt;, основным назначением которого является разбор url, который запрашивает пользователь и запуск соответствующего &lt;strong&gt;экшена&lt;/strong&gt; на исполнение. &lt;br/&gt;
Роутер является единственной точкой вхождения в приложение и только он определяет что сам движок и его плагины будут делать.&lt;br/&gt;
&lt;br/&gt;
Первое с чего начинает свою работу роутер, это разбирает url на составляющие, а как он это делает покажу на примере разбора адреса страницы &lt;em&gt;&lt;a href=&quot;http://example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&quot; rel=&quot;nofollow&quot; &gt;example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&lt;/a&gt;)&lt;/em&gt;&lt;br/&gt;
" class="term">router</a>&#39;][&#39;redirect&#39;] = array(
    &#39;http://*&#39; =&#62; &#39;https://*&#39;,
);</code></pre>По-моему, тут все предельно ясно — «звездочка» заменяет любоую последовательность символов. И все, что приходится на «звездочку» в шаблоне, подставляется вместо «звоздочки» в целевом адресе.<br>
<br>
<h5>Пример 2. Смена адреса страницы</h5>
Допустим, были у вас страницы по адресу <strong><a href="http://site.com/old-path/" rel="nofollow">http://site.com/old-path/</a></strong> и вы хотите перенести их на новый адрес по адресу <strong><a href="http://site.com/new-path/" rel="nofollow">http://site.com/new-path/</a></strong>, вот только позиции в поисковиках терять не хочется. Ок, решаем проблему:<br>
<pre class="prettyprint"><code>$config[&#39;<a href="https://altocms.ru/909.html" title="<strong>router&nbsp;</strong><br>Роутер, это &lt;strong&gt;синглетон&lt;/strong&gt;, основным назначением которого является разбор url, который запрашивает пользователь и запуск соответствующего &lt;strong&gt;экшена&lt;/strong&gt; на исполнение. &lt;br/&gt;
Роутер является единственной точкой вхождения в приложение и только он определяет что сам движок и его плагины будут делать.&lt;br/&gt;
&lt;br/&gt;
Первое с чего начинает свою работу роутер, это разбирает url на составляющие, а как он это делает покажу на примере разбора адреса страницы &lt;em&gt;&lt;a href=&quot;http://example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&quot; rel=&quot;nofollow&quot; &gt;example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&lt;/a&gt;)&lt;/em&gt;&lt;br/&gt;
" class="term">router</a>&#39;][&#39;redirect&#39;] = array(
    &#39;http://site.com/old-path/*&#39; =&#62; &#39;http://site.com/new-path/*.html&#39;,
);</code></pre>А если это временный редирект, то добавим код 302 (по умолчанию используется код 301):<br>
<pre class="prettyprint"><code>$config[&#39;<a href="https://altocms.ru/909.html" title="<strong>router&nbsp;</strong><br>Роутер, это &lt;strong&gt;синглетон&lt;/strong&gt;, основным назначением которого является разбор url, который запрашивает пользователь и запуск соответствующего &lt;strong&gt;экшена&lt;/strong&gt; на исполнение. &lt;br/&gt;
Роутер является единственной точкой вхождения в приложение и только он определяет что сам движок и его плагины будут делать.&lt;br/&gt;
&lt;br/&gt;
Первое с чего начинает свою работу роутер, это разбирает url на составляющие, а как он это делает покажу на примере разбора адреса страницы &lt;em&gt;&lt;a href=&quot;http://example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&quot; rel=&quot;nofollow&quot; &gt;example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&lt;/a&gt;)&lt;/em&gt;&lt;br/&gt;
" class="term">router</a>&#39;][&#39;redirect&#39;] = array(
    &#39;http://site.com/old-path/*&#39; =&#62; array(&#39;http://site.com/new-path/*.html&#39;, 302),
);</code></pre><br>
<h5>Пример 3. Раздел сайта переехал на поддомен</h5>
Был у вас блог на сайте Редирект средствами движка, который вы перенесли на поддомен <strong>blabla.site.com</strong>. Настраиваем:<br>
<pre class="prettyprint"><code>$config[&#39;<a href="https://altocms.ru/909.html" title="<strong>router&nbsp;</strong><br>Роутер, это &lt;strong&gt;синглетон&lt;/strong&gt;, основным назначением которого является разбор url, который запрашивает пользователь и запуск соответствующего &lt;strong&gt;экшена&lt;/strong&gt; на исполнение. &lt;br/&gt;
Роутер является единственной точкой вхождения в приложение и только он определяет что сам движок и его плагины будут делать.&lt;br/&gt;
&lt;br/&gt;
Первое с чего начинает свою работу роутер, это разбирает url на составляющие, а как он это делает покажу на примере разбора адреса страницы &lt;em&gt;&lt;a href=&quot;http://example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&quot; rel=&quot;nofollow&quot; &gt;example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&lt;/a&gt;)&lt;/em&gt;&lt;br/&gt;
" class="term">router</a>&#39;][&#39;redirect&#39;] = array(
    &#39;http://site.com/blog/blabla/*&#39; =&#62; &#39;http://blabla.site.com/*&#39;,
);</code></pre><br>
<h5>Пример 4. Шаблон с несколькими «звездочакми»</h5>
Допустим, вы переехали на Альто с какого-то другого движка, где у вас страницы формировались так: <strong>site.com/blog/blabla/123.html</strong><br>
<br>
А на Альто вы хотите, чтоб страница отображалась без всяких лишних элементов вот так: <strong>site.com/123.html</strong><br>
<pre class="prettyprint"><code>$config[&#39;<a href="https://altocms.ru/909.html" title="<strong>router&nbsp;</strong><br>Роутер, это &lt;strong&gt;синглетон&lt;/strong&gt;, основным назначением которого является разбор url, который запрашивает пользователь и запуск соответствующего &lt;strong&gt;экшена&lt;/strong&gt; на исполнение. &lt;br/&gt;
Роутер является единственной точкой вхождения в приложение и только он определяет что сам движок и его плагины будут делать.&lt;br/&gt;
&lt;br/&gt;
Первое с чего начинает свою работу роутер, это разбирает url на составляющие, а как он это делает покажу на примере разбора адреса страницы &lt;em&gt;&lt;a href=&quot;http://example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&quot; rel=&quot;nofollow&quot; &gt;example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&lt;/a&gt;)&lt;/em&gt;&lt;br/&gt;
" class="term">router</a>&#39;][&#39;redirect&#39;] = array(
    &#39;http://site.com/blog/*/*.html&#39; =&#62; &#39;http://site.com/$2.html&#39;,
);</code></pre>Здесь в шаблоне использованы две «звездочки», и в целевом адресе вместо &#39;$2&#39; будет подставлено то, что приходится на вторую «звездочку» шаблона.<br>
<br>
<h5>Пример 5. Регулярные выражения</h5>
Допустим, вы переехали на Альто с какого-то другого движка, где у вас страницы формировались так: <strong>site.com/blog/blabla/123.html</strong><br>
<br>
А на Альто вы хотите, чтоб страница отображалась без всяких лишних элементов вот так: <strong>site.com/123.html</strong><br>
<br>
Можно это сделать и через «звоздочки», как делалось выше, но если вы умеете работать с регулярными выражениями, то можете использовать и их (важно — настоящие регулярные выражения заключаем в квадратные скобки):<br>
<pre class="prettyprint"><code>$config[&#39;<a href="https://altocms.ru/909.html" title="<strong>router&nbsp;</strong><br>Роутер, это &lt;strong&gt;синглетон&lt;/strong&gt;, основным назначением которого является разбор url, который запрашивает пользователь и запуск соответствующего &lt;strong&gt;экшена&lt;/strong&gt; на исполнение. &lt;br/&gt;
Роутер является единственной точкой вхождения в приложение и только он определяет что сам движок и его плагины будут делать.&lt;br/&gt;
&lt;br/&gt;
Первое с чего начинает свою работу роутер, это разбирает url на составляющие, а как он это делает покажу на примере разбора адреса страницы &lt;em&gt;&lt;a href=&quot;http://example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&quot; rel=&quot;nofollow&quot; &gt;example.com/action/event/param1/param2/p0?p3&amp;p4&amp;p5&lt;/a&gt;)&lt;/em&gt;&lt;br/&gt;
" class="term">router</a>&#39;][&#39;redirect&#39;] = array(
    &#39;[~(.+/)/blog/([\w\-]+)/(\d+).html$~]&#39; =&#62; &#39;$1/$3.html&#39;,
);</code></pre>]]></description>
					<pubDate>Fri, 01 May 2015 14:33:14 +0300</pubDate>
									</item>
							<item>
					<title>Как задать свой размер аватары</title>
					<guid isPermaLink="true">https://altocms.ru/t/623/</guid>
					<link>https://altocms.ru/623.html</link>
					<author>vshemarov@gmail.com</author>
					<description><![CDATA[В шаблонах CMS ссылка на аватарку пользователя задается методом <strong>getAvatarUrl()</strong>, например, так:<br>
<pre class="prettyprint"><code>&#60;img src=&#34;{$oUser-&#62;getAvatarUrl()}&#34;&#62;</code></pre>В этом случае будет дана ссылка на картинку-аватар размером, который задан в конфиг-файле:<br>
<pre class="prettyprint"><code>$config[&#39;module&#39;][&#39;user&#39;][&#39;profile_avatar_size&#39;] = 100; // размер аватара по умолчанию 100x100</code></pre> Но если нужно задать конкретный размер, то его надо указать явно, например так:<br>
<pre class="prettyprint"><code>&#60;img src=&#34;{$oUser-&#62;getAvatarUrl(85)}&#34;&#62; &#60;!-- размер аватары 85x85 --&#62;
&#60;img src=&#34;{$oUser-&#62;getAvatarUrl(&#39;60x80&#39;)}&#34;&#62; &#60;!-- размер аватары 60x80 --&#62;
&#60;img src=&#34;{$oUser-&#62;getAvatarUrl(&#39;x80&#39;)}&#34;&#62; &#60;!-- ширина аватары 80, а высота - как получится --&#62;</code></pre>Важно отметить: когда задается новый размер, который еще не использовался, то аватара нужного размера будет создана автоматически в момент запроса, а впоследствии нужный URL будет просто выдаваться в шаблон. Поэтому нет необходимости как-то специально создавать аватары нового размера, если вы вдруг решили изменить их в своих шаблонах, просто задайте новые размеры (либо в шаблоне, либо в конфиг-файле) и все! Все остальное будет сделано автоматически.]]></description>
					<pubDate>Wed, 25 Jun 2014 12:16:25 +0400</pubDate>
									</item>
							<item>
					<title>Работа с css- и js-файлами - дополнительные возможности для разработчиков шаблонов и плагинов</title>
					<guid isPermaLink="true">https://altocms.ru/t/600/</guid>
					<link>https://altocms.ru/600.html</link>
					<author>vshemarov@gmail.com</author>
					<description><![CDATA[В продолжении к статье <a href="https://altocms.ru/597.html">Файлы js и css, а также прочие asset&#39;ы – тонкости и нюансы работы с ними в Альто</a> хочу рассказать о некоторых дополнительных возможностях по работе с css- и js-файлами, которые будут полезны тем, кто разрабатывает собственные шаблоны и плагины для <a href="https://altocms.ru/871.html" title="<strong>Alto&nbsp;</strong><br>Если вы собираетесь создавать сайт и выбираете для этой цели CMS (или «движок», как еще говорят), то наверняка у вас возникает вопрос: «А чем же Alto лучше других CMS? И годится ли для моих задач?»&lt;br/&gt;
&lt;br/&gt;
Выбирая Alto CMS, вы получаете «из коробки» функционал, который в других движках достигается установкой множества плагинов:" class="term">Alto</a> CMS. <h5>Разработчикам шаблонов</h5>
Разработчикам собственных шаблонов и фронтендерам будет полезно напомнить, что они могут дополнить либо полностью переназначить весь комплект js- и css-файлов. Это можно сделать в файле конфигурации шаблона:<br>
<pre class="prettyprint"><code>$config[&#39;head&#39;][&#39;default&#39;][&#39;js&#39;] = Config::Get(&#39;head.default.js&#39;); // получаем стандартный js-комплект
$config[&#39;head&#39;][&#39;default&#39;][&#39;js&#39;][] = &#39;___path.skin.dir___/assets/js/template.js&#39;; // добавляем файл
// добавляем еще файл с доп.параметрами
$config[&#39;head&#39;][&#39;default&#39;][&#39;js&#39;][&#39;___path.skin.dir___/assets/js/other.js&#39;] = array(
  &#39;name&#39; =&#62; &#39;other.js&#39;,
  &#39;prepare&#39; =&#62; true,
);

// Полностью переопределяем css-комплект
$config[&#39;head&#39;][&#39;default&#39;][&#39;css&#39;] = array(
    /*
     * здесь список css-файлов
     */
);</code></pre>В этом примере файл <strong>template.js</strong> будет добавлен в общий список и подключен в HTML. А файл <strong>other.js</strong> будет только перемещен в папку <strong>/_run/assets/</strong>, но не будет включаться в HTML-код. Это можно сделать позже при выполнении javascript-кода:<br>
<pre class="prettyprint"><code>&#60;script&#62;
$.ajax({
    url: ls.getAssetUrl(&#39;other.js&#39;),
    dataType: &#39;script&#39;
});
&#60;script&#62;</code></pre><br>
Иногда возникает необходимость обработать без подключения целую папку с js- и css-файлами. Покажу на примере подключения библиотеки <strong>tinyMCE</strong> (немного упрощенно, но суть будет ясна). Вот так это выглядит в конфиг-файле:<br>
<pre class="prettyprint"><code>$config[&#39;head&#39;][&#39;default&#39;][&#39;js&#39;] = array(
    &#39;___path.frontend.dir___/libs/vendor/tinymce_4/tinymce.min.js&#39;       =&#62; array(
        &#39;dir_from&#39; =&#62; &#39;___path.frontend.dir___/libs/vendor/tinymce_4/&#39;,
        &#39;name&#39;     =&#62; &#39;tinymce_4&#39;,
        &#39;compress&#39; =&#62; false,
        &#39;merge&#39;    =&#62; false,
    ),
    &#39;___path.frontend.dir___/libs/vendor/tinymce_4/plugins/*&#39;       =&#62; array(
        &#39;dir_from&#39;  =&#62; &#39;___path.frontend.dir___/libs/vendor/tinymce_4/&#39;,
        &#39;prepare&#39;   =&#62; true,
        &#39;compress&#39;  =&#62; false,
        &#39;merge&#39;     =&#62; false,
    ),
    &#39;___path.frontend.dir___/libs/vendor/tinymce_4/skins/*&#39;       =&#62; array(
        &#39;dir_from&#39; =&#62; &#39;___path.frontend.dir___/libs/vendor/tinymce_4/&#39;,
        &#39;prepare&#39;  =&#62; true,
        &#39;compress&#39; =&#62; false,
        &#39;merge&#39;    =&#62; false,
    ),
);</code></pre>Здесь важно обратить внимание на три момента:<br>
<br>
<img src="https://altocms.ru/uploads/images/00/00/02/2014/05/26/034dab.gif" align="right">1) Непосредственно в HTML-код будет подключаться только tinymce.min.js (причем, без сжатия и без объединения с другими файлами). Другие файлы обрабатываются, но не подключается — скрипт tinyMCE делает это самостоятельно.<br>
<br>
2) В обрабатываемых файлах можно указать путь, оканчивающийся на «*» — так мы указываем, что нужно обработать все файлы, лежащие в этой папке.<br>
<br>
3) И, наконец, у всех файлов в этой группе есть еще один параметр — <strong>dir_from</strong>. С его помощью мы восстанавливаем структуру подпапок при переносе файлов в <strong>/_run/assets/</strong>. Т.е. допустим, у нас изначально в библиотеках фронтенда в папке <strong>/common/templates/frontend/libs/vendor/</strong> есть такая структура, как на картинке. Тогда, если сам файл <strong>tinymce.min.js</strong> копируется при обработке в <strong>/_run/assets/322c3371/tinymce.min.js</strong>, то <strong>skin.min.css</strong> будет скопирован в <strong>/_run/assets/322c3371/skins/lightgray/skin.min.css</strong>, и т.д. Т.е. копироваться будут не просто сами файлы, но и вся структура содержимого папки, указанной в параметре <strong>dir_from</strong>.<br>
<br>
<h5>Вставка js- и css-файлов в шаблон</h5>
Иногда бывает нужно вставить какие-то специфические файлы прямо в файл шаблона. Делается это так:<br>
<pre class="prettyprint"><code>&#60;script src=&#34;{asset file=&#39;js/myscript.min.js&#39;}&#34;&#62;&#60;/script&#62;
&#60;img src=&#34;{asset file=&#39;images/logo.png&#39;}&#34;&#62;</code></pre>Smarty-функция asset проверит наличие искомых файлов в папке <strong>/_run/assets/</strong> и если нет, то скопирует из папки <strong>/assets/</strong> текущего скина, а затем подставит нужный URL в HTML-код. При необходимости можно указать и скин, и тему, откуда брать файлы:<br>
<pre class="prettyprint"><code>&#60;img src=&#34;{asset file=&#39;images/logo.png&#39; skin=&#39;start-kit&#39; theme=&#39;green&#39;}&#34;&#62;</code></pre>Отмечу, что это могут быть любые файлы, которые вы решите включить в HTML-код, например, флеш, шрифты и т.д.<br>
<br>
<h5>Разработчикам плагинов</h5>
Разработчикам плагинов тоже нередко требуется подключать свои стили и скрипты. Для этого в модуле <strong>Viewer</strong> существуют соответствующие методы:<br>
<pre class="prettyprint"><code>/**
 * Добавляет js-файл в конец списка
 *
 * @param string $sFile    - Локальный путь или URL файла
 * @param array  $aParams  - Параметры подключения
 */
public function AppendScript($sFile, $aParams = array()) { }

/**
 * Добавляет js-файл в начало списка
 *
 * @param string $sFile    - Локальный путь или URL файла
 * @param array  $aParams  - Параметры подключения
 */
public function PrependScript($sFile, $aParams = array()) { }

/**
 * Добавляет css-файл в конец списка
 *
 * @param string $sFile    - Локальный путь или URL файла
 * @param array  $aParams  - Параметры подключения
 */
public function AppendStyle($sFile, $aParams = array()) { }

/**
 * Добавляет css-файл в конец списка
 *
 * @param string $sFile    - Локальный путь или URL файла
 * @param array  $aParams  - Параметры подключения
 */
public function PrependStyle($sFile, $aParams = array()) { }

/**
 * Обрабатывает (но не подключает) js-файл
 *
 * @param string $sFile    - Локальный путь или URL файла
 * @param array  $aParams  - Параметры подключения
 */
public function PrepareScript($sFile, $aParams = array()) { }

/**
 * Обрабатывает (но не подключает) css-файл
 *
 * @param string $sFile    - Локальный путь или URL файла
 * @param array  $aParams  - Параметры подключения
 */
public function PrepareStyle($sFile, $aParams = array()) { }</code></pre><br>
Мне кажется, можно особо не расписывать действие этих методов, ибо и так очевидно, как они работают (но если вдруг кому непонятно — спрашивайте).<br>
<br>
Добавлю лишь, что эти методы часто вызывают при инициализации плагина. Хотя это и совсем не обязательно. Они могут вызываться и в экшенах, и в исполняемых (но не в шаблонных!) хуках. Главное, чтобы их вызов был выполнен до завершения текущего экшена. Пример вызова:<br>
<pre class="prettyprint"><code>/**
 * Инициализация плагина
 */
public function Init() {
    $this-&#62;Viewer_AppendStyle(Plugin::GetTemplateDir(__CLASS__) . &#39;css/style.css&#39;);
}</code></pre>Либо, если хотите, чтоб css-файл не обрабатывался, а подключался в HTML-код прямо из папки шаблонов плагина, то можно так:<br>
<pre class="prettyprint"><code>    $this-&#62;Viewer_AppendStyle(Plugin::GetTemplateUrl(__CLASS__) . &#39;css/style.css&#39;);</code></pre>Но если в процессе разработки и отладки такое вполне допустимо, в рабочих проектах делать это крайне не рекомендуется.]]></description>
					<pubDate>Mon, 26 May 2014 18:05:35 +0400</pubDate>
									</item>
					</channel>
	</rss>
