Как сделать ЧПУ товара и категории без вложенности но с полными хлебными крошками

категория: , Дорабатываем, Полезности


Опубликовано: 06.01.2018 Просмотров: 1607 Комментарии: 20


Как сделать ЧПУ товара и категории без вложенности но с полными хлебными крошками

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


Из коробки 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']));

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


Комментарии:


Фото комментатора

София 11.01.2018

Здравствуйте, Спасибо за статью. Сделала, как вы написали. После замены строчки на $parts = explode('_', $this->getPathByCategory($this->request->get['path'])); выдает ошибку. И в какое место файла контроллера категории вставлять кусок кода?
Администратор

Ответ for-opencart.com 11.01.2018

София, статья расчитана на более подготовленный уровень, для работы с файлами магазина. Там где в sopro - вместе с этой foreach ($categories as $category) { все 3 строки надо заменять. В контроллере категории код private function getPathByCategory($category_id) { можем вставить перед function index(){ или перед последней "}" в файле catalog/controller/product/category.php Далее по замене строки - находите как в статье строку и заменяете на нужную - там она только в одном месте.
Фото комментатора

София 11.02.2018

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

Ответ for-opencart.com 11.02.2018

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

Дмитрий 18.02.2018

Замечательная статья, то что я искал, только ничего не получается, посмотрите пожалуйста, что не так в seopro: foreach ($data as $key => $value) { switch ($key) { case 'product_id': case 'manufacturer_id': case 'category_id': case 'information_id': case 'order_id': $queries[] = $key . '=' . $value; unset($data[$key]); $postfix = 1; break; case 'path': $categories = explode('_', $value); $queries[] = 'category_id=' . end($categories); break; } } В category.php вставил метод так: <?php class ControllerProductCategory extends Controller { 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]; } public function index() { Здесь же заменил строчку получилось так: $path = ''; $parts = explode('_', $this->getPathByCategory($this->request->get['path'])); $category_id = (int)array_pop($parts); Сылки не изменились хлебные крошки тоже, Помогите пожалуйста разобраться
Администратор

Ответ for-opencart.com 18.02.2018

Все сделано верно, почистите кеш модификаторов. Должно работать.
Фото комментатора

Александр 20.02.2018

Спасибо, все получилось. Единственное не сразу понял, что нужно все 3 строки foreach ($categories as $category) { $queries[] = 'category_id=' . $category; } заменить полностью на $queries[] = 'category_id=' . end($categories);
Администратор

Ответ for-opencart.com 20.02.2018

Все верно.
Фото комментатора

Дмитрий 22.02.2018

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

Ответ for-opencart.com 22.02.2018

И Вам спасибо! :)
Фото комментатора

invites 28.02.2018

Спасибо за такой полезный мануал! Для категорий все прекрасно работает, второй уровень вложенности и полный путь по хлебным крошкам. А как реализовать полный путь по хлебным крошкам для товаров?
Администратор

Ответ for-opencart.com 28.02.2018

Аналогично как и для категорий просто берет из seopro функцию полного пути до товара.
Фото комментатора

invites 28.02.2018

Скиньте на почту мануал как реализовать. Спасибо. Я пробую сделать сам, но вывод хлебных крошек не изменяется. В файле product.php вставляю функцию полного пути до товара (private function getPathByProduct) и в этом же файле меняю строку аналогично как для категорий ($parts = explode).
Администратор

Ответ for-opencart.com 28.02.2018

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

invites 28.02.2018

Добавьте пожалуйста мануал по выводу полных хлебных крошек для товаров. Спасибо!
Администратор

Ответ for-opencart.com 28.02.2018

Да, я добавлю, но немного позже т.к. сейчас очень загружен.
Фото комментатора

invites 28.02.2018

Кеш, да, чищу. После добавления функции полного пути до товара, в файле product.php найти и заменить $parts = explode('_', (string)$this->request->get['path']); на $parts = explode('_', $this->getPathByProduct($this->request->get['path'])); Верно? Версия ocStore 2.3.x.x "ЧПУ товаров с категориями: Нет"
Администратор

Ответ for-opencart.com 28.02.2018

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

invites 28.02.2018

Категория задана конечная. Незнаю как посмотреть что отдает функция getPathByProduct
Администратор

Ответ for-opencart.com 28.02.2018

например $this->log->write($this->getPathByProduct($product_id)); и посмотрите в логе что отдает. Должно давать 12_453_345 то есть полный перечень id категорий для хлебных. Еще есть подозрение что код не туда вставляете, должно работать как часы.
Фото комментатора

invites 28.02.2018

А где смотреть лог?
Администратор

Ответ for-opencart.com 28.02.2018

Не, ну Вы смеетесь?) Лог ошибок в опенкарт. Система - Инструменты - Лог ошибок. Если Вы беретесь за правки в коде, Вы должны понимать как делать отладку если что-то не работает, я же не могу все показать и рассказать, пробуйте раз решили самостоятельно.
Фото комментатора

invites 28.02.2018

Я смотрел журнал ошибок, там пусто. Поэтому уточнил. Код вставляю в конце файла, но в середине class ControllerProductProduct extends Controller. https://i.imgur.com/xapS73f.jpg https://i.imgur.com/V9pAHy8.jpg
Администратор

Ответ for-opencart.com 28.02.2018

Там где идет $this->getPathByProduct надо указать не $this->request->get['path'] а $product_id. Вы же сейчас делаете выборку не по id товара а по категории - а это же фундаментально неправильно. В Функцию надо передавать исключительно $product_id
Фото комментатора

invites 28.02.2018

Сделал. Но не работает. Крошки по прежнему отображаются без категории (Главная > Товар) Кеш чистил, в логе ошибок пусто. Для категорий работает четко, для товаров не работает и все тут. https://i.imgur.com/fGCyX4B.jpg
Администратор

Ответ for-opencart.com 28.02.2018

Поставьте вместо $product_id вот это $this->request->get['product_id'] Переменная $product_id = объявлена ниже по коду.
Фото комментатора

invites 28.02.2018

Спасибо, но не работает. Я попробовал и $this->request->get['product_id'] и переместить код вверх и использовать $product_id, не работает. https://i.imgur.com/Ki4LCbT.jpg
Администратор

Ответ for-opencart.com 28.02.2018

Тогда по скринам ничего не могу сказать надо смотреть, где-то что-то не то.
Фото комментатора

Петр 12.04.2018

Доброго времени суток. Огромное спасибо за очень полезную статью, все получилось сделать. Есть вопрос, при включенном сео про, встроенный в ОС модуль категорий (extension\module\category), который выводит список категорий для навигации, при переходе по ссылкам второго уровня, саму страницу категорий открывает но в списке встроенного модуля возвращает на первоначальный список, соответственно дальнейшая навигация возможна только на странице категорий, а в меню категорий остается первоначальный список. Подскажите пожалуйста, как сделать чтобы следовало вложенности и в меню категорий, а не возвращало на первоначальный список или хотя бы направьте в какой стороне кода смотреть. Спасибо.
Администратор

Ответ for-opencart.com 12.04.2018

Добрый день! Посмотрите как сделаны хлебные крошки в категории. Там мы методом из сеопро берем всю цепочку из категорий что бы сформировать полные хлебные крошки. Так вот этот подход можно внедрить в модуле Категории. Просто там строку $parts = explode('_', (string)$this->request->get['path']); меняем на $parts = explode('_', $this->getPathByCategory($this->request->get['path']));
Фото комментатора

Максим 24.05.2018

Спасибо за статью! Все получилось! А не поможете разобраться еще с такой проблемой: Сейчас у меня ссылки такого вида: site.ru/cat1 site.ru/cat2 site.ru/tov1 site.ru/tov2 А хочу сделать так: site.ru/category/cat1 site.ru/category/cat2 site.ru/product/tov1 site.ru/product/tov2 Это нужно чтоб сохранить ссылки при переносе с другого движка. Очень буду благодарен если поможете! Еще раз спасибо!
Администратор

Ответ for-opencart.com 24.05.2018

Ну проще чем изменять структуру ЧПУ в магазине сделать 301 редирект. Например если в ссылке есть category/ или product/ то это вырезаем и редиректим 301-м просто на cat.. или tov..
Фото комментатора

Николай 10.07.2018

Спасибо. Все вышло и работает. Вопрос, а можно ли модифицировать как-то код, где мы получаем последний элемент из урл так, чтобы он убирал только те урл, что вложенностью больше 3х. например сайт/категория - оставляем сайт/категория/подкатегория - тоже оставлял а вот уже сайт/категория/подкатегория/совсемподкатегория переводил в сай/категория/совсемподкатегория. т.е. работал бы как и текущий код, только вместе с end($categories) перед этим еще и первый элемент массива вызывал как-то ?
Администратор

Ответ for-opencart.com 10.07.2018

Смотрите в сторону count($this->getPathByCategory($this->request->get['path']))
Фото комментатора

Сергей 19.07.2018

Супер! Вот это действительно полезно. Спасибо!
Фото комментатора

Володя 31.07.2018

А для версии ocStore 2.3.0.2.3 т.к. у меня файлик называется seo_pro и строчка по другому выходит: $this->cache_data = $this->cache->get('seo_proforeach ($categories as $category) { $queries[] = 'category_id=' . $category; } Можно сделать?
Администратор

Ответ for-opencart.com 31.07.2018

Не понятные строки в SEOPRO Смотрите по аналогии, тяжело понять по куску кода.
Фото комментатора

Владимир 01.08.2018

В том то и дело что аналогии нету. Файлик у меня называется seo_pro.php Его содержимое указал в том месте где есть совпадение с тем что описано в статье ... помогите пжлст. https://drive.google.com/file/d/1Zyv5WFlKDPY5WbyvFk0G5l6GCAaQMqaw/view?usp=sharing

Быстрый поиск

Новое на сайте