Главная / Мои проекты / ЗдравТовар / Создание интернет-магазина с нуля. Opencart PRO + UniShop

Создание интернет-магазина с нуля. Opencart PRO + UniShop

Опишу установку и настройку интернет-магазина на движке 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>&nbsp;&nbsp;&nbsp;
        <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

Инструкция от модуля

Инструкция от модуля

# Модуль для CMS OpenCart (ocStore)
# 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));

Для Opencart 2.2 и выше:
В 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');

В настройках модуля на вкладке «Редиректы» пропишите основной домен (для редиректа по-умолчанию).

Страница модуля на opencartforum

Устанавливаем по инструкции и настраиваем.

Правки:

\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);
		}
	}

 

Автор: Алексей Байков

Алексей Байков
Веду записи в основном для себя, т.к. частенько всё забываю.
  • Dmitri Sorokin

    Очень полезная статья,спасибо..ещё огромная просьба помочь с установкой Multimerch на unishop… С подробным описанием, я думаю многим она поможет…