SEO URL важная функциональная часть в программном обеспечении OpenCart, объяснять её востребованность нет смысла, достаточно вспомнить технологии SEO. Режим SEO-ссылок включается в панели администрирования в настройках магазина (закладка Сервер).
Вроде всё понятно, но есть одна проблема - это существенная нагрузка на базу данных! Это, пожалуй, самая затратная часть в плане расхода вычислительных ресурсов сервера. С ростом количества товаров и посетителей замедление в работе магазина становится настоящей проблемой! Можно, конечно, выбрать оборудование получше, но если вы собираетесь серьёзно заниматься онлайн-коммерцией, то в какой-то момент времени посмотрите на счета за услуги хостинга и удивитесь сумме ежемесячных платежей. Именно решением этой проблемы мы и занимаемся.
Чтобы понять, как работает режим SEO URL, необходимо разобрать алгоритм формирования и распознания таких ссылок. Весь процесс происходит в файле ./catalog/controller/common/seo_url.php.
По умолчанию система формирует ссылки в стандартном виде и только в режиме SEO URL они преобразуются функцией rewrite. Выглядит это следующим образом:
...
содержимое необходимо заменить на код ниже:
$queries = array();
foreach ($data as $key => $value) {
if (isset($data['route'])) {
if (($data['route'] == 'product/product' && $key == 'product_id') ||
(($data['route'] == 'product/manufacturer/info' ||
$data['route'] == 'product/product') && $key == 'manufacturer_id') ||
($data['route'] == 'information/information' && $key == 'information_id')) {
$queries[] = $key . '=' . (int)$value;
} elseif ($key == 'path') {
$categories = explode('_', $value);
foreach ($categories as $category) {
$queries[] = "category_id=" . (int)$category;
}
}
}
}
if (count($queries)) {
$cache = md5(http_build_query($queries));
$rows = $this->cache->get('url.alias.' . (int)$this->config->get('config_store_id') . $cache);
if (!$rows) {
$db_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "url_alias
WHERE `query` IN('" . implode("', '", $queries) . "')");
$rows = $db_query->rows;
$this->cache->set('url.alias.' . (int)$this->config->get('config_store_id') . $cache, $rows );
}
foreach ($queries as $query) {
foreach ($rows as $row) {
if($row['query'] == $query) {
$url .= '/' . $row['keyword'];
$query = explode('=', $query);
$key = array_shift($query);
$key = ($key=='category_id') ? 'path' : $key;
unset($data[$key]);
break;
}
}
}
}
Обратите внимание, что в эту функцию добавлено также кэширование запросов к базе данных, это уже комплексное решение, которое сводит влияние режима SEO URL на производительность сервера к существенному минимуму (вместо 30-100 запросов всего 5-10).
При использовании кеширования не забудьте его сбрасывать после изменения/создания категории, продукта, статьи или производителя. Для этого в модели этих объектов наравне с удалением собственного кэша добавьте строчку кода $this->cache->delete('url.alias');
Если у вас возникли трудности с освоением данной статьи, то всю работу по оптимизации вашего магазина мы готовы взять на себя.
Вроде всё понятно, но есть одна проблема - это существенная нагрузка на базу данных! Это, пожалуй, самая затратная часть в плане расхода вычислительных ресурсов сервера. С ростом количества товаров и посетителей замедление в работе магазина становится настоящей проблемой! Можно, конечно, выбрать оборудование получше, но если вы собираетесь серьёзно заниматься онлайн-коммерцией, то в какой-то момент времени посмотрите на счета за услуги хостинга и удивитесь сумме ежемесячных платежей. Именно решением этой проблемы мы и занимаемся.
Чтобы понять, как работает режим SEO URL, необходимо разобрать алгоритм формирования и распознания таких ссылок. Весь процесс происходит в файле ./catalog/controller/common/seo_url.php.
По умолчанию система формирует ссылки в стандартном виде и только в режиме SEO URL они преобразуются функцией rewrite. Выглядит это следующим образом:
- Контроллер формирует контент с сылками, которые форматируются в библиотеке ./system/library/url.php. Если режим SEO URL активен (см. config_seo_url), то после каждого форматирования ссылки она разбивается на составные части, которые сверяются с содержимым таблицы базы данных url_alias в поиске значения keyword. Это значение закрепляется пользователем при редактировании категории, продукта, статьи или производителя.
- При преходе пользователем по SEO-ссылке со страниц магазина или с результатов выдачи поисковой системы происходит обратное преобразование ссылки в стандартный формат. Она также разбивается на части (разделителем служит прямой слэш), которые сверяются с таблицой url_alias в поиске идентификаторов категории, продукта, статьи или производителя.
Независимо от того, присвоили ли вы ключевое слово (keyword) категории, продукту, статье или производителю, обращения к базе в этом режиме будут постоянны. Чем глубже ссылка и чем больше их количество, тем медленнее будет работать ваш магазин.
Последний момент усугубляется наличием циклов foreach, в котором для каждой части ссылки происходит обращение к базе данных. Логично было бы построить один запрос для всех частей ссылки:
Последний момент усугубляется наличием циклов foreach, в котором для каждой части ссылки происходит обращение к базе данных. Логично было бы построить один запрос для всех частей ссылки:
В файле seo_url.php часть содержимого функции index() после строки $parts = explode('/', rtrim($this->request->get['_route_'], '/')); и до
- if (isset($this->request->get['product_id'])) {
$this->request->get['route'] = 'product/product';
...
необходимо заменить на следующий код:
if (count($parts)) {
$parts = array_map(array($this->db, 'escape'), $parts);
$db_query = $this->db->query("
$parts = array_map(array($this->db, 'escape'), $parts);
$db_query = $this->db->query("
SELECT SUBSTRING_INDEX(query,'=',1) AS name,
CONVERT(SUBSTRING_INDEX(query,'=',-1),UNSIGNED INTEGER) AS value
FROM " . DB_PREFIX . "url_alias WHERE keyword IN('" . implode("','", $parts) . "') ORDER BY
FIND_IN_SET(keyword, '" . implode(",", $parts) . "')
");
foreach($db_query->rows as $row) {
if($row['name'] == 'category_id') {
if (!isset($this->request->get['path'])) {
$this->request->get['path'] = $row['value'];
} else {
$this->request->get['path'] .= '_' . $row['value'];
}
} else $this->request->get[$row['name']] = $row['value'];
}
} else $this->request->get['route'] = 'error/not_found';
}
}
В том же файле, но уже для функции rewrite() после строки parse_str($url_data['query'], $data); и до if ($url) {
unset($data['route']);...
содержимое необходимо заменить на код ниже:
$queries = array();
foreach ($data as $key => $value) {
if (isset($data['route'])) {
if (($data['route'] == 'product/product' && $key == 'product_id') ||
(($data['route'] == 'product/manufacturer/info' ||
$data['route'] == 'product/product') && $key == 'manufacturer_id') ||
($data['route'] == 'information/information' && $key == 'information_id')) {
$queries[] = $key . '=' . (int)$value;
} elseif ($key == 'path') {
$categories = explode('_', $value);
foreach ($categories as $category) {
$queries[] = "category_id=" . (int)$category;
}
}
}
}
if (count($queries)) {
$cache = md5(http_build_query($queries));
$rows = $this->cache->get('url.alias.' . (int)$this->config->get('config_store_id') . $cache);
if (!$rows) {
$db_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "url_alias
WHERE `query` IN('" . implode("', '", $queries) . "')");
$rows = $db_query->rows;
$this->cache->set('url.alias.' . (int)$this->config->get('config_store_id') . $cache, $rows );
}
foreach ($queries as $query) {
foreach ($rows as $row) {
if($row['query'] == $query) {
$url .= '/' . $row['keyword'];
$query = explode('=', $query);
$key = array_shift($query);
$key = ($key=='category_id') ? 'path' : $key;
unset($data[$key]);
break;
}
}
}
}
Обратите внимание, что в эту функцию добавлено также кэширование запросов к базе данных, это уже комплексное решение, которое сводит влияние режима SEO URL на производительность сервера к существенному минимуму (вместо 30-100 запросов всего 5-10).
При использовании кеширования не забудьте его сбрасывать после изменения/создания категории, продукта, статьи или производителя. Для этого в модели этих объектов наравне с удалением собственного кэша добавьте строчку кода $this->cache->delete('url.alias');
* * *
Дополнительное решение для тех, кто понимает насколько важным является наименование и переименование ссылок.
Всем известна пословица, как корабль назовешь, так он и поплывет. Это определение можно применить и к ссылкам. Речь идет не только о формате ссылок, но и об их звучании и зрительном восприятии. В первом случае это качественное ранжирование в поисковых системах, а во втором - реклама ресурса при обмене ссылками между пользователями, например, в социальных сетях.
Допустим в процессе наполнения каталогов товарами качеству ссылок не придавалось особого значения и магазин был проиндексирован поисковыми роботами в том виде в котором был наполнен. Спустя некоторое время пришло понимание того, что если бы ссылка на один из популярных товаров была названа по другому, например, к наименованию была бы добавлена модель продукта или ключевой атрибут, то трафик на страницу данного товара увеличился.
Если просто переименовать ссылку объекта в OpenCart, то по старому адресу страница окажется недоступной (404 Not Found), а это чревато потерей потенциальных клиентов и позиций в поисковой выдаче. Выходом из данной ситуации может стать редирект с кодом 301 на новый адрес страницы.
В данном решении используется история переименований объектов OpenCart в виде дополнительной таблицы url_alias_archive, представления url_alias_view, двух триггеров и одного события (event). В файл ./catalog/controller/common/seo_url.php вносятся небольшие коррективы. Заказать решение можно у автора статьи.
Если у вас возникли трудности с освоением данной статьи, то всю работу по оптимизации вашего магазина мы готовы взять на себя.
описанное здесть усовершенствование не работает. При включении ЧПУ выдает ошибку
ОтветитьУдалитьNotice: Error: Table 'open1551.url_alias' doesn't exist
Error No: 1146
SELECT SUBSTRING_INDEX(query,'=',1) AS name, CONVERT(SUBSTRING_INDEX(query,'=',-1),UNSIGNED INTEGER) AS value FROM `url_alias` WHERE keyword IN('desktops','pc') ORDER BY FIND_IN_SET(keyword, 'desktops,pc') in /home/htdocs/open1551.loc/system/database/mysql.php on line 50
И в 1.5.3.1 и в 1.5.5.1
Чтобы заработало в конструкцию запроса "FROM `url_alias` WHERE keyword IN" надо внести изменения "FROM `oc_url_alias` WHERE keyword IN" где ос_ префикс базы
УдалитьДа, действительно, в запросе пропущен префикс, исправлено!
УдалитьОбратите внимание, если будите кэшировать запросы в режиме SEO URL, то Вы должны быть уверены в производительности дисковой системы, т.к. при большом количестве товаров, количество файлов в кэше может привести к падению общей производительности.
ОтветитьУдалитьМожно ведь кешировать массив, в таком случае у нас будет 1 файл
УдалитьНе рекомендуется использовать один файл, может возникнуть очередь на чтение/запись. Также не забывайте, что на сереализацию и десериализацию данных затрачиваются ресурсы процессора.
УдалитьОтличная модификация стандартного seo_url, но вот проблема осталась - дубли как были - так и остались, а для СЕО - это один из важнейших приоритетных задач.
ОтветитьУдалитьЧто подразумевается под дублями? Если для одного товара отмечено несколько категорий, то разумеется будут дубли, но с разными абсолютными путями (для категорий).
УдалитьПо-хорошему нужно скопировать товар в каждую из категорий под новым каноническим именем и модифицировать содержимое и заголовок. Таким образом у одного и того же товара появится больше шансов на попадание в результаты поиска.
Вот Вашему вниманию сайт (на правах понимания о чем речь) www.fomka.com.ua, там я исправил сео_урл, с присвоение 1-й уникальной категории товару, отображение же в хитах, рекомендуемых, акциях, поиске, производителях - никак не влияет на URL страницы товара, он уникален на всю систему.
ОтветитьУдалитьХиты, акции, производители и прочие разделы закрываются в robots.txt
УдалитьХорошо, напишу по другому, товар "iPhone" - добавлен во все категории, и по всюду отображается, найдите 2-ве одинаковые ссылки на товар (ну и для поискового робота так же важен этот момент)
УдалитьТоесть сам фокус в том, что создается дополнительное поле в БД, под названием main_category_id, и туда вносится 1-н id выбранной в админке категории из списка всех отмеченных, а выдёргиваю для контроллера таким вот запросом:
ОтветитьУдалить______________________
$query = $this->db->query("SELECT pc.category_id pc_id, u.keyword, c.parent_id cc_id FROM " . DB_PREFIX . "product_to_category pc JOIN (" . DB_PREFIX . "url_alias u, " . DB_PREFIX . "category c) ON (u.`query` = CONCAT('category_id=', pc.category_id) AND c.category_id = pc.category_id) WHERE pc.main_category = 1 AND pc.product_id = " . (int)$data['product_id'] . ' LIMIT 1');
_______________________
Вот почитал пост, и задался вопросом, как сделать к моей модификации - кеширование или наоборот, к вашему кешированию - уникальность СЕО урла...
В OpenCart путь к товару может быть относительным и абсолютным.
ОтветитьУдалитьПример абсолютного пути:
http://www.domain.com/product_1.html
Пример относительного пути:
http://www.domain.com/category_1/product_1.html
http://www.domain.com/category_1/sub_category/product_1.html
http://www.domain.com/category_2/product_1.html
http://www.domain.com/manufacturer_1/product_1.html
Как видно, product_1.html продублирован в нескольких разделах, это нормально. Какую бы ссылку робот не открыл, он получит каноническое имя http://www.domain.com/product_1.html и поймёт, где постоянный адрес (абсолютный путь).
Если каноническое имя (rel="canonical") совпадает с сылкой, тогда это настоящие дубли, которые снижают вес страницы товара. В этом случае лишние разделы закрываются в robots.txt, а дубли переписываются через копирование под новым каноническим именем (SEO URL).
Разные адреса, которые ведут на один контент (в нашей теме - относительный путь) всегда будет плохо сказываться на SEO, по поводу rel="canonical", то в опенкарте (стандартном), с этим сложновато, особенно для наших поисковиков (СНГ), так что абсолютный путь - оптимальное решение в данном контексте (ИМХО).
ОтветитьУдалитьТогда используйте SEO URL Pro, там можно найти компромис. В любом случае, SEO не панацея, нужно работать над контентом!
УдалитьНа мой взгляд лучшее решение seo url тут:
ОтветитьУдалитьhttp://opencartforum.ru/topic/27002-процесс-работ-над-релизом-ocstore-15512/page-6#entry213622
И мультиязычность поддерживается (включая Ajax и iframe), и обращений к базе минимум, и кеширование полное одним файлом
Ajax, iFrame и мультиязычность не имеют к этому отношения, здесь упоминается кеширование канонических имен стандартной модели OpenCart, не более.
УдалитьКеширование SEO URL актуально, прежде всего, на хостинге с поддержкой SSD или когда БД находится на отдельном сервере.
Дополнительное решение для тех, кто понимает насколько важным является наименование и переименование ссылок (см. статью).
ОтветитьУдалитьУдалось практически полностью пересмотреть файл-контроллер SEO URL. Оптимизирован код и пересмотрен описанный выше алгоритм, что позволило увеличить производительность в среднем на 15%. При этом, кэширование не используется, и согласно последним тестам, только снижает скорость открытия страниц при большом количестве товаров. Не забывайте, что к базе данных применимы свои методы оптимизации.
ОтветитьУдалитьКонтроллер, как и саму оптимизацию ПО OpenCart, можно заказать у автора блога.
Подойдет ли акое решение для файла сео_про или там не возникает подобных проблем?
ОтветитьУдалитьНет, это решение для стандартного контроллера ПО OpenCart. В SEO URL Pro есть аналогичные проблемы (в зависимости от версий), но они здесь не рассматриваются.
Удалить)))) эх, обычно сайт грузился 3 сек, сделал все по статье, начал по 40-50 сек грузить страницы
ОтветитьУдалитьЭто решение не предназначено для последних версий OpenCart или для его клонов (любых версий), только немодифицированный OpenCart 1.5+.
УдалитьЭтот комментарий был удален автором.
ОтветитьУдалитьПодскажите, не могу нигде найти информацию: где в opencart изменить в коде все абсолютные ссылки на относительные. Например, чтобы ссылки формировались не так: http://site.com.ua/categoty/ а так: //site.com.ua/categoty/ или так: /categoty/ ? Нужно для переезда на https
ОтветитьУдалитьЗдравствуйте! Базовые адреса для ссылок задаются в файле config.php, там же можно убрать протокол из ссылки или заменить HTTP на HTTPS.
УдалитьБлагодарю!
УдалитьДаже не ожидал такой быстрый ответ!)
На оф. форуме ответа не дождешься никогда... Все сильно гордые, чтобы помочь.
Как сделаю - отпишусь о результатах)
Спасибо огромное!
ОтветитьУдалитьВы мне очень помогли! Сам бы 100 лет искал.
Все получилось!) Исправил в корневой директории файла config.php 3-ю строку, убрав из нее домен. Для http версии работает, на https по ходу еще нужно будет то же самое подправить на 6-й строке, что начинается с define('https... =)
Пожалуйста!
УдалитьЯ попробовал внести правки в этот файл на свежеустановленный движок, но при включенном ЧПУ появляются ошибки, ссылаясь на 156 и 221 строку файла /catalog/controller/common/seo_pro.php
УдалитьКак только отключаешь - все ок. Но урлы не ЧПУ. Не подскажите в чем может быть дело?
seo_pro.php не является стандартным контроллером OpenCart. В этом файле обрабатывается протокол ссылки, поэтому и возникают ошибки.
УдалитьСпасибо, буду думать в этом направлении...
Удалить