11 заметок с тегом

simplacms

SimplaCMS: Итоговая стоимость на ThankYou Page

Не нашёл переменной, которая выводит стоимость заказа с учётом доставки, пришлось написать костылёк прям в шаблоне. Работает просто — забираем данные из переменных (total_price и delivery_price), складываем (math equation), преобразовываем в переменную (assign) и выводим значение в отформатированном виде (total|convert).

{math equation = $order->total_price + $order->delivery_price assign = 'total'}
{$total|convert} {$currency->sign}
2018   simplacms

Simpla: Показываем JivoSite в определённое время

Сделал на одном сайте привязку кнопок «Обратный звонок» и «Отправить заявку» к JivoSite.
Возможно для кого-то это покажется дикостью, но это на самом деле удобно — обратный звонок должен происходить моментально, а не через три часа, когда менеджер по продажам, который отсиживает жопу на зарплате, накурится сигарет и напьется кофе. И JivoSite в этом плане оказался очень удобен.

Но столкнулся с интересной проблемой. В JivoSite есть настройки времени, когда можно совершать звонок с сайта. Чтобы появилась форма обратного звонка нужно нажать на соответствующую кнопку/ссылку. Конкретный пример:

Предположим мы поставим в настройках JivoSite часы работы с 9 до 18 часов. Как вы думаете, что произойдет, если мы нажмём на ссылку «Обратный звонок» в 18:02? Правильно. Ничего. Она не сработает, а это проёбаный лид. Техподдержке передал, но нужно сохранить лид уже сегодня и своими силами.

Чтобы лид остался с нами, нужно проверить сколько сейчас на часах и предложить альтернативу, например, оффлайн форму того же JivoSite. И в SimplaCMS это решалось так:

<a href="tel:{$settings->company_phone|escape}"><h3>{$settings->company_phone|escape}</h3></a>
{if $smarty.now|date_format:'%H.%M' > '09.00' && $smarty.now|date_format:'%H.%M' < '18.00' }
{literal}<a href="#" onclick="jivo_api.open({start : 'call'});">Обратный звонок</a>{/literal}
{else}
<a href="#" onclick="jivo_api.open();">Обратный звонок</a>
{/if}

Если время сервера попадает в заданный интервал, показать ссылку №1. В противном случае №2.

2018   jivosite   simplacms

Вторая цена в Simpla CMS

На базе Simpla CMS делаю каталог объектов. Возникла необходимость вывести две цены, например, за час и за смену. Реализация:

  1. Делаем SQL запрос в таблицу s_variants:
ALTER TABLE `s_variants` ADD `price2` TEXT NOT NULL AFTER `price`;
  1. Обновим запрос в /api/Variants.php в двух местах:
$query = $this->db->placehold("SELECT v.id, v.product_id , v.price, v.price2, NULLIF(v.compare_price, 0) as compare_price, v.sku, IFNULL(v.stock, ?) as stock, (v.stock IS NULL) as infinity, v.name, v.attachment, v.position
...
  1. Чтобы вторая цена выводилась в админке в общем списке товаров, добавим в /simpla/design/default/products.tpl ~80 строка:
<input class="price" type="text" name="price2[{$variant->id}]" value="{$variant->price2}" />{$currency->sign}
  1. Чтобы можно было редактировать цену в карточке объекта, добавим ~585 строчка:
<li class="variant_price">     <input name="variants[price2][]"         type="text"   value="{$variant->price2|escape}" /></li>
  1. Чтобы вывести в фронтэнде:
{if $v->price2 > 0}{$v->price2|convert} {$currency->sign}

Готово.

2018   simplacms

Создаем иконки страниц в Simpla CMS

Задача: создать в админке инструмент по выбору иконок типа Font Awesome и вывести их в меню в шапке сайта.

Решение.

Открываем phpMyAdmin и выполняем SQL-запрос

ALTER TABLE `s_pages` ADD `icon` TEXT NOT NULL AFTER `url`;

Далее открываем /api/Pages.php (~30 и 55 строки) и добавляем в SQL-запрос:

, icon

Далее открываем /simpla/PagesAdmin.php, ищем

if($this->request->method('post'))
  	{

И ниже добавляем:

$this->pages->icon = $this->request->post('icon');

Далее открываем файл /simpla/design/html/page.tpl и добавим после ~209 строчки:

<div id="column_right">
		<div class="block layer">
			<h2>Оформление страницы</h2>
			<ul>
				<li><label class=property>Иконка</label><input name="icon" class="simpla_inp" type="text" value="{$page->icon|escape}" /></li>
			</ul>
			<p align="right" style="color: #bbb;font-size: 10px;">Список иконок можно посмотреть <a href="https://linearicons.com/free">здесь</a>.</p>
		</div>
	</div>

Чтобы вывести в шаблоне:

{if $p->icon}<span class="lnr lnr-{$p->icon}"></span>{/if}
2018   simplacms

Шорткоды в SimplaCMS

{$product->created|date} - дата создания продукта
{$product->brand} - название бренда
{$product->brand_url} - URL бренда
{foreach $product->features as $f} {if ($f->feature_id == '174')} {$f->name} {$f->value} {/if} {/foreach} - конкретное свойство товара
{$meta_keywords|escape} - мета-тег ключевые слова
{$meta_description|escape} - мета-тег с описанием
{$config->root_url} - адрес сайта
{$settings->theme|escape} - имя темы
{include file='имя_файла'} - подключить файл
{$settings->site_name|escape} - имя сайта из настроек

Список будет дополняться.

2018   simplacms

Произвольные переменные в Simpla CMS

Для того, чтобы добавить номер телефона компании, адрес компании или email, откроем файл SettingsAdmin.php ~20 строка и добавим:

$this->settings->company_phone = $this->request->post('company_phone');
$this->settings->company_address = $this->request->post('company_address');
$this->settings->company_email = $this->request->post('company_email');

Далее откроем файл /simpla/design/html/settings.tpl ~42 строка и добавим:

<li><label class=property>Имя компании</label><input name="company_phone" class="simpla_inp" type="text" value="{$settings->company_phone|escape}" /></li>
<li><label class=property>Имя компании</label><input name="company_address" class="simpla_inp" type="text" value="{$settings->company_address|escape}" /></li>
<li><label class=property>Имя компании</label><input name="company_email" class="simpla_inp" type="text" value="{$settings->company_email|escape}" /></li>

Столбец в SQL-таблице settings будет создана автоматически при добавлении значений в панели администратора.

Вывести можно так:

{if $settings->phone}Номер телефона: {$settings->phone}{/if}
2018   simplacms

Обратный звонок Simpla CMS

Открываем phpMyAdmin и делаем SQL запрос:

CREATE TABLE IF NOT EXISTS `s_callbacks` (
  `id` bigint(20) NOT NULL,
  `date` datetime NOT NULL,
  `name` varchar(255) NOT NULL,
  `phone` varchar(255) NOT NULL,
  `message` text NOT NULL,
  `processed` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=MyISAM AUTO_INCREMENT=5745 DEFAULT CHARSET=utf8;

ALTER TABLE `s_callbacks`
  ADD PRIMARY KEY (`id`);
ALTER TABLE `s_callbacks`
  MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=5745;

Далее открываем файл /api/Simpla.php и добавляем ~40 строка:

'callbacks'	 => 'Callbacks',

Далее открываем файл /api/Managers.php и добавляем ~16 строка:

, 'callbacks'

Далее открываем файл /view/IndexView.php и добавляем ~33 строка:

if($this->request->method('post') && $this->request->post('callback')) {
            $callback = new stdClass();
            $callback->phone        = $this->request->post('phone');
            $callback->name         = $this->request->post('name');
            $this->design->assign('callname',  $callback->name);
            $this->design->assign('callemail', $callback->phone);
            $this->design->assign('call_sent', true);
            $callback_id = $this->callbacks->add_callback($callback);
            $this->callbacks->email_callback_admin($callback_id);
        }

Далее открываем файл /simpla/design/html/comments.tpl и добавляем ~строка 6:

{if in_array('callbacks', $manager->permissions)}<li><a href="index.php?module=CallbacksAdmin">Заказ обратного звонка</a></li>{/if}

Далее открываем файл /simpla/design/html/feedbacks.tpl и добавляем ~строка 6:

{if in_array('callbacks', $manager->permissions)}<li><a href="index.php?module=CallbacksAdmin">Заказ обратного звонка</a></li>{/if}

Далее создаем файл /simpla/design/html/callbacks.tpl с таким содержимым:

{* Вкладки *}
{capture name=tabs}
    {if in_array('comments', $manager->permissions)}
        <li><a href="index.php?module=CommentsAdmin">Комментарии</a></li>
    {/if}
		<li class="active"><a href="index.php?module=ReviewsAdmin">Отзывы</a></li>
    {if in_array('feedbacks', $manager->permissions)}
        <li><a href="index.php?module=FeedbacksAdmin">Обратная связь</a></li>
    {/if}
    <li class="active"><a href="index.php?module=CallbacksAdmin">Заказ обратного звонка</a></li>
{/capture}

{* Title *}
{$meta_title='Заказ обратного звонка' scope=parent}

<div id="header">
	{if $callbacks_count}
	<h1>{$callbacks_count} {$callbacks_count|plural:'заказ':'заказа':'заказов'}</h1> 
	{else}
	<h1>Нет заказов</h1> 
	{/if}
</div>

<div id="main_list">
    {include file='pagination.tpl'}
    {if $callbacks}
        <form id="list_form" method="post">
            <input type="hidden" name="session_id" value="{$smarty.session.id}"/>
            <div id="list" class="sortable">
                {foreach $callbacks as $callback}
                    <div class="{if !$callback->processed}unapproved{/if} row">
                        <div class="checkbox cell">
                            <input type="checkbox" id="{$callback->id}" name="check[]" value="{$callback->id}"/>
                            <label for="{$callback->id}"></label>
                        </div>
                        <div class="name cell">
                            <div class='comment_name'>
                                {$callback->name|escape}
                                <a class="approve" href="#">Обработать</a>
                            </div>
                            <div class='comment_text'>
                                Телефон: {$callback->phone|escape|nl2br}
                            </div>
                            <div class='comment_text'>
                                Сообщение: {$callback->message|escape|nl2br}
                            </div>
                            <div class='comment_info'>
                                Заявка отправлена {$callback->date|date} в {$callback->date|time}
                            </div>
                        </div>
                        <div class="icons cell">
                            <a href='#' title='Удалить' class="delete"></a>
                        </div>
                        <div class="clear"></div>
                    </div>
                {/foreach}
            </div>

            <div id="action">
                <label id='check_all' class='dash_link'>Выбрать все</label>
                <span id=select>
                <select name="action">
                    <option value="processed">Отметить как обработанные</option>
                    <option value="delete">Удалить</option>
                </select>
                </span>
                <input id='apply_action' class="button_green" type=submit value="Применить">
            </div>
        </form>
    {else}
        Нет сообщений
    {/if}
    {include file='pagination.tpl'}
</div>
{literal}
<script>
$(function() {

	// Раскраска строк
	function colorize()
	{
		$("#list div.row:even").addClass('even');
		$("#list div.row:odd").removeClass('even');
	}
	// Раскрасить строки сразу
	colorize();
	
	// Выделить все
	$("#check_all").click(function() {
		$('#list input[type="checkbox"][name*="check"]').attr('checked', $('#list input[type="checkbox"][name*="check"]:not(:checked)').length>0);
	});	

	// Удалить 
	$("a.delete").click(function() {
		$('#list input[type="checkbox"][name*="check"]').attr('checked', false);
		$(this).closest(".row").find('input[type="checkbox"][name*="check"]').attr('checked', true);
		$(this).closest("form").find('select[name="action"] option[value=delete]').attr('selected', true);
		$(this).closest("form").submit();
	});
	
	// Обработать
	$("a.approve").click(function() {
		var line        = $(this).closest(".row");
		var id          = line.find('input[type="checkbox"][name*="check"]').val();
		line.addClass('loading_icon');
		$.ajax({
			type: 'POST',
			url: 'ajax/update_object.php',
			data: {'object': 'callback', 'id': id, 'values': {'processed': 1}, 'session_id': '{/literal}{$smarty.session.id}{literal}'},
			success: function(data){
				line.removeClass('loading_icon');
                line.removeClass('unapproved');
			},
			dataType: 'json'
		});	
		return false;	
	});
	
	// Подтверждение удаления
	$("form#list_form").submit(function() {
		if($('select[name="action"]').val()=='delete' && !confirm('Подтвердите удаление'))
			return false;	
	});

});

</script>
{/literal}

И тут же добавим ещё один файл с шаблоном письма на почту email_callback_admin.tpl с таким содержимым:

{$subject="Заявка на обратный звонок от `$callback->name|escape`" scope=parent}
<h1 style="text-align: center;font: 18px;background: #41ade2;color: #fff;padding: 5px; width: 800px;">
    Заявка на обратный звонок от {$callback->name|escape}
</h1>
<table cellpadding=6 cellspacing=0 style='border-collapse: collapse;border: 2px solid #2c6f95;'>
   <tr style="border-bottom: 2px solid #2c6f95;">
    <td style='padding:6px; width:170px; background-color:#41ade2; border:1px solid #e0e0e0;font-family:arial;'>
      Имя
    </td>
    <td style='padding:6px; width:330px; background-color:#ffffff; border:1px solid #e0e0e0;font-family:arial;'>
      {$callback->name|escape}
    </td>
  </tr>
   <tr style="border-bottom: 2px solid #2c6f95;">
    <td style='padding:6px; width:170px; background-color:#41ade2; border:1px solid #e0e0e0;font-family:arial;'>
      Телефон
    </td>
    <td style='padding:6px; width:330px; background-color:#ffffff; border:1px solid #e0e0e0;font-family:arial;'>
     {$callback->phone|escape}
    </td>
  </tr>
</table>

Чтобы вывести в шаблоне:

<form id="callback_form" class="form" method="post">
    <div class="callback_title">Заказ обратного звонка</div>
    <div class="form_group">
        <label for="callback_name">Ваше имя</label>
        <input id="callback_name" class="form_input" type="text" name="name" data-format=".+" data-notice="Введите имя" value="" />
    </div>
    <div class="form_group">
        <label for="callback_phone">Ваш телефон</label>
        <input id="callback_phone" class="form_input" type="text" name="phone" data-format=".+" data-notice="Введите № телефона" value="" maxlength="255" />
    </div>
    <input class="button" type="submit" name="callback" value="Заказать" />
</form>
2018   simplacms

Функция вывода товаров в Simpla CMS

Создадим вызов функции в /view/View.php

$this->design->smarty->registerPlugin("function", "get_products", array($this, 'get_products_plugin'));

Далее там же добавим саму функцию, например, после get_discounted_products:

public function get_products_plugin($params, &$smarty)
{
    if(!isset($params['visible']))
        $params['visible'] = 1;
    if(!empty($params['var']))
    {
        foreach($this->products->get_products($params) as $p)
            $products[$p->id] = $p;
 
        if(!empty($products))
        {
            // id выбраных товаров
            $products_ids = array_keys($products);
     
            // Выбираем варианты товаров
            $variants = $this->variants->get_variants(array('product_id'=>$products_ids, 'in_stock'=>true));
             
            // Для каждого варианта
            foreach($variants as &$variant)
            {
                // добавляем вариант в соответствующий товар
                $products[$variant->product_id]->variants[] = $variant;
            }
             
            // Выбираем изображения товаров
            $images = $this->products->get_images(array('product_id'=>$products_ids));
            foreach($images as $image)
                $products[$image->product_id]->images[] = $image;
 
            foreach($products as &$product)
            {
                if(isset($product->variants[0]))
                    $product->variant = $product->variants[0];
                if(isset($product->images[0]))
                    $product->image = $product->images[0];
            }               
        }
 
        $smarty->assign($params['var'], $products);
         
    }
}

Пример использования:

{get_products var=all_products limit=3}
{if $all_products}
{foreach $all_products as $p}
//выводим товар в цикле
{/foreach}
{/if}
  1. limit с числовым значение указывает какое количество товара долно быть в выборке
  2. discounted — передав данный параметр со значение 1 мы получим товары со скидкой
  3. featured со значение 1 вернет рекомендуемые товары
  4. sort может принимать 4 значения — name, created, position и price — вернет товары в той сортировке, которую указали
  5. in_stock со значением 1 указывает, что надо только те товары, которые есть в наличии
  6. brand_id с числовым индексом бренда вернет товары указанного бренда
  7. category_id с числовым индексом категории вернет товары указанной категории
  8. keyword со значение к примеру «Samsung» вернет товары где в названии или META встречается указанное слово (поиск по названию)

Найдено в интернете, но пользуюсь регулярно.

2018   simplacms

Simpla CMS: JS & CSS Minify + Combine

Велосипед не мой, но очень полезный. Сначала поработаем под капотом:

  1. Распаковать из архива в корень сайта файлы
  2. Добавим в api/Simpla.php:
'js'     => 'Javascript',
'css'     => 'Stylesheet',
  1. Добавим в файл view/View.php после строки:
$this->design->smarty->registerPlugin('block', 'js',        array($this, 'add_javascript_block'));
$this->design->smarty->registerPlugin('function', 'unset_js',        array($this, 'unset_javascript_function'));
$this->design->smarty->registerPlugin('function', 'javascript',        array($this, 'print_javascript'));
$this->design->smarty->registerPlugin('block', 'css',        array($this, 'add_stylesheet_block'));
$this->design->smarty->registerPlugin('function', 'unset_css',        array($this, 'unset_stylesheet_function'));
$this->design->smarty->registerPlugin('function', 'stylesheet',        array($this, 'print_stylesheet'));
  1. Далее в этом же файле перед строкой:
public function get_discounted_products_plugin($params, &$smarty)

Добавим:

public function add_javascript_block($params, $content, $smarty, &$repeat)
    {
        if(!isset($params['id']) || $repeat || (empty($content)) && empty($params['include']))
            return false;
        if(!isset($params['priority']))
            $params['priority'] = 10;
        if(!empty($params['include']))
            $this->js->add_files($params['id'], $params['include'], $params['priority']);
        if(!empty($content))
            $this->js->add_code($params['id'], $content, $params['priority']);
        if(!empty($params['render']))
        {
            if(!isset($params['minify']))
                $params['minify'] = null;    
            if(!isset($params['combine']))
                $params['combine'] = true;
            return $this->js->render($params['id'], $params['minify'], $params['combine']);
        }
    }    
    public function unset_javascript_function($params, $smarty)
    {
        if(!isset($params['id']))
            return false;
        $this->js->unplug($params['id']);
    }
    public function print_javascript($params)
    {
        if(!isset($params['id']))
            $params['id'] = null;
        if(!isset($params['combine']))
            $params['combine'] = true;
        if(!isset($params['minify']))
            $params['minify'] = null;
        return $this->js->render($params['id'], $params['minify'], $params['combine']);
    }    
    public function add_stylesheet_block($params, $content, $smarty, &$repeat)
    {
        if(!isset($params['id']) || $repeat || (empty($content)) && empty($params['include']))
            return false;
        if(!isset($params['priority']))
            $params['priority'] = 10;
        if(!isset($params['less']))
            $params['less'] = false;
        if(!empty($params['include']))
            $this->css->add_files($params['id'], $params['include'], $params['priority'], $params['less']);
        if(!empty($content))
            $this->css->add_code($params['id'], $content, $params['priority'], $params['less']);
        if(!empty($params['render']))
        {
            if(!isset($params['minify']))
                $params['minify'] = null;    
            if(!isset($params['combine']))
                $params['combine'] = true;
            return $this->css->render($params['id'], $params['minify'], $params['combine']);
        }
    }    
    public function unset_stylesheet_function($params, $smarty)
    {
        if(!isset($params['id']))
            return false;
        $this->css->unplug($params['id']);
    }
    public function print_stylesheet($params)
    {
        if(!isset($params['id']))
            $params['id'] = null;
        if(!isset($params['combine']))
            $params['combine'] = true;
        if(!isset($params['minify']))
            $params['minify'] = null;
        return $this->css->render($params['id'], $params['minify'], $params['combine']);
    }
  1. В config-файл добавляем:
minify_js    = false;
minify_css    = false;
minify_gzip_level    = 0;
minify_cache_dir    = cache/minify/;
  1. В .htaccess после RewriteEngine on добавляем:
<FilesMatch "(js|css).gz[1-9]$">
	<IfModule mod_headers.c>
		Header set Content-Encoding: gzip
	</IfModule>
    <FilesMatch "css.gz[1-9]$">
        ForceType text/css
    </FilesMatch>
    <FilesMatch "js.gz[1-9]$">
        ForceType text/javascript
    </FilesMatch>
</FilesMatch>
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^cache/minify/(.+).gz([1-9])$ resize/gzip.php [L,END]

Чтобы всё заработало:

{stylesheet minify=true}
{javascript combine=true}

Группировка файлов:

{css id="libs" include=[
"design/{$settings->theme}/css/bootstrap.css",
"design/{$settings->theme}/css/animate.css",
"design/{$settings->theme}/css/style.css"
]}{/css}

{js id="libs" priority=99 include=[
"design/{$settings->theme}/js/jquery-2.1.1.min.js",
"design/{$settings->theme}/js/bootstrap.min.js"
]}{/js}

Функции принимают параметры:

id — служит для идентификации (обязательный параметр)
include — строка или массив строк для добавления в очередь
priority — приоритет вывода. По умолчанию равен 10 (если не указывать файлы будут становится один за одним согласно вызову функций) Чем больше приоритет тем он быстрее будет на выводе
less — если установлено true то данному ресурсу будет применен синтаксис less и перекодирован в css. (по умолчанию: false)
render — если данный параметр установлен в true то код на очередь не станет, а будет выведен прямо в месте вызова функции. Параметры minify и combine буриться глобальные.
minify — если данный параметр установлен в true то к данному ресурсу будет применяться сжатие. Если false — то файлы принадлежащие данному id не будут сжиматься. (по умолчанию: значение config.php)
combine — если данный параметр установлен в true то к данному ресурсу будет применяться упаковка в один файл. Если false — то файлы принадлежащие данному id не будут паковаться в один файл. (по умолчанию: значение config.php)

2018   htaccess   simplacms

SimplaCMS: Определение города пользователя по IP

Работает через Yandex API. Подключим jQuery, если до этого не подключён:

<script src="http://yastatic.net/jquery/2.1.1/jquery.min.js"></script>

Далее разместим в подвале скрипт:

<script type="text/javascript">
  window.onload = function () {
      jQuery("#user-city").text(ymaps.geolocation.city);
  }
</script>
<script src="http://api-maps.yandex.ru/2.0-stable/?load=package.standard&lang=ru-RU" type="text/javascript"></script>

А чтобы вывести, в шаблоне в необходимом месте пишем:

<div id="user-city"></div> или <span id="user-city"></span>
2018   simplacms
Ранее Ctrl + ↓