Перейти к содержанию

admin

Администратор
  • Постов

    994
  • Зарегистрирован

Сообщения, опубликованные admin

  1. Сортировка товаров в Opencart по названию в списке никак не хотело выводить в нужном порядке. Пришлось искать обходной путь

    Как-то у меня появилось задание - починить сортировку по алфавиту, то есть по названию товара. К моему большому удивлению в списке товаров сортировка не работала, было все в разброс.

    Код стоял стандартный Opencart где в методе выборки товаров четко задана сортировка $sql .= " ORDER BY LCASE(" . $data['sort'] . «)"; но это не срабатывало.

    Подозрение пало на старую версию mysql на сервере, в которой есть такие проблемы.

    Решается это достаточно просто.

    Открываем файл catalog/model/catalog/product.php находим строку

    $sql .= " ORDER BY LCASE(" . $data['sort'] . ")";

    И меняем на

    $sql .= " ORDER BY BINARY(lower(" . $data['sort'] . "))";

    Таким образом у нас выровняется сортировка по алфавиту.

    Но метод обходной и я рекомендую просто обновить mysql на сервере.

     

  2. Для сортировки элементов в списке можно использовать javascript библиотеку jquery.ui. Для её работы необходимо подключить скрипт. Открываем файл admin/view/template/common/header.tpl находим строку подключения jquery, например

    <script type="text/javascript" src="view/javascript/jquery/jquery-2.1.1.min.js"></script>

    и сразу после нее вставляем строку подключения jquery.ui

    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>

    После этого открываем файл шаблона модуля рекомендуемые по адресу admin/view/template/module/featured.tpl где находим строки

    <script type="text/javascript"><!--

    после них вставляем

    $(document).ready(function(){
      sortable_product();
    });
    function sortable_product(){
      $('#featured-product').sortable({
          cursor: 'move'
      });
      $('#featured-product').disableSelection();
    }

    И в Ajax запросе там где success и select в конец добавляем вызов функции sortable_product();

    Таким образом мы добавили сортировку рекомендуемых товаров простым перемещением курсора мышки

    Такую сортировку можно применить по аналогии в любых списках - что дает нам еще больше удобства в админке.

  3. photocopy.png.e7bd6199a009319f9cd27b273483febc.png

    Делюсь скриптом простого удаления всех ненужных фото удаленных товаров

    Когда в Opencart удаляется товар, фото физически остается на сервере а удаляется лишь в базе сам товар и привязка к файлу.

    Чем это плохо?

    Первое - это накопление ненужных файлов. Как следствие,  для магазина требуется еще больше памяти на сервере, а это дополнительные затраты. Второе - при наличии большого количества файлов сайт может подтормаживать.

    По-этому хочу поделится с вами скриптом, который сможет удалить все неиспользуемые фото товара. Скрипт достаточно простой и по желанию можно доработать под свои потребности.

    Сразу хочу сказать, что фото должны быть в отдельной папке от всех остальных изображений, баннеров, картинок шаблона и т.п. То есть фото полностью отделено от магазина.

    Код скрипта можно вставить например в admin/controller/common/header.php в функцию index

    echo "<pre>";
    		$net = 0;
    		$find_files = $this->scan_Dir(DIR_IMAGE . "data"); // здесь указываем директория где есть только фото товаров
    		if($find_files){		
    			foreach($find_files as $file){
    				$image = explode("www/image/", $file);
    				
    				$query = $this->db->query("SELECT product_id FROM oc_product WHERE image = '".$image[1]."'"); //главное фото
    				if(!$query->rows){
    					$query_dop = $this->db->query("SELECT * FROM oc_product_image WHERE image = '".$image[1]."'"); //доп фото
    					if(!$query_dop->rows){
    						//echo $file . "<br>"; //можно раскомментировать строку - отображение файла который удаляется
    						unlink($file);
    						$net++;
    					}					
    				}
    			}
    		}
    echo "Всего фото: " . count($find_files) . "<br>";
    echo "Удалено: " . $net . "<br>";		
    echo "</pre>";

    И перед функцией index вставляем функцию сканирования папки:

    public function scan_Dir($dir) {
    		$dir = str_replace("//", "/", $dir);
    		$arrfiles = array();
    		if (is_dir($dir)) {
    			if ($handle = opendir($dir)) {
    				chdir($dir);
    				while (false !== ($file = readdir($handle))) {
    					if ($file != "." && $file != "..") {
    						if (is_dir($file)) {
    							$arr = $this->scan_Dir($file);
    							foreach ($arr as $value) {
    								$arrfiles[] = $dir."/".$value;
    							}
    						} else {
    							$arrfiles[] = $dir."/".$file;
    						}
    					}
    				}
    				chdir("../");
    			}
    			closedir($handle);
    		}
    		return $arrfiles;
    	}

    После сохранения - заходим в админку и смотрим на статистику сколько есть файлов и сколько удалено лишних.

    В примере поставлен стандартный префикс oc_ для таблиц в Opencart, если у вас другой (смотрите конфиг) поменяйте.

    Вообще что бы не копились фото при удалении товара а сразу удалялись рекомендую использовать бесплатный модуль.

    delete_images.ocmod.zip

  4. extended-search.png.f580a27f979815a82d7bfaff3ece1dd5.png

    Дорабатываем поиск что бы искал не только товары, но и категории

    Приветствую друзья! Сегодня я хочу поделиться решением которое позволит выполнять поиск не только по товарам а и по категориям.

    Зачем это нужно

    Во-первых, идет более понятная выдача, многие покупатели просто не хотят искать в категориях ту что надо, особенно если их много. Они просто вбивают в поиск название того что ищут. Например, это может быть запрос Велосипед или Мотоцикл.

    Во-вторых, в магазинах часто идет название категории а в ней идут модели товаров, часто без названия что это именно. Тот же пример на велосипедах. Есть категория Велосипеды в ней идут товары в названия которых есть только бренд и модель. В таком случае в стандартном поиске ничего не будет найдено из-за того что нет вхождений поискового запроса в названии товара.

    Совсем другое дело когда мы добавим поиск по категориям, и тогда при поиске у нас будет выведена категория Велосипеды, перейдя в которую покупатель найдет то, что он искал.

    Как это сделать

    Для начала нам надо в модель добавить метод выборки категорий по исковому запросу. Для этого открываем файл catalog/model/catalog/category.php и добавляем эту функцию:

    public function getCategoriesLive($search) {
    		$category_data = array();
    		$sql = "SELECT * FROM " . DB_PREFIX . "category c
    			LEFT JOIN " . DB_PREFIX . "category_description cd ON (c.category_id = cd.category_id)
    			LEFT JOIN " . DB_PREFIX . "category_to_store c2s ON (c.category_id = c2s.category_id) WHERE
    			cd.name LIKE '%" . $search . "%' 
    			AND cd.language_id = '" . (int)$this->config->get('config_language_id') . "'
    			AND c2s.store_id = '" . (int)$this->config->get('config_store_id') . "'
    			AND c.status = '1' ORDER BY c.sort_order, LCASE(cd.name)";
    		$query = $this->db->query($sql);
    		foreach ($query->rows as $result) {
    			$category_data[$result['category_id']] = $this->getCategory($result['category_id']);
    		}
    		return $category_data;
    	}

    После этого надо перейти в контроллер и добавить код для формирования массива найденных категорий. Открываем файл catalog/controller/product/search.php и перед строкой

    $data['products'] = array();

    Добавить строки:

    $data['cats'] = array();
    		$categories = $this->model_catalog_category->getCategoriesLive($search);
    		foreach($categories as $category){
    			$data['cats'][] = array(
    				'product_id' => $category['category_id'],
    				'name'       => html_entity_decode($category['name'], ENT_QUOTES, 'UTF-8'),
    				'url'        => $this->url->link('product/category', 'path=' . $category['category_id'])
    			);
    		}

    После чего переходим в шаблон и добавим вывод найденных категорий. Для этого открываем файл catalog/view/theme/ТЕМА/template/product/search.tpl где в нужном месте добавляем вывод категорий строками:

    <?php if ($cats) { ?>
            <h2>Найденные категории</h2>
            <ul>
              <?php foreach($cats as $cat) { ?>
                <li><a href="<?php echo $cat['url']; ?>"><?php echo $cat['name']; ?></a></li>
              <?php } ?>
            </ul>
          <?php } ?>

    Этим кодом мы заставляем поиск искать и по категориям. На этом конечно не ограничивается, это как заготовка, которую можно расширять по своему усмотрению. Понятно, по аналогии можно можно сделать и в быстром поиске, да и везде где есть поиск.

  5. sortable-cart-opencart.jpg.e87cf7247123085a71c3bcfeb27ae9d3.jpg

    Сортировка товаров в корзине по порядку добавления

    В Opencart с 2.x сортировка товаров в корзине не соответствует порядку их добавления. Например мы добавили домофон, кабель к нему и монитор. Так вот в корзине может быть нарушен порядок, то есть сначала будет идти кабель, потом монитор а уже после них первый добавленный домофон. Согласитесь, это не совсем логично.

    Виной всему будет выборка из базы данных в таблице  cart. Дело в том что при запросе в базу нет условия сортировки и данные идут как им захочется. Что бы структурировать их необходимо в файле system/library/cart/cart.php строку

    $cart_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "cart WHERE api_id = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "' AND customer_id = '" . (int)$this->customer->getId() . "' AND session_id = '" . $this->db->escape($this->session->getId()) . "' ORDER BY date_added ASC");

    Таким образом в конец запроса мы добавили условия сортировки - сортировать по дате добавления по возрастания. После чего в корзине будут идти товары в той последовательности в которой их добавили туда.

  6. short_seo_url.png.6f3cbce8a2879d7f275b1891f8fe5afc.png

    Делаем краткие ЧПУ адреса с полноценные хлебными крошками

    Из коробки OcStore создает ЧПУ с вложенностью, например:

    Страница категории: сайт/категория/подкатегория/...и т.д.

    Страница товара: сайт/категория/подкатегория/товар

    В SEOPRO есть настройка, которая позволяет делать ЧПУ товара прямым без подкатегорий - сайт/товар

    Но для категорий нет такой настройки и проходится делать доработку что бы ссылка на категория была сайт/конечная-категория без вложенности промежуточных категорий.

    Как это сделать что бы хлебные крошки были полные а ссылка короткая?

    Первое, переходим в catalog/controller/common/seopro.php (catalog/controller/startup/seopro.php) и строки

    foreach ($categories as $category) {
      $queries[] = 'category_id=' . $category;
    }

    надо заменить на

    $queries[] = 'category_id=' . end($categories);

    После чего у нас ЧПУ станет коротким, в котором будет только последняя категория. Однако, при таком подходе поломаются хлебные крошки, в которых пропадет полный путь к категории. Для того что бы сделать полные хлебные крошки, нам надо позаимствовать один метод из seopro.

    Для этого открываем файл - контроллер категории catalog/caontroller/product/category.php где вставляем метод формирования правильного пути к категории:

    private function getPathByCategory($category_id) {
      $category_id = (int)$category_id;
      if ($category_id < 1) return false;
      static $path = null;
      if (!isset($path)) {
        $path = $this->cache->get('category.seopath');
        if (!isset($path)) $path = array();
      }
      if (!isset($path[$category_id])) {
        $max_level = 10;
        $sql = "SELECT CONCAT_WS('_'";
        for ($i = $max_level-1; $i >= 0; --$i) {
          $sql .= ",t$i.category_id";
        }
        $sql .= ") AS path FROM " . DB_PREFIX . "category t0";
        for ($i = 1; $i < $max_level; ++$i) {
          $sql .= " LEFT JOIN " . DB_PREFIX . "category t$i ON (t$i.category_id = t" . ($i-1) . ".parent_id)";
        }
        $sql .= " WHERE t0.category_id = '" . $category_id . "'";
        $query = $this->db->query($sql);
        $path[$category_id] = $query->num_rows ? $query->row['path'] : false;
        $this->cache->set('category.seopath', $path);
      }
      return $path[$category_id];
    }

    После чего находим в этом же файле строку

    $parts = explode('_', (string)$this->request->get['path']);

    И заменяем на

    $parts = explode('_', $this->getPathByCategory($this->request->get['path']));

    Таким образом у нас ссылка будет только с последней категорией а хлебные крошки полные.

  7. Периодически проскакивают номера заказов и теряются заказы - узнаем причину и как это поправить.

    Очень часто ко мне обращаются мои клиенты с просьбой разобраться почему у них пропадают заказы. То есть клиенты звонят и говорят что заказ сделали но никто не перезванивает. И в админке номера заказов сбиваются. К примеру заказы были 13 434, 13 435 и следующий будет 13 437 то есть 13 436 пропал.

    Такая ситуация случается часто, причина этому - не назначение статуса заказа.

    Вылечить проблему можно следующим образом:

    Заходим в файл admin/model/sale/order.php

    Строку

    $sql .= " WHERE o.order_status_id > '0'";

    Заменяем на:

    $sql .= " WHERE o.total";

    Таким образом мы делаем выборку заказов в магазине без учета статуса и все заказы у нас не пропадают а высвечиваются в заказах.

    Еще хочу заметить что в редактируемом файле таких строк 2 - все заменяем и будет все работать, но есть нюанс во второй замене нет приставки o.

  8. Как при зажатии кнопки +/- делать ускоренное увеличение/уменьшение количества товара
    opencart_calc.png.c69a32b58a30cfece59f05715c6460c8.png

    Как понять что кнопки мыши зажата и выполнять какое-то действие при длительном нажатии.


    Часто делаю калькуляторы, где есть расчеты по количеству квадратных метров, количество упаковок, добавляю +/- в товаре и другие доработки.

    Недавно обратился постоянный заказик с просьбой сделать ускоренное действие по зажатии кнопки мышки на + или -. У него я ранее делал кнопки + и - при нажатии на которые увеличивается или уменьшается количество товара с шагом 0.1.

    Небольшая пред история

    Заказчик сообщил что смотрит в яндекс вибвизоре и клиенты на его сайте что бы выбрать количество 6 кликают 60 раз по кнопке плюс))! (Шаг то 0.1). Он предложил сделать как в пульте от телевизора - когда зажимаешь кнопку идет быстрое изменение количества.

    Итак, сказано, сделано. Для этого достаточно было написать небольшой код:

    //быстрое зажатие
    $('.tab_box .calc_input span').mousedown(function(){ //нажатие кнопки мышки
      this_class = $(this).attr('class'); //берем класс кнопки (что бы понять + это или -)
      click_interval = false;
      click_timer = setTimeout(function(){ //запускаем таймаут что бы понять что кнопка зажата более чем на 300мс
        click_interval = setInterval(function(){ //запускаем действие через интервал 30мс
          $('.tab_box .calc_input span.' + this_class).trigger('click'); //само действие - клик по кнопке + или -
        }, 30);
      }, 300);
    });
    $('.tab_box .calc_input span').mouseup(function(){ //когда отпускаем кнопку мышки все ресетим
      clearTimeout(click_timer); //убираем таймаут
      clearInterval(click_interval); //убираем интервал
    });
    $('.tab_box .calc_input span').mouseleave(function(){ //когда покидаем мышкой кнопку (фикс когда зажатой кнопкой покинем + или -)
      clearTimeout(click_timer);
      clearInterval(click_interval);
    });
    //быстрое зажатие

    Таким образом при зажатии кнопки более чем на 300мс идут имитации быстрых кликов с интервалом 30мс на которых уже есть события + и -. Задача выполнена на 100%, клиент доволен. А кому надо можете использовать этот код у себя в проектах

  9. В Opencart есть один небольшой но досадный баг. При пагинации есть ссылка на первую страницу с параметром page=1 и при переходе открывается дубль категории. Исправляем это

    В пагинации Opencart зарыто очень много багов. Например при перелистывании категории кнопками 1.2.3... у нас создаются дубли страниц, которые можно решить с помощью внедрения тегов prev и next. Но самый жесткий это дубль категории из-за ссылки https://site.com/category/?page=1. Эта ссылка формируется в пагинации для страницы 1. Хотя должна там быть без page=1.

    Как решить проблему с page=1

    Отчасти можно поправить пагинацию (system/library/pagination) что бы не формировалась сама ссылка. Но почему отчасти? Потому что все равно при переходе на страницу https://site.com/category/?page=1 робот увидит дубль. Надо с page=1 делать 301 редирект на страницу без page. Много кто скажет а как же роботы найдут страницу с параметром page если ее не формировать. Да, по логике не должны, но как показывает практика роботы все это видят.

    Для того что бы решить проблему надо в контроллер категории после пагинации добавить код:

    //301 from page=1
    if(isset($this->request->get['page']) && $this->request->get['page'] == 1){
      header('Location: ' . $this->url->link('product/category', 'path=' . $category_info['category_id'], true), true, 301);
      exit();
    }
    //301 from page=1

    Так, если система увидит что page=1 автоматически сделает редирект на страницу без параметра page. Это небольшое дополнение в код защитит вас от дублей категории.

  10. information-in-product-page-opencart-min.thumb.png.267337da7a30ed77e6e9f35ea0aa069b.png

    Для того что бы вывести кастомную информацию не надо много кода. Достаточно применить правильный подход и пару строк кода. Читаем в статье.

    Приветствую тебя юный разработчик! Очень часто в заданиях или целых проектах у меня бывают похожие пункты. Очень популярный это вывод информационного блока в карточке товара, а то и не одного.

    Конечно, можно сделать в стиле хард кодинг - это прописать текст в нужном блоке прямо в шаблоне интернет магазина. Но это не наши методы. При таком подходе для изменения информации надо залезать в код. Ну очень жестко. Тем более ни о какой мультиязычности не может быть и речи. Ладно не буду описывать неправильное. Гораздо лучше акцентировать внимание как сделать правильно.

    Делаем функционал

    Для того что бы вывести информацию нам надо ее создать и где-то редактировать. Я сторонник того что бы как можно меньше делать какой-то кастом а использовать по максимуму стандартные возможности движка.

    Для создания информационного блока воспользуемся Каталог - Статьи и просто создаем статью. Хорошо то, что у нас есть возможность не только задать информацию в визуальном редакторе а также есть масса других полей который также можно использовать в наших целях. И заметьте, пока что ни одного файла не изменено.

    После этого открываем контроллер товара catalog/controller/product/product.php и вставляем строки:

    $this->load->model('catalog/information');
    $information_info = $this->model_catalog_information->getInformation(777);
    $data['custom_info'] = html_entity_decode($information_info['description'], ENT_QUOTES, 'UTF-8');

    где 777 - это id статьи.

    После этого у нас в шаблон товара уже передается переменная custom_info где и будет выводится на нужном языке информация в карточке товара. Для вывода достаточно вывести в любом нужном месте в карточке товара кодом: <?php echo $custom_info; ?>

    Редактировать ее можно как и обычную статью через админку.  С минимальными изменениями мы сделали отличный кастомный функционал.

  11. Зачем это нужно и как выглядит

    Это нужно что бы в определенном блоке вывести все заголовки описания и при клике на любой зоголовок идет пролистывание к нему в описании.

    Также при скролле справа надо было сделать плавающий блок с заголовками что бы читая описание можно было переходить по нему с помощью удобного меню.

    Так как описаний в магазине 80 000 было принято решение сделать все автоматически. Для этого надо обработать описание товара. А где это сделать как не в контроллере. Но для "считывания" описания нам поможет библиотека phpQuery. 

    phpQuery - это как jQuery только в php. Позволяет забирать какие-то данные по селекторам, как в js

    Для подключения библиотеки для начала скачиваем ее и открываем файл catalog/controller/product/product.php и после <?php вставляем строку для подключения библиотеки

    require_once(DIR_SYSTEM . 'library/phpQuery-onefile.php');

    После можем в любом удобном месте функции index вставить код который "выдергивает" все заголовки из описания и создает блок с заголовками

    $description = $data['description'];
    $tags = array();
    $doc = phpQuery::newDocumentHTML($description);
    phpQuery::selectDocument($doc);
    foreach(pq(':header') as $index_h => $h){
    	$tags[] = html_entity_decode("<a class='mh-" . $h->nodeName . "' data-name='hname-" . $index_h . "' href='". $this->url->link('product/product', $url . '&product_id=' . $product_id) . "#hname-" . $index_h . "'>" . $h->nodeValue . "</a>",ENT_QUOTES,'UTF-8');
    	$data['description'] = str_replace($h->nodeValue . "</" . $h->nodeName. ">", '<a name="hname-' . $index_h . '"></a>' . $h->nodeValue. "</" . $h->nodeName. ">", $data['description']);
    }
    $data['description_tags'] = $tags;

    Далее нам надо в любом удобном месте вывести это в шаблоне товара

    <?php foreach($description_tags as $desc_tag){ ?>
      <li>
        <?php echo $desc_tag; ?>
      </li>
    <?php } ?>

    И конечно же добавим стилей и скриптов что бы все это украсить и оживить

    Стили

    .show-description-nav{padding: 10px 10px 7px 10px;background: #fff;border: 1px solid #ddd;box-shadow: 0 0 10px #999;}
    .fixed_menu_right{display:none;position: fixed;z-index:9999999;left:50%;top:30%;margin-left:360px;}
    .fixed_menu_right:hover .description-navigation-scrolling{display:block;}
    .show-description-nav .fa{font-size:25px;}
    .description-navigation-scrolling{position: absolute;display: none;background:#fff;width:410px;top:-20px;left:-60px;border: 1px solid #ddd;box-shadow: 0 0 10px #999;padding:10px 10px 10px 5px;}
    .description-navigation ul{padding-left:0;}
    .description-navigation li{list-style-type: none;margin-bottom:5px;}
    .description-navigation li a{font-size:13px;text-decoration:none;border-bottom:1px dashed #333;}
    .description-navigation li a:hover{border-bottom:1px dashed #fff;}
    .mh-h1{margin-left:0px;font-size:20px!important;margin-bottom:20px;}
    .mh-h2{margin-left:10px;font-size:16px!important;margin-bottom:10px;}
    .mh-h3{margin-left:20px;font-size:14px!important;}
    .mh-h4{margin-left:30px;font-size:13px!important;}
    .mh-h5{margin-left:40px;font-size:12px!important;}
    .mh-h6{margin-left:50px;font-size:11px!important;}

    Скрипты

    $(document).ready(function(){
    	$(".description-navigation a, .description-navigation-scrolling a").click(function(e) {
    		e.preventDefault();
    		scrollTo = $(this).data("name");
    		$([document.documentElement, document.body]).animate({
    			scrollTop: $("a[name = '" + scrollTo + "']").offset().top
    		}, 700);
    	});
    	$(document).scroll(function(){
    		if($(window).scrollTop() < 500  && $(window).width() > 768){
    			$('.fixed_menu_right').fadeOut(200);
    		}else{
    			$('.fixed_menu_right').fadeIn(200);
    		}
    	});
    });

    И чуть не забыл еще если хотите вывести плавающий фикс блок с заголовками то сделать это можно например так

    <div class="fixed_menu_right">
      <button class="show-description-nav"><i class="fa fa-bars" aria-hidden="true"></i></button>
      <div class="description-navigation-scrolling">
        <ul>
          <?php foreach($description_tags as $desc_tag){ ?>
            <li>
              <?php echo $desc_tag; ?>
            </li>
          <?php } ?>
        </ul>
      </div>
    </div>

    Таким образом у нас есть функционал для автоматического отделения заголовков и создания якорей. 

    Кстати якори очень полезная штука для СЕО

  12. Во втором Opencart замечен странный баг который вместо копирования товара в списке его удаляет. Что бы исправить необходимо открыть файл

    admin/view/template/catalog/product_list.tpl

    <button type="submit" form="form-product" href="<?php echo $copy; ?>" data-toggle="tooltip" title="<?php echo $button_copy; ?>" class="btn btn-default"><i class="fa fa-copy"></i></button>

    или (в зависимости от версии Opencart)

    <button type="submit" form="form-product" formaction="<?php echo $copy; ?>" data-toggle="tooltip" title="<?php echo $button_copy; ?>" class="btn btn-default"><i class="fa fa-copy"></i></button>

    Заменяем на строку

    <button type="button" data-toggle="tooltip" title="<?php echo $button_copy; ?>" class="btn btn-default" onclick="$('#form-product').attr('action', '<?php echo $copy; ?>').submit()"><i class="fa fa-copy"></i></button>

    Таким образом мы поменяли систему отправки формы что бы браузера google chrome все это нормально отрабатывал.

  13. calculate-square-metrs.jpg.6562631308c2c1fce8d9f97c488d580d.jpg

     

    Часто бывает что цена идет за кв.м., а в упаковке, например ламината, находится более одного квадратного метра. В таком случае наш магазин должен автоматически все считать.


    Часто бывает, особенно в строительных магазинах, что цена идет за квадратный метр, а в упаковке, например ламината, находится более одного квадратного метра. Покупатель будет заказывать определенное количество упаковок, а Opencart должен автоматически подсчитывать сколько это в квадратных метрах.

    Например, нам надо купить ламинат на комнату 20 кв.м.

    Первое что бы делаем это находим интернет магазин, выбираем товар и ставим в количество упаковок. Но без автоматического подсчета неудобно совершать покупки. Из-за этого надо вручную считать сколько заказывать.

    В этой доработке мы сделаем автоматический подсчет упаковок товара.

    План работ

    1. Добавление в админку поле ввода количества квадратных метров в упаковке. (Например 1,56 кв.м. в пачке ламината)
    2. Добавляем в карточке товара + и - для увеличения или уменьшения количества упаковок в кв.м.
    3. Добавляем код для правильного отображения в категории..

    Добавляем в админку поле ввода.

    Открываем файл admin/catalog/view/template/catalog/product_form.tpl

    ищем строки:

    <div class="form-group">
      <label class="col-sm-2 control-label" for="input-price"><?php echo $entry_price; ?></label>
      <div class="col-sm-10">
    	<input type="text" name="price" value="<?php echo $price; ?>" placeholder="<?php echo $entry_price; ?>" id="input-price" class="form-control" />
      </div>
    </div>

    после них вставляем:
     

    <div class="form-group">
      <label class="col-sm-2 control-label" for="input-mpn">Количество м<sup>2</sup> в упаковке</label>
      <div class="col-sm-10">
        <input type="text" name="mpn" value="<?php echo $mpn; ?>" id="input-mpn" class="form-control" />
      </div>
    </div>

    Эти строки удаляем:
     

    <div class="form-group">
      <label class="col-sm-2 control-label" for="input-mpn"><span data-toggle="tooltip" title="<?php echo $help_mpn; ?>"><?php echo $entry_mpn; ?></span></label>
      <div class="col-sm-10">
       <input type="text" name="mpn" value="<?php echo $mpn; ?>" placeholder="<?php echo $entry_mpn; ?>" id="input-mpn" class="form-control" />
      </div>
    </div>

    Этим кодом мы добавили поле ввода количества м2 для товара в админке, путем удаления ненужного mpn и присвоения этой переменной нашему полю.


    square-meters-in-admin.jpg.7a1c8d45bc541fd38a07f0e7a4225a4c.jpg

     

    Также добавим поле для ввода количества штук в упаковке (для информации покупателю). Для этого после строк выше добавляем:
     

    <div class="form-group">
      <label class="col-sm-2 control-label" for="input-isbn"><span data-toggle="tooltip" >Количество шт. в упаковке</span></label>
      <div class="col-sm-10">
        <input type="text" name="isbn" value="<?php echo $isbn; ?>" placeholder="<?php echo $entry_isbn; ?>" id="input-isbn" class="form-control" />
      </div>
    </div>

    И удаляем код для ввода isbn, который практически никому не нужен:
     

    <div class="form-group">
      <label class="col-sm-2 control-label" for="input-isbn"><span data-toggle="tooltip" title="<?php echo $help_isbn; ?>"><?php echo $entry_isbn; ?></span></label>
      <div class="col-sm-10">
        <input type="text" name="isbn" value="<?php echo $isbn; ?>" placeholder="<?php echo $entry_isbn; ?>" id="input-isbn" class="form-control" />
      </div>
    </div>

    Далее открываем файл admin/model/catalog/product.php

    Ищем в документе отрезок кода:

    price = '" . (float)$data['price'] . "',

    И меняем его на:
     

    price = '" . (float)$data['price'] * ($data['mpn']?$data['mpn']:1) . "',

    Этим мы добавили калькуляцию цены в зависимости от количества квадратов в упаковке. Если количество квадратов не заполнено, цена будет оригинальная.

    Далее открываем файл admin/controller/catalog/product.php

    Находим строки:
     

    if (isset($this->request->post['price'])) {
    	$data['price'] = $this->request->post['price'];
    } elseif (!empty($product_info)) {
    	$data['price'] = $product_info['price'];
    } else {
    	$data['price'] = '';
    }  

    Меняем их на:

    if (isset($this->request->post['price'])) {
    	$data['price'] = $this->request->post['price']/($this->request->post['mpn']?$this->request->post['mpn']:1);
    } elseif (!empty($product_info)) {
    	$data['price'] = $product_info['price'] / ($product_info['mpn']?$product_info['mpn']:1);
    } else {
    	$data['price'] = '';
    }

    Этим мы добавили отображения цены в поле цена за один квадратный метр. По админке все готово.

    При добавлении цены с количеством квадратов в упаковке идет автоматический подсчет и в базу пишется цена за упаковку то есть фактическая за конкретный товар.

    Далее будем редактировать фронт магазина для правильного отображения цены и количества кв. м. в заказе.

    Добавляем в карточку товара + и -

    Для этого открываем файл catalog/controller/product/product.php

    Находим строки:

    if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) {
    	$data['price'] = $this->currency->format($this->tax->calculate($product_info['price'], $product_info['tax_class_id'], $this->config->get('config_tax')));
    } else {
    	$data['price'] = false;
    }

    Меняем их на:

    if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) {
    	$data['price'] = $this->currency->format($this->tax->calculate($product_info['price'] / ($product_info['mpn']?$product_info['mpn']:1), $product_info['tax_class_id'], $this->config->get('config_tax')));
    } else {
    	$data['price'] = false;
    }

    Этим действием мы выводим цену за квадратный метр. Далее, после этих строк вставляем

    $data['in_box'] = $product_info['mpn'];
    $data['count_in_box'] = $product_info['isbn'];

    Этой переменной мы передаем количество квадратных метров в упаковке (in_box) и количество штук в упаковке (count_in_box) Далее открываем файл catalog/view/theme/default/template/product/product.tpl

    И добавляем плюс и минус возле поля количество, где мы будем выводить его в квадратных метрах. Также добавим скрытое поле quantity (которое учитывается при добавлении) для реального количества упаковок.

    В этом файле ищем код:

    <input type="text" name="quantity" value="<?php echo $minimum; ?>" size="2" id="input-quantity" class="form-control" />

    Меняем его на:

    <div class="col-sm-12 form-group">
      <div class="col-sm-3">
        <span data-type="q_minus" class="control-in-de btn btn-primary btn-block">-</span>
      </div>
      <div class="col-sm-6">
        <input type="text" name="quantity_in_box" value="<?php echo $minimum * ($in_box?$in_box:1); ?> кв.м. (<?php echo $minimum; ?> уп.)" size="2" id="input-quantity" class="form-control" />
        <input type="hidden" name="quantity" value="<?php echo $minimum; ?>" />
      </div>
      <div class="col-sm-3">
        <span data-type="q_plus" class="control-in-de btn btn-primary btn-block">+</span>
      </div>
    </div>

    Этим кодом мы добавили +/- и правильное отображение количества квадратных метров и упаковок. Отображение кнопок можно менять под свою тему или на свое усмотрение как будет удобно. В этом же файле находим:

    <?php echo $footer; ?>

    И перед этой строкой вставляем скрипты для оживления кнопок + и -

    <script>
    $('.control-in-de').click(function(){ 
    	if($(this).data('type') == 'q_minus'){
    	  if($('input[name="quantity"]').val() > '<?php echo $minimum; ?>'){
    		$('input[name="quantity"]').val(parseInt($('input[name="quantity"]').val())-1);
    	  }
    	}else{
    		$('input[name="quantity"]').val(parseInt($('input[name="quantity"]').val())+1);					
    	}
    	in_box = parseInt($('input[name="quantity"]').val())*<?php echo $in_box; ?>;
    	$('input[name="quantity_in_box"]').val(in_box.toFixed(2) + ' кв.м. (' + $('input[name="quantity"]').val() + ' уп.)');
    });
    </script>

    После этого у нас все хорошо отображается и в корзину добавляется в упаковках. Возле вывода цены, можно писать что это за 1 кв.м.
    calculate-square-metrs.jpg.6562631308c2c1fce8d9f97c488d580d.jpg

    Для вывода информации о количестве штук в упаковке добавьте в этом файле в удобном месте вывод
     

    Количество в упаковке <?php echo $count_in_box; ?> шт.

    Правильное отображение цены за квадратный метр в категории

    После всех изменений нам надо вывести цену за кв.м. в категории, для этого открываем файл catalog/controller/product/category.php

    И находим строку:
     

    $price = $this->currency->format($this->tax->calculate($result['price'], $result['tax_class_id'], $this->config->get('config_tax')));

    Меняем ее на:
     

    $price = $this->currency->format($this->tax->calculate($result['price'] / ($result['mpn']?$result['mpn']:1), $result['tax_class_id'], $this->config->get('config_tax')));

    По аналогии делаем вывод цены за кв.м. В других модулях, такие как новинки, скидки, хиты продаж и т. д.

    P.S. В Opencart 2 после всех изменений в коде магазина надо зайти в Модули  Модификаторы и нажать на кнопку Очистить и Обновить справа вверху.

  14. На данный момент форум пуст, но в течени времени он будет активно наполнятся нужной, полезной и в силу нынешних обстоятельств зачастую недоступен широкому кругу пользователей. 
    Будем стараться по максимуму и в течении короткого времени ликвидировать этот проблему.

  15. В силу сложившихся обстоятельств многим из нас был закрыт доступ на opencartforum.com, в связи с чем открывается данный форум для русскоязычного сегмента пользователей , разработчиков и всех желающих освоить данный движок, либо заказать разработку своего ресурса и пр. 
    Все мы мирные граждане разных стран и объединяет нас работа с CMS Opencart и ни как иначе. Мы против конфликтов по национальному признаку, по месту жительства и расовой принадлежности. 
    Будем так же рады видеть на нашем ресурсе и жителей Украины, у нас нет злости или предвзятости. 
    Мы - аполитичны. Если Вы согласны не нарушать элементарные нормы поведения и этики в общении с жителями других государств, мы с удовольствием примем Вас в наш круг единомышленников.
    Всем мира, здоровья и терпения. 

×
×
  • Создать...