Опишу установку и настройку интернет-магазина на движке OpenCart в связке с шаблоном UniShop.
По шагам рассмотрим установку и настройку модулей.
1) Установка Опенкарт ПРО
Убираем ненужные ссылки из левого меню админки:
\admin\view\template\common\menu.tpl
языковой файл
\admin\language\russian\common\menu.php
хотел добавить свои, языковые константы не подхватились…
2) Удаление ненужных стран и регионов (оставляем только Россию)
3) Установка шаблона UniShop + блог
a. Исправил отображение корзины на странице заказа
\catalog\language\russian\checkout\simplecheckout.php
$_['text_items'] = '%s'; // sart //'Товаров: %s (%s)';
Убрал две ссылки у корзины в хэдере и поставил одну кнопку оформления заказа
\catalog\view\theme\unishop\template\common\cart.tpl
<?php } else { ?> <a href="/simplecheckout/" class="btn btn-primary"><?php echo $text_checkout; ?></strong></a> <!-- <a href="<?php echo $cart; ?>"><strong><i class="fa fa-shopping-cart"></i> <?php echo $text_cart; ?></strong></a> <a href="<?php echo $checkout; ?>"><strong><i class="fa fa-share"></i> <?php echo $text_checkout; ?></strong></a> --> <?php } ?>
b. Добавим вывод дополнительных вкладок на страницу товара.
\catalog\view\theme\unishop\template\product\product.tpl
<?php foreach($product_tabs as $key => $tab){ ?> <li><a href="#tab-<?php echo $product_id ?>-<?php echo $tab['product_tab_id']; ?>" data-toggle="tab"><?php echo $tab['title']; ?></a></li> <?php } ?>
<?php foreach($product_tabs as $key => $tab){ ?> <div class="tab-pane" id="tab-<?php echo $product_id ?>-<?php echo $tab['product_tab_id']; ?>"><?php echo $tab['description']; ?></div> <?php } ?>
c. Нужно выпилить стандартный блог Opencart.pro и установить UniBlog
— Удаляем все папки blog на хостинге
— Удаляем из БД все таблицы article и blog
— Из следующих файлов выпиливаем, либо комментим строки между //blog …… //blog:
\catalog\controller\common\seo_pro.php
(в этом файле дополнительно заменяем blog_category_id на category_id)
} elseif ($url[0] == 'blog_category_id') { if (!isset($this->request->get['blog_category_id'])) { $this->request->get['blog_category_id'] = $url[1]; } else { $this->request->get['blog_category_id'] .= '_' . $url[1]; }
В следующих файлах
\catalog\controller\common\column_left.php
\catalog\controller\common\column_right.php
\catalog\controller\common\content_top.php
\catalog\controller\common\content_bottom.php
выпилить блок
if ($route == 'blog/category' && isset($this->request->get['blog_category_id'])) { $this->load->model('blog/category'); $layout_id = $this->model_blog_category->getCategoryLayoutId($this->request->get['blog_category_id']); } if ($route == 'blog/article' && isset($this->request->get['article_id'])) { $this->load->model('blog/article'); $layout_id = $this->model_blog_article->getArticleLayoutId($this->request->get['article_id']); }
Эти файлы пока не трогаем, но будем иметь их ввиду:
\system\storage\modification\catalog\controller\common\seo_pro.php
\system\unishop_blog.ocmod.xml
4) Установка модификатора карты в админке
Тут, вроде, всё просто. Заливаем файлы и обновляем модификаторы.
5) Установка модуля Simple
Правки:
Редактируем страницу заказа Simple
Было: {left_column}{cart}{customer}{payment_address}{shipping_address}{/left_column}{right_column}{payment}{shipping}{comment}{/right_column}{payment_form}
Стало: {cart}{left_column}{customer}{shipping}{/left_column}{right_column}{shipping_address}{payment}{/right_column}{comment}{payment_form}
6) Установка модуля GeoIP
Инструкция от модуля
Инструкция от модуля
# GeoIP — определение региона по IP-адресу пользователя.
# Автор Роман Шипилов https://opencartforum.com/user/28285-progroman/
1) Скопируйте в корень сайта содержимое папки upload.
Для версии Opencart 2.2 и выше также скопируйте содержимое папки opencart-2.2.
2) Зайдите через браузер http://ВАШ_САЙТ/install-geoip, выберите необходимые настройки и нажмите кнопку «Установить», установщик добавит в вашу базу необходимые таблицы.
После установки папку install-geoip можно удалить.
3) Для Opencart до версии 2.2:
В index.php перед $controller = new Front($registry); добавьте $registry->set(‘geoip’, new GeoIP($registry));
В system/config/catalog.php добавить ‘geoip_mod’ через запятую в $_[‘library_autoload’] = array( … ); должно получится примерно так:
// Autoload Libraries $_[‘library_autoload’] = array( ‘openbay’, ‘geoip_mod’ );
4) Зайдите в установщик модулей OpenCart (http://ВАШ_САЙТ/admin/index.php?route=extension/installer), загрузите файл geoip.ocmod.xml.
5) В catalog/view/theme/ВАША_ТЕМА/template/common/header.tpl вставить
<?php echo $geoip; ?>
в том месте, где нужно вывести модуль.
6) Обновите модификаторы:
Перейдите в раздел Модификаторы (Modification) (http://ВАШ_САЙТ/admin/index.php?route=extension/modification), отметьте GeoIP и нажмите кнопку Обновить (Refresh) в правом верхнем углу.
7) Работа с поддоменами
Если вы используете поддомены, установите для них одну сессию, для этого в .htaccess добавьте:
php_value session.cookie_domain .site.com
где site.com — ваш сайт
Если ваш сайт находится на виртуальном хостинге и при этом php работает в режиме FastCGI, то установка некоторых переменных невозможна через .htaccess,
в том числе и php_value session.cookie_domain
Попробуйте устанавливать данное значение непосредственно в коде скрипта используя функцию ini_set()
ini_set('session.cookie_domain','.site.com');
В настройках модуля на вкладке «Редиректы» пропишите основной домен (для редиректа по-умолчанию).
Устанавливаем по инструкции и настраиваем.
Правки:
\catalog\view\theme\unishop\template\common\header.tpl
<!-- GeoIP --> <?php echo $geoip; ?> <!-- !GeoIP --> <?php echo $language; ?> <?php echo $currency; ?>
В файле стилей закомментируем размер шрифта:
\catalog\view\theme\default\stylesheet\geoip.css
/* geoip */ .geoip-module { padding: 7.5px 12px; /*font-size: 12px;*/ }
В модуле Simple есть функционал «Автозаполнение города», чтобы использовать города из установленной базы GeoIP (таблица fias в базе данных) нужно в
catalog/model/tool/simplegeo.php
раскомментировать (убрать /* в начале и */ в конце) код:
$sql = "SELECT g.id,g.full_name,g.name,g.postcode,z.zone_id,z.country_id FROM " . DB_PREFIX . "geo g LEFT JOIN " . DB_PREFIX . "zone z ON g.zone_id = z.zone_id WHERE g.name LIKE '" . $this->db->escape($city) . "%' AND g.postcode <> '' ORDER BY population DESC LIMIT 100"; /*$sql = " SELECT f1.fias_id AS id, CONCAT_WS(', ', CONCAT(f1.shortname, ' ', f1.offname), CONCAT(f2.offname, ' ', f2.shortname), CONCAT(f3.offname, ' ', f3.shortname), CONCAT(f4.offname, ' ', f4.shortname)) AS full_name, CONCAT(f1.shortname, ' ', f1.offname) AS name, f1.postalcode AS postcode, CASE WHEN ztf1.zone_id IS NOT NULL THEN ztf1.zone_id ELSE CASE WHEN ztf2.zone_id IS NOT NULL THEN ztf2.zone_id ELSE CASE WHEN ztf3.zone_id IS NOT NULL THEN ztf3.zone_id END END END AS zone_id, CASE WHEN ctf2.country_id IS NOT NULL THEN ctf2.country_id ELSE CASE WHEN ctf3.country_id IS NOT NULL THEN ctf3.country_id ELSE CASE WHEN ctf4.country_id IS NOT NULL THEN ctf4.country_id END END END AS country_id FROM fias f1 LEFT JOIN fias f2 ON f2.fias_id = f1.parent_id LEFT JOIN fias f3 ON f3.fias_id = f2.parent_id LEFT JOIN fias f4 ON f4.fias_id = f3.parent_id LEFT JOIN zone_to_fias ztf1 ON f1.fias_id = ztf1.fias_id LEFT JOIN zone_to_fias ztf2 ON f2.fias_id = ztf2.fias_id LEFT JOIN zone_to_fias ztf3 ON f3.fias_id = ztf3.fias_id LEFT JOIN country_to_fias ctf2 ON f2.fias_id = ctf2.fias_id LEFT JOIN country_to_fias ctf3 ON f3.fias_id = ctf3.fias_id LEFT JOIN country_to_fias ctf4 ON f4.fias_id = ctf4.fias_id WHERE f1.offname LIKE '" . $this->db->escape($city) . "%' AND (f1.level = 6 OR f1.level = 4 OR (f1.level = 1 AND f1.shortname = 'г.')) ORDER BY f1.level, f2.level, f3.level, f1.shortname LIMIT 100";*/
Работа с геотегами описана в хэлпе.
Создал геотэги «Предложный падеж города» и «Телефон»
Открываем контроллер шапки
\catalog\controller\common\header.php
и в начале функции index() после { добавляем:
// geoIP sart $geoip = $this->registry->get('geoip'); $data['geoip_city_predl'] = $geoip->getRule('city_predl');
т.к. сначала нужно определить телефон по умолчанию, после строки 96
$data['telephone'] = $this->config->get('config_telephone');
вставляем
$data['geoip_phone'] = $geoip->getRule('phone', $data['telephone']);
Выводим город в тайтл:
\catalog\view\theme\unishop\template\common\header.tpl
вместо
<title><?php echo $title; ?></title>
вставляем
<title><?php echo $title; ?> <?php echo $geoip_city_predl; ?></title>
И подменяем телефон для города
<div><i class="fa fa-phone" aria-hidden="true"></i> <span><?php echo $geoip_phone; ?><?php// echo $telephone; ?></span> <i class="fa fa-chevron-down hidden-xs" aria-hidden="true"></i></div>
7) Интеграция с RetailCRM
Устанавливаем по инструкции
Для синхронизации добавим 2 задания в крон
//каждые 4 часа /opt/php/5.6/bin/php-cgi -f /var/www/u0215002/data/www/new.zdravtovar.ru/system/cron/export.php >/dev/null 2>&1 //каждые 5 минут /opt/php/5.6/bin/php-cgi -f /var/www/u0215002/data/www/new.zdravtovar.ru/system/cron/history.php >/dev/null 2>&1 //каждые 5 минут wget -q -O - http://new.zdravtovar.ru/system/cron/history.php >/dev/null 2>&1
согласен, тут их три, но я не знаю какое работает…
Немного доработаем интеграцию. Нужно сделать так, чтобы в опенкарте у товара появилось дополнительное поле «закупочная цена» и эта цена выгружалась в CRM.
Ставим модуль CostPrice — закупочная цена товаров в opencart 1.01
Правим файл
\admin\model\retailcrm\icml.php
/** * Name & price & cost */ $e->appendChild($this->dd->createElement('name')) ->appendChild($this->dd->createTextNode($offer['name'])); $e->appendChild($this->dd->createElement('productName')) ->appendChild($this->dd->createTextNode($offer['name'])); $e->appendChild($this->dd->createElement('price')) ->appendChild($this->dd->createTextNode($offer['price'])); $e->appendChild($this->dd->createElement('purchasePrice')) ->appendChild($this->dd->createTextNode($offer['cost']));
Настроим передачу артикула не из поля sku, как это сделано по умолчанию, а из поля «Артикул»
/*if ($offer['sku']) { $sku = $this->dd->createElement('param'); $sku->setAttribute('code', 'article'); $sku->setAttribute('name', $this->language->get('article')); $sku->appendChild($this->dd->createTextNode($offer['sku'])); $e->appendChild($sku); }*/ if ($offer['model']) { $model = $this->dd->createElement('param'); $model->setAttribute('code', 'article'); $model->setAttribute('name', $this->language->get('article')); $model->appendChild($this->dd->createTextNode($offer['model'])); $e->appendChild($model); }
Добавим себестоимость доставки равной стоимости доставки
\admin\model\retailcrm\order.php
$order['delivery'] = array( 'code' => $settings['retailcrm_delivery'][$delivery_code], 'cost' => $deliveryCost, 'netCost' => $deliveryCost, // добавим себестоимость доставки 'address' => array( 'index' => $order_data['shipping_postcode'], 'city' => $order_data['shipping_city'], 'country' => $order_data['shipping_country_id'], 'region' => $order_data['shipping_zone_id'], 'text' => implode(', ', array( $order_data['shipping_postcode'], $country, $order_data['shipping_city'], $order_data['shipping_address_1'], $order_data['shipping_address_2'] )) ) );
Интеграция с Collector.
\catalog\view\theme\unishop\template\common\header.tpl
<script type="text/javascript"> (function(_,r,e,t,a,i,l){_['retailCRMObject']=a;_[a]=_[a]||function(){(_[a].q=_[a].q||[]).push(arguments)};_[a].l=1*new Date();l=r.getElementsByTagName(e)[0];i=r.createElement(e);i.async=!0;i.src=t;l.parentNode.insertBefore(i,l)})(window,document,'script','https://collector.retailcrm.pro/w.js','_rc'); _rc('create', 'RC-61094637833-3', { 'customerId': '<?=$customer_id?>' }); _rc('send', 'pageView'); </script> </head>
\catalog\controller\common\header.php
if ($this->customer->isLogged()) { $data['customer_id'] = $this->customer->getId(); } else {$data['customer_id'] = '';}
Парам-пам-пам! Нихуя не работает…
Едем дальше. Настроим интеграцию с Ecommerce Universal Analytics как самого магазина так и RetailCRM.
Как пошагово настроить счетчик — тут
Устанавливаем код счетчика на сайт и пишем небольшой модуль для ecommerce.
ga_ecommerce.ocmod.xml
ga_ecommerce.ocmod.xml
<?phpxml version="1.0" encoding="UTF-8"?> <modification> <name>Ecommerce for Universal Analitics</name> <code>commercega</code> <version>1.0</version> <author>Sart</author> <link>http://redseo.ru/ga-ecommerce/</link> <file path="catalog/controller/checkout/success.php"> <operation> <search><![CDATA[ if (isset($this->session->data['order_id'])) { ]]></search> <add position="after"><![CDATA[ $data['ga_order_id'] = $this->session->data['order_id']; $data['ga_store_name'] = $this->config->get('config_name'); $this->load->model('account/order'); $this->load->model('checkout/order'); $data['ga_order_info'] = $this->model_checkout_order->getOrder($this->session->data['order_id']); $data['ga_order_info1'] = $this->model_account_order->getOrder($this->session->data['order_id']); $data['ga_order_products'] = $this->model_account_order->getOrderProducts($this->session->data['order_id']); $data['ga_order_total'] = $this->model_account_order->getOrderTotals($this->session->data['order_id']); ]]></add> </operation> </file> <file path="catalog/view/theme/*/template/common/success.tpl"> <operation> <search><![CDATA[<?php echo $footer; ?>]]></search> <add position="before"><![CDATA[ <?php if(isset($ga_order_id) && $ga_order_id) { ?> <?php foreach ($ga_order_total as $totals) { if ($totals['code'] == 'shipping') { $deliveryCost = $totals['value']; } } ?> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-32005850-1', 'auto'); function getRetailCrmCookie(name) { var matches = document.cookie.match(new RegExp( '(?:^|; )' + name + '=([^;]*)' )); return matches ? decodeURIComponent(matches[1]) : ''; } ga('set', 'dimension1', getRetailCrmCookie('_ga')); ga('send', 'pageview'); ga('require', 'ecommerce', 'ecommerce.js'); ga('ecommerce:addTransaction', { 'id': '<?php echo $ga_order_id; ?>A', 'affiliation': '<?php echo $ga_store_name; ?>', 'revenue': '<?php echo $ga_order_info["total"]; ?>', 'shipping': '<?php echo $deliveryCost; ?>', 'tax': '' }); <?php foreach ($ga_order_products as $row) { ?> ga('ecommerce:addItem', { 'id': '<?php echo $ga_order_id; ?>A', 'name': '<?php echo $row["name"]; ?>', 'sku': '<?php echo $row["model"]; ?>', 'category': '', 'price': '<?php echo $row["price"]; ?>', 'quantity': '<?php echo $row["quantity"]; ?>' }); <?php } ?> ga('ecommerce:send'); </script> <?php } ?> ]]></add> </operation> </file> <file path="catalog/view/theme/*/template/common/footer.tpl"> <operation> <search><![CDATA[<?php foreach ($analytics as $analytic) { ?>]]></search> <add position="replace" offset="2"><![CDATA[ <?php if ($_SERVER['QUERY_STRING'] != 'route=checkout/success') { ?> <?php foreach ($analytics as $analytic) { ?> <?php echo $analytic; ?> <?php }} ?> ]]></add> </operation> </file> </modification>
Различные правки
После удаления парсера прайсов, с какого-то хера отвалились страницы производителей…
Ошибка выскакивала в уже засветившихся ранее файлах:
\catalog\controller\common\column_left.php
\catalog\controller\common\column_right.php
\catalog\controller\common\content_top.php
\catalog\controller\common\content_bottom.php
выпилить блок
if ($route == 'product/manufacturer/info' && isset($this->request->get['manufacturer_id'])) { $this->load->model('catalog/manufacturer'); $layout_id = $this->model_catalog_manufacturer->getManufacturerLayoutId($this->request->get['manufacturer_id']); }
Убираем дополнительные разряды в весе на странице корзины
\system\library\weight.php
public function format($value, $weight_class_id, $decimal_point = '.', $thousand_point = ',') { if (isset($this->weights[$weight_class_id])) { // добавлено if ($this->weights[$weight_class_id]['unit']=="гр") {return number_format($value, 0, $decimal_point, $thousand_point) ." ". $this->weights[$weight_class_id]['unit'];} // конец return number_format($value, 2, $decimal_point, $thousand_point) ." ". $this->weights[$weight_class_id]['unit']; } else { return number_format($value, 2, $decimal_point, $thousand_point); } }