Оценок: 1
551
Стикер для товаров Opencart - новинка, рекомендуемый, популярный

Стикеры для товаров: новинка, рекомендуемый, популярный

Здесь расскажу как добавить выбор дополнительного статуса (стикера) для товара в админке (в списке и в карточке) и вывести этот статус на сайт. Понадобится добавить одно поле в базу данных (БД), внести правки в файлы. Способ, который здесь описан, вероятно самый легкий с точки зрения нагрузки, но всего возможно не более 9 вариантов стикеров (в большинстве случаев их и столько не нужно).

Для начала в админке сделаю вывод в форму и список товаров, с возможностью сортировки, выведу на сайт. Затем сделаю управление не только через форму товара, но и через checkbox-ы в списке товаров.

Статусы (стикеры) которые буду добавлять:

  • 1 - Новый
  • 2 - Популярный
  • 3 - Рекомендуем

Позже сможете свой список сделать, не сложно.

Шаг 1. БД

Первое что нужно сделать - добавить поле в БД. Начинаем с этого, т.к. если поля не будет к моменту обращения к нему, будет ошибка. Поле нужно только одно, вариантов статуса может быть сколько угодно, отличаться будут цифрой. Соответственно, добавляем в таблицу oc_product (вместо oc_ может быть любой другой префикс) следующее поле:

Добавляем поле в БД

Поле будет такое:

  • Имя: sticker
  • Тип: INT
  • Длина: 11
  • По умолчанию: 0 (как определено) - для всех "обычных" товаров

Добавляем поле в БД - параметры

Поле добавлено, в БД больше ничего не нужно, идем дальше. Теперь выводим поле в админке + предусматриваем, что будет сортировка и фильтрация по этому полю (правки model - controller - view). Ничего сложного, но долго и скучно (интереснее будет позже), можно копировать существуюшие части кода и менять на свое. Начнем.

Шаг 2. Admin. Model.

Открываем admin/model/catalog/product.php. Здесь ищем по "status", почти везде где находим, добавляем аналогично "sticker":

Находим (в двух местах)

, status = '" . (int)$data['status'] . "'

Меняем (добавляем):

, status = '" . (int)$data['status'] . "', sticker = '" . (int)implode('', $data['sticker']) . "'

Здесь поясню. Из формы статусы приходят в виде массива, а в базу нужно записать число, соответственно преобразуем и записываем. Затем, при выводе, нужно будет это число "расчленить" на цифры и преобразовать в массив.
Идем дальше и находим (так же 2 раза):

if (isset($data['filter_status']) && !is_null($data['filter_status'])) {
	$sql .= " AND p.status = '" . (int)$data['filter_status'] . "'";
}

Ниже добавляем (здесь есть небольшое отличие):

if (isset($data['filter_sticker']) && !is_null($data['filter_sticker'])) {
	$sql .= " AND p.sticker LIKE '%" . (int)$data['filter_sticker'] . "%'";
}

Это нужно для сортировки по стикеру. Т.к. в поле несколько цифр, добавлен "%"

Далее находим:

$sort_data = array(
	'pd.name',
	'p.model',
	'p.price',
	'p.quantity',
	'p.status',
	'p.sort_order'
);

И внутрь добавляем (для сортировки, хотя польза от нее в данном случае сомнительна):

	'p.sticker',

Здесь пока все. Переходим в контроллер и действуем по тому же принципу.

Шаг 3. Admin. Controller.

Файл admin/controller/catalog/product.php. Находим (8 совпадений):

if (isset($this->request->get['filter_status'])) {
	$url .= '&filter_status=' . $this->request->get['filter_status'];
}

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

if (isset($this->request->get['filter_sticker'])) {
	$url .= '&filter_sticker=' . $this->request->get['filter_sticker'];
}

Находим:

if (isset($this->request->get['filter_status'])) {
	$filter_status = $this->request->get['filter_status'];
} else {
	$filter_status = null;
}

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

if (isset($this->request->get['filter_sticker'])) {
	$filter_sticker = $this->request->get['filter_sticker'];
} else {
	$filter_sticker = null;
}

Находим в $filter_data :

'filter_status'   => $filter_status,

И после добавляем:

'filter_sticker'   => $filter_sticker,

В массив $data['products'][] добавляем (строка 390-какаято, это вывод отдельного товара в таблицу):

'sticker'   => str_split($result['sticker']),

Находим:

$data['sort_status'] = $this->url->link('catalog/product', 'token=' . $this->session->data['token'] . '&sort=p.status' . $url, true);

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

$data['sort_sticker'] = $this->url->link('catalog/product', 'token=' . $this->session->data['token'] . '&sort=p.sticker' . $url, true);

Находим:

$data['filter_status'] = $filter_status;

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

$data['filter_sticker'] = $filter_sticker;

Ранее были беспорядочные правки, в основном для списка и формы сразу (одни и те же замены), следующее выводит поле в форму. Находим:

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

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

if (isset($this->request->post['sticker'])) {
	$data['sticker'] = $this->request->post['sticker'];
} elseif (!empty($product_info)) {
	$data['sticker'] = str_split($product_info['sticker']);//число в массив
} else {
	$data['sticker'] = array();
}

Шаг 4. Admin. View.

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

admin/view/template/catalog/product_form.tpl

Находим:

	<div class="form-group">
		<label class="col-sm-2 control-label" for="input-status"><?php echo $entry_status; ?></label>
		<div class="col-sm-10">
			<select name="status" id="input-status" class="form-control">
				<?php if ($status) { ?>
					<option value="1" selected="selected"><?php echo $text_enabled; ?></option>
					<option value="0"><?php echo $text_disabled; ?></option>
				<?php } else { ?>
					<option value="1"><?php echo $text_enabled; ?></option>
					<option value="0" selected="selected"><?php echo $text_disabled; ?></option>
				<?php } ?>
			</select>
		</div>
	</div>

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

	<div class="form-group">
		<label class="col-sm-2 control-label" for="input-sticker">Стикер</label>
		<div class="col-sm-10 checkbox">
			<input type="hidden" name="sticker[]" value="" checked />
			<label><input type="checkbox" name="sticker[]" value="1" <?php if (in_array(1,$sticker)) { echo 'checked'; } ?> /> Новый</label>, 
			<label><input type="checkbox" name="sticker[]" value="2" <?php if (in_array(2,$sticker)) { echo 'checked'; } ?> /> Популярный</label>, 
			<label><input type="checkbox" name="sticker[]" value="3" <?php if (in_array(3,$sticker)) { echo 'checked'; } ?> /> Рекомендуем</label>
		</div>
	</div>

Здесь уже можно зайти в форму товара и проверить. Теперь список.

admin/view/template/catalog/product_list.tpl

Находим:

	<div class="form-group">
		<label class="control-label" for="input-model"><?php echo $entry_model; ?></label>
		<input type="text" name="filter_model" value="<?php echo $filter_model; ?>" placeholder="<?php echo $entry_model; ?>" id="input-model" class="form-control" />
	</div>

Добавляем:

	<div class="form-group">
		<label class="control-label" for="input-sticker">Стикер</label>
		<select name="filter_sticker" id="input-sticker" class="form-control">
			<option value="*"></option>
			<option value="1" <?php if ($filter_sticker == '0') { echo 'selected="selected"'; } ?>>Нет</option>
			<option value="1" <?php if ($filter_sticker == '1') { echo 'selected="selected"'; } ?>>Новый</option>
			<option value="2" <?php if ($filter_sticker == '2') { echo 'selected="selected"'; } ?>>Популярный</option>
			<option value="3" <?php if ($filter_sticker == '3') { echo 'selected="selected"'; } ?>>Рекомендуем</option>
		</select>
	</div>

Находим:

<td class="text-left"><?php if ($sort == 'p.status') { ?>
	<a href="<?php echo $sort_status; ?>" class="<?php echo strtolower($order); ?>"><?php echo $column_status; ?></a>
<?php } else { ?>
	<a href="<?php echo $sort_status; ?>"><?php echo $column_status; ?></a>
<?php } ?></td>

Добавляем:

	<td class="text-left"><?php if ($sort == 'p.sticker') { ?>
		<a href="<?php echo $sort_sticker; ?>" class="<?php echo strtolower($order); ?>">Стикер</a>
	<?php } else { ?>
		<a href="<?php echo $sort_sticker; ?>">Стикер</a>
	<?php } ?></td>

Находим:

<td class="text-left"><?php echo $product['status']; ?></td>

Добавляем после:

<td class="text-left">
	<?php $i=0; foreach ($product['sticker'] as $sticker) { $i++; ?>
		<?php if ($i > 1) { echo '<br />'; } ?>
		<?php if ($sticker == 1) { ?>Новый
		<?php } else if ($sticker == 2) { ?>Популярный
		<?php } else if ($sticker == 3) { ?>Рекомендуем<?php } ?>
	<?php } ?>
</td>

Находим (ниже, в скриптах):

	var filter_status = $('select[name=\'filter_status\']').val();

	if (filter_status != '*') {
		url += '&filter_status=' + encodeURIComponent(filter_status);
	}

Добавляем:

  var filter_sticker = $('select[name=\'filter_sticker\']').val();
	if (filter_sticker != '*') {
		url += '&filter_sticker=' + encodeURIComponent(filter_sticker);
	}

На этом в админке добавлено, далее вывод на сайт

Шаг 5. Frontend.

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

1. Catalog. Model. - catalog/model/catalog/product.php

В самом начале, где выводятся все поля товара, добавим sticker (здесь покажу только часть кода, нет смысла копировать все):

				'minimum'          => $query->row['minimum'],
				'sort_order'       => $query->row['sort_order'],
				'status'           => $query->row['status'],
				'date_added'       => $query->row['date_added'],

Здесь, например после status:

'sticker'           => $query->row['sticker'] ? str_split($query->row['sticker']) : array(),

Здесь добавил проверку, что бы исключить "0" и сразу преобразовал в массив. И идем дальше, к контроллеру

2. Catalog. Controller. Здесь будет два примера - для контроллера отдельного товара и для контроллеров со списком товаров, вторых много, но все аналогично.

2.1. Отдельный товар. catalog/controller/product/product.php

После:

$data['model'] = $product_info['model'];

Добавим (всего одна строка, остальное в шаблоне):

$data['sticker'] = $product_info['sticker'];

2.2. Список товаров. На примере категории, аналогично в модулях, рекомендуемые в контроллере товара, поиск и т.д. catalog/controller/product/category.php

Здесь находим массив:

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

Внутри этого массива добавим (например, после 'rating' => $result['rating'],):

'sticker'      => $result['sticker'],

Далее вывод в шаблон, опять же, для двух вариантов

3. Catalog. View.

3.1. Отдельный товар. catalog/view/theme/default/template/product/product.tpl

В любом удобном месте:

<?php if ($sticker) { ?><div class="stickers">
	<?php $name = 'NONAME'; foreach ($sticker as $item) { if ($item == 1) { $name = 'Новый'; } else if ($item == 2) { $name = 'Популярный'; } else if ($item == 3) { $name = 'Рекомендуем'; } ?>
		<span class="sticker sticker-<?php echo $item; ?>"><?php echo $name; ?></span>
	<?php } ?>
</div><?php } ?>

$name = 'NONAME' - добавлено на всякий случай. Если вдруг добавили новый вариант стикера и не везде прописали.

3.2. Шаблон списка товаров. catalog/view/theme/default/template/product/category.tpl

Где то после:

<?php foreach ($products as $product) { ?>

Вставляем:

<?php if ($product['sticker']) { ?><div class="stickers">
	<?php $name = 'NONAME'; foreach ($product['sticker'] as $item) { if ($item == 1) { $name = 'Новый'; } else if ($item == 2) { $name = 'Популярный'; } else if ($item == 3) { $name = 'Рекомендуем'; } ?>
		<span class="sticker sticker-<?php echo $item; ?>"><?php echo $name; ?></span>
	<?php } ?>
</div><?php } ?>

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

Шаг 6. Admin. Смена стикера в списке товаров (Ajax).

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

1. admin/view/template/catalog/product_list.tpl - здесь находим в таблице вывод текущего стикера. Вот этот код:

				<td class="text-left">
					<?php $i=0; foreach ($product['sticker'] as $sticker) { $i++; ?>
						<?php if ($i > 1) { echo '<br />'; } ?>
						<?php if ($sticker == 1) { ?>Новый
						<?php } else if ($sticker == 2) { ?>Популярный
						<?php } else if ($sticker == 3) { ?>Рекомендуем<?php } ?>
					<?php } ?>
				</td>

Его нужно изменить. Будет список checkbox, как и в форме. Меняем:

<td id="change-sticker-<?php echo $product['product_id']; ?>" class="text-left form-group change-sticker-td" data-id="<?php echo $product['product_id']; ?>">
	<input type="checkbox" name="change_sticker[]" value="1" <?php if (in_array(1,$product['sticker'])) { echo 'checked'; } ?> /> Новый<br />
	<input type="checkbox" name="change_sticker[]" value="2" <?php if (in_array(2,$product['sticker'])) { echo 'checked'; } ?> /> Популярный<br />
	<input type="checkbox" name="change_sticker[]" value="3" <?php if (in_array(3,$product['sticker'])) { echo 'checked'; } ?> /> Рекомендуем
</td>

Атрибут data-id у td нужен что бы узнать для какого товара делать изменение. Теперь напишем ajax запрос к функции в контроллере (которую чуть позже добавим). Перед <?php echo $footer; ?>:

<script>
$('.change-sticker-td input').on('click', function() {
	var sticker = '';
	$(this).parent().find('input[type=\'checkbox\']:checked').each(function(){
		sticker = sticker+$(this).val();
	});
	var product_id = $(this).parent().data('id');
	$.ajax({
		url: 'index.php?route=catalog/product/changeSticker&token=<?php echo $token; ?>',
		type: 'get',
		data: {product_id:product_id,sticker:sticker},
		dataType: 'html',
		success: function(html) {
			if(html != ''){       
				$('#change-sticker-'+product_id).addClass('ok');
			} else {
				$('#change-sticker-'+product_id).addClass('error');
			}
		}
	});
});
</script>

Теперь нужно добавить функцию changeSticker в контроллер

2. admin/controller/catalog/product.php здесь находим:

public function autocomplete() {

Перед этой добавляем нашу функцию

	public function changeSticker() {
		$this->load->model('catalog/product');
		$output='';
		if(isset($this->request->get['product_id']) && isset($this->request->get['sticker'])){
			$product_id = (int)$this->request->get['product_id'];
			$sticker = (int)$this->request->get['sticker'];
			$output = $this->model_catalog_product->changeSticker($product_id, $sticker);
		}
		$this->response->setOutput($output);
	}

Из контроллера есть обращение к функции в модели. Значит теперь нужно прописать функцию и туда. последний шаг, на котором запишем новый стикер в БД

3. admin/model/catalog/product.php здесь находим:

public function getTotalProductsByLayoutId($layout_id) {

Перед найденной добавляем:

	public function changeSticker($product_id, $sticker){
		if ($this->user->hasPermission('modify', 'catalog/product')) {
			$this->db->query("UPDATE " . DB_PREFIX . "product SET sticker = '" . (int)$sticker . "' WHERE product_id = '" . (int)$product_id . "'");
			return 'ok';
		}
	}

На этом все!!! Ocmod будет (уже жалею, что сразу не сделал), но позже

Оценок: 1

Комментарии (15)

  1. Классный мануал, спасибо!
    А случайно нету у вас образца вывода под twig? Никак не соображу, как там прицепить

    Настя 04 января 2024, 10:34 0
    • Вопрос, а если надо прикрепить к одному товару не один стикер, а все три, то как сделать?

      Алекс 22 сентября 2021, 08:48 0
      • Обычно в таких случаях делают несколько полей, вполне можно так и сделать. Здесь добавлено одно поле, по тому же принципу еще два добавить, только в каждом вместо списка стикеров — да/нет (1/0).
        Еще как вариант (мне больше нравится, т.к. меньше полей в базе, да и кода поменьше), к текущим вариантам добавить "+":
        1 — Новый
        2 — Популярный
        3 — Рекомендуем
        4 — Новый+популярный
        5 — новый+рекомендуем
        6 — популярный+рекомендуем
        ___
        только в шаблоне нужно будет сделать проверку, если <4 выводить 1 span, если больше, то 2. Можно с одним классом, а в CSS обращаться к .sticker-3 и .sticker-3+span (например)

        Владимир 22 сентября 2021, 09:29 0
        • Можно сделать просто чекбоксами?

          Алекс 22 сентября 2021, 10:28 0
          • Вообще то можно. Даже без увеличения количества полей, запросов… мысль хорошая, только мне придется много переписать (или даже отдельно написать) :(

            Владимир 22 сентября 2021, 10:44 0
            • Ждать? )

              Алекс 22 сентября 2021, 12:31 0
              • Да, думаю есть смысл, переделаю (тот вариант лучше). Опять же, ближе к ночи

                Владимир 22 сентября 2021, 13:00 0
                • напишите тогда тут ) Буду мониторить фидбэк )

                  Алекс 22 сентября 2021, 13:19 0
                  • Переписал. Пробуйте.

                    Владимир 22 сентября 2021, 22:23 0
                    • Не выводит стикеры на сайте, пишет ошибку:

                      Показать код
                      Notice: Undefined variable: name in /Users/aleksandrosin/Sites/alco/catalog/view/theme/emarket/template/product/product.tpl on line 17
                      
                      Вот такие ошибки в админ:
                      yadi.sk/d/hV3ITF1kIQvLMA

                      Алекс 23 сентября 2021, 05:28 0
                      • А в списке товаров такая:

                        Показать код
                        Notice: Undefined variable: name in /Users/aleksandrosin/Sites/alco/system/storage/modification/catalog/view/theme/emarket/template/product/category.tpl on line 117
                        

                        Алекс 23 сентября 2021, 05:29 0
                        • Ищите ошибки. Что то где то не добавили. или не туда. Не видя файлов (с изменениями) ничем не помогу. Можете прислать на vl@onenv.ru, посмотрю

                          Владимир 23 сентября 2021, 07:10 0
                          • ответил на почту

                            Алекс 23 сентября 2021, 11:19 +1
                            • Благодарю еще раз за модуль
                              поощрил )

                              Алекс 19 октября 2021, 13:05 0
                              • Спасибо!

                                Владимир 19 октября 2021, 13:59 0
                Надежный хостинг VPS серверов
                • Свои ISO образы
                • VDS с оплатой раз и навсегда
                • Аренда VDS на любой срок, с оплатой по дням
                • Большое разнообразие конфигураций
                • Дата-центры в ЕС и России
                + скидка 10%