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

Дубли страниц категорий. Модуль SeoPro

Рекомендуемые сообщения

Доброго времени всем!

При сканировании магазина прогой Xenu обнаружилось ряд страниц, многое дублирующее. Большинство проблем устранил через настройки в админке и в robots/.htaccess Но есть страницы, дублирующие категории. Причём самым наглым образом - в конец ссылки категории ставим alias бренда(производителя) и получаем дубль страницы категории любой. Как пример: 

вот тут структура ссылок, когда всё нормально - 

myshop.com/category -  основная категория

myshop.com/category/podcat/ - адрес подкатегории 

 

а вот дубли тех же самых страниц что выше, но с приставкой в конце урла алиаса на бренд(производитель) - 
 

myshop.com/category/brand -  основная категория дубль 

myshop.com/category/podcat/brand  - адрес подкатегории дубль

Т.е. не важно какая категория, не важно какой в конец урла ставить алиас имеющего на сайте бренда, но получается 100500 комбинаций, если подставлять ко всем категориям все бренды по очереди. Здесь однозначно что-то надо изменить в файле seo_pro.php, но каких-либо решений или подсказок  в сети не нашёл

Изменено пользователем andrus

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

подсказка:

isset($this->request->get['manufacturer_id'])

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

подсказка:

isset($this->request->get['manufacturer_id'])

Благодарю за наводку, но не без вопроса тут же: "Удалить это место из кода, или изменить код исполнения условия? Если да, то какое нужно прописать .." 

___________________________________

........................

} elseif (isset($this->request->get['path'])) {
$this->request->get['route'] = 'product/category';
} elseif (isset($this->request->get['manufacturer_id'])) {
$this->request->get['route'] = 'product/manufacturer/info';
} elseif (isset($this->request->get['information_id'])) {
$this->request->get['route'] = 'information/information';
} elseif(isset($this->cache_data['queries'][$route_])) {
header($this->request->server['SERVER_PROTOCOL'] . ' 301 Moved Permanently');
$this->response->redirect($this->cache_data['queries'][$route_]);

..........................

_________________________________________

Изменено пользователем andrus

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Otvet, совершенно верно ,что сложнее будет сделать. Покопался уже полдня, чего только не придумывал.. в итоге не достиг желаемого.
Пока пауза, так как времени нет вообще, во многом не успеваю. А когда тебе особо не понять что там и куда в этом файле "seo_pro.php" заворачивает, генерирует.. то тем более.

Просто собственно вопрос к заглянувшим сюда в тему -  "У вас также как описано выше? Что если приставить алиас бренда к любой категории или подкатегории, то получишь ссылку на эту же категорию, но с новым "урл" ?" Магазину уже как год, а я вот только на днях заметил подобный дуль, родом вообще из ниоткуда. :/ 

Изменено пользователем andrus

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не смог разобраться со своею проблемой. Сам код этого файла "seo_pro.php" прикрепляю ниже. Что там и как редиректит с помощью 301, так и осталось неизвестным... :/ 

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

<?php
class ControllerCommonSeoPro extends Controller {
	private $cache_data = null;

	public function __construct($registry) {
		parent::__construct($registry);
		$this->cache_data = $this->cache->get('seo_pro');
		if (!$this->cache_data) {
			$query = $this->db->query("SELECT LOWER(`keyword`) as 'keyword', `query` FROM " . DB_PREFIX . "url_alias ORDER BY url_alias_id");
			$this->cache_data = array();
			foreach ($query->rows as $row) {
				if (isset($this->cache_data['keywords'][$row['keyword']])){
					$this->cache_data['keywords'][$row['query']] = $this->cache_data['keywords'][$row['keyword']];
					continue;
				}
				$this->cache_data['keywords'][$row['keyword']] = $row['query'];
				$this->cache_data['queries'][$row['query']] = $row['keyword'];
			}
			$this->cache->set('seo_pro', $this->cache_data);
		}
	}

	public function index() {

		// Add rewrite to url class
		if ($this->config->get('config_seo_url')) {
			$this->url->addRewrite($this);
		} else {
			return;
		}

		// Decode URL
		if (!isset($this->request->get['_route_'])) {
			$this->validate();
		} else {
			$route_ = $route = $this->request->get['_route_'];
			unset($this->request->get['_route_']);
			$parts = explode('/', trim(utf8_strtolower($route), '/'));
			list($last_part) = explode('.', array_pop($parts));
			array_push($parts, $last_part);

			$rows = array();
			foreach ($parts as $keyword) {
				if (isset($this->cache_data['keywords'][$keyword])) {
					$rows[] = array('keyword' => $keyword, 'query' => $this->cache_data['keywords'][$keyword]);
				}
			}

			if (isset($this->cache_data['keywords'][$route])){
				$keyword = $route;
				$parts = array($keyword);
				$rows = array(array('keyword' => $keyword, 'query' => $this->cache_data['keywords'][$keyword]));
			}

			if (count($rows) == sizeof($parts)) {
				$queries = array();
				foreach ($rows as $row) {
					$queries[utf8_strtolower($row['keyword'])] = $row['query'];
				}

				reset($parts);
				foreach ($parts as $part) {
					if(!isset($queries[$part])) return false;
					$url = explode('=', $queries[$part], 2);

					if ($url[0] == 'category_id') {
						if (!isset($this->request->get['path'])) {
							$this->request->get['path'] = $url[1];
						} else {
							$this->request->get['path'] .= '_' . $url[1];
						}
					} elseif (count($url) > 1) {
						$this->request->get[$url[0]] = $url[1];
					}
				}
			} else {
				$this->request->get['route'] = 'error/not_found';
			}

			if (isset($this->request->get['product_id'])) {
				$this->request->get['route'] = 'product/product';
				if (!isset($this->request->get['path'])) {
					$path = $this->getPathByProduct($this->request->get['product_id']);
					if ($path) $this->request->get['path'] = $path;
				}
			} elseif (isset($this->request->get['path'])) {
				$this->request->get['route'] = 'product/category';
			} elseif (isset($this->request->get['manufacturer_id'])) {
				$this->request->get['route'] = 'product/manufacturer/info';
			} elseif (isset($this->request->get['information_id'])) {
				$this->request->get['route'] = 'information/information';
			} elseif(isset($this->cache_data['queries'][$route_])) {
					header($this->request->server['SERVER_PROTOCOL'] . ' 301 Moved Permanently');
					$this->response->redirect($this->cache_data['queries'][$route_]);
			} else {
				if (isset($queries[$parts[0]])) {
					$this->request->get['route'] = $queries[$parts[0]];
				}
			}

			$this->validate();

			if (isset($this->request->get['route'])) {
				return new Action($this->request->get['route']);
			}
		}
	}

	public function rewrite($link) {
		if (!$this->config->get('config_seo_url')) return $link;

		$seo_url = '';

		$component = parse_url(str_replace('&', '&', $link));

		$data = array();
		parse_str($component['query'], $data);

		$route = $data['route'];
		unset($data['route']);

		switch ($route) {
			case 'product/product':
				if (isset($data['product_id'])) {
					$tmp = $data;
					$data = array();
					if ($this->config->get('config_seo_url_include_path')) {
						$data['path'] = $this->getPathByProduct($tmp['product_id']);
						if (!$data['path']) return $link;
					}
					$data['product_id'] = $tmp['product_id'];
					if (isset($tmp['tracking'])) {
						$data['tracking'] = $tmp['tracking'];
					}
				}
				break;

			case 'product/category':
				if (isset($data['path'])) {
					$category = explode('_', $data['path']);
					$category = end($category);
					$data['path'] = $this->getPathByCategory($category);
					if (!$data['path']) return $link;
				}
				break;

			case 'product/product/review':
			case 'information/information/agree':
				return $link;
				break;

			default:
				break;
		}

		if ($component['scheme'] == 'https') {
			$link = $this->config->get('config_ssl');
		} else {
			$link = $this->config->get('config_url');
		}

		$link .= 'index.php?route=' . $route;

		if (count($data)) {
			$link .= '&' . urldecode(http_build_query($data, '', '&'));
		}

		$queries = array();
		if(!in_array($route, array('product/search'))) {
			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);
						foreach($categories as $category) {
							$queries[] = 'category_id=' . $category;
						}
						unset($data[$key]);
						break;

					default:
						break;
				}
			}
		}

		if(empty($queries)) {
			$queries[] = $route;
		}

		$rows = array();
		foreach($queries as $query) {
			if(isset($this->cache_data['queries'][$query])) {
				$rows[] = array('query' => $query, 'keyword' => $this->cache_data['queries'][$query]);
			}
		}

		if(count($rows) == count($queries)) {
			$aliases = array();
			foreach($rows as $row) {
				$aliases[$row['query']] = $row['keyword'];
			}
			foreach($queries as $query) {
				$seo_url .= '/' . rawurlencode($aliases[$query]);
			}
		}

		if ($seo_url == '') return $link;

		$seo_url = trim($seo_url, '/');

		if ($component['scheme'] == 'https') {
			$seo_url = $this->config->get('config_ssl') . $seo_url;
		} else {
			$seo_url = $this->config->get('config_url') . $seo_url;
		}

		if (isset($postfix)) {
			$seo_url .= trim($this->config->get('config_seo_url_postfix'));
		} else {
			$seo_url .= '/';
		}

		if(substr($seo_url, -2) == '//') {
			$seo_url = substr($seo_url, 0, -1);
		}

		if (count($data)) {
			$seo_url .= '?' . urldecode(http_build_query($data, '', '&'));
		}

		return $seo_url;
	}

	private function getPathByProduct($product_id) {
		$product_id = (int)$product_id;
		if ($product_id < 1) return false;

		static $path = null;
		if (!isset($path)) {
			$path = $this->cache->get('product.seopath');
			if (!isset($path)) $path = array();
		}

		if (!isset($path[$product_id])) {
			$query = $this->db->query("SELECT category_id FROM " . DB_PREFIX . "product_to_category WHERE product_id = '" . $product_id . "' ORDER BY main_category DESC LIMIT 1");

			$path[$product_id] = $this->getPathByCategory($query->num_rows ? (int)$query->row['category_id'] : 0);

			$this->cache->set('product.seopath', $path);
		}

		return $path[$product_id];
	}

	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];
	}

	private function validate() {
		if (isset($this->request->get['route']) && $this->request->get['route'] == 'error/not_found') {
			return;
		}
		if (ltrim($this->request->server['REQUEST_URI'], '/') =='sitemap.xml') {
			$this->request->get['route'] = 'feed/google_sitemap';
			return;
		}

		if(empty($this->request->get['route'])) {
			$this->request->get['route'] = 'common/home';
		}

		if (isset($this->request->server['HTTP_X_REQUESTED_WITH']) && strtolower($this->request->server['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
			return;
		}

		if (isset($this->request->server['HTTPS']) && (($this->request->server['HTTPS'] == 'on') || ($this->request->server['HTTPS'] == '1'))) {
			$config_ssl = substr($this->config->get('config_ssl'), 0, $this->strpos_offset('/', $this->config->get('config_ssl'), 3) + 1);
			$url = str_replace('&', '&', $config_ssl . ltrim($this->request->server['REQUEST_URI'], '/'));
			$seo = str_replace('&', '&', $this->url->link($this->request->get['route'], $this->getQueryString(array('route')), true));
		} else {
			$config_url = substr($this->config->get('config_url'), 0, $this->strpos_offset('/', $this->config->get('config_url'), 3) + 1);
			$url = str_replace('&', '&', $config_url . ltrim($this->request->server['REQUEST_URI'], '/'));
			$seo = str_replace('&', '&', $this->url->link($this->request->get['route'], $this->getQueryString(array('route')), false));
		}

		if (rawurldecode($url) != rawurldecode($seo)) {
			header($this->request->server['SERVER_PROTOCOL'] . ' 301 Moved Permanently');

			$this->response->redirect($seo);
		}
	}

	private function strpos_offset($needle, $haystack, $occurrence) {
		// explode the haystack
		$arr = explode($needle, $haystack);
		// check the needle is not out of bounds
		switch($occurrence) {
			case $occurrence == 0:
				return false;
			case $occurrence > max(array_keys($arr)):
				return false;
			default:
				return strlen(implode($needle, array_slice($arr, 0, $occurrence)));
		}
	}

	private function getQueryString($exclude = array()) {
		if (!is_array($exclude)) {
			$exclude = array();
			}

		return urldecode(http_build_query(array_diff_key($this->request->get, array_flip($exclude))));
		}
	}
?>

Изменено пользователем andrus

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В раздел платных услуг, как минимум час надо покопаться/поэкспериментировать

Я вот представляю куда примерно копать но тратить  кучу времени ни кто не станет просто так

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Otvet, Благодарю за участие в данной дискуссии.

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

Только вот следующее теперь постоянно будет интересовать: это именно в версии сборки ocStore 1.5.5.1.2 такой баг и недуг с этим SeoPRO, или такое на всех магазинах наблюдается. Но в тоже время никто на форуме данную проблему не поднял, возможно и всё нормально у других - не дублирует "алиас" производителя содержимое страницы категории.  Может нам переустановить движок OC на другую версию? Загадка, откуда такая ошибка появилась и была ли она изначально на сайте. 

п.с. Отпишитесь те, по желанию, кто если и заглянули в эту тему случайно.. как у вас на сайте с такими ссылками?))
 

Изменено пользователем andrus

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так и есть, посмотрел еще у многих магазинах, которые тут представлены в разделе форума "магазины на опенкарте" - везде такая вот проблема. Не только у Вас.

Печально.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Otvet, Благодарю за участие в данной дискуссии.

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

Только вот следующее теперь постоянно будет интересовать: это именно в версии сборки ocStore 1.5.5.1.2 такой баг и недуг с этим SeoPRO, или такое на всех магазинах наблюдается. Но в тоже время никто на форуме данную проблему не поднял, возможно и всё нормально у других - не дублирует "алиас" производителя содержимое страницы категории.  Может нам переустановить движок OC на другую версию? Загадка, откуда такая ошибка появилась и была ли она изначально на сайте. 

п.с. Отпишитесь те, по желанию, кто если и заглянули в эту тему случайно.. как у вас на сайте с такими ссылками?))

 

Таки да, и в 1.5.5.1.2 и в 2.1.0.1 присутствует. Проблема ли это? Скорее нет, ссылки такого вида вы создали сами. Сам себе их робот генерировать и индексировать не будет. Если это так беспокоит, а решения нет, выгрузите список категорий и брендов, и сцепите в экселе. Это займет 20 минут и вы получите длиннючий список ссылок, который можно всунуть в роботс.тхт или сделать редирект.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ссылки такого вида вы создали сами. Сам себе их робот генерировать и индексировать не будет

именно так, уж не раз писалось тут

 

 

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

 

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

просто нужно резать то что генерирует

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

.....

 ссылки такого вида вы создали сами. Сам себе их робот генерировать и индексировать не будет....

А вот совсем и не так. Я случайно заметил на 200 стр. в кабинете ЯндексВебмастера 8 ссылок вида myshop.com/category/podcat/brand Потом начал вбивать вариации разные в конец урл категорий, и получил доступные новые страницы с дублирующим содержимым.

  

Есть такая программа как "SiteMap Generator".. ну и "Xenu" тоже сюда же, которые можно сказать имитируют тот самый бот от Google и Яндекс. Если бы не эти инструменты, я бы никогда и не заметил такой баг в ocStore 1.5.5.1.2 с дублями категорий. "SiteMap Generator" такое сразу нагенерировал.  Возможно так и перекалашмативают спустя время, роботы ваши магазины. Находят те самые дубли и зашвыривают их однажды в индекс. А потом сидишь неделями и  листаешь то что есть в индексе дублированного из 1000 или 5000 товаров, категорий... в кабинете вебмастера. Рубишь всё это тегом "ноуиндекс" и "в роботс/хтацесс" 

​Но это же не выход,  надо убрать генерацию подобного... 

 

Изменено пользователем andrus

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А вот совсем и не так. Я случайно заметил на 200 стр. в кабинете ЯндексВебмастера 8 ссылок вида myshop.com/category/podcat/brand Потом начал вбивать вариации разные в конец урл категорий, и получил доступные новые страницы с дублирующим содержимым.

Есть такая программа как "SiteMap Generator".. ну и "Xenu" тоже сюда же, которые можно сказать имитируют тот самый бот от Google и Яндекс. Если бы не эти инструменты, я бы никогда и не заметил такой баг в ocStore 1.5.5.1.2 с дублями категорий. "SiteMap Generator" такое сразу нагенерировал. Возможно так и перекалашмативают спустя время, роботы ваши магазины. Находят те самые дубли и зашвыривают их однажды в индекс. А потом сидишь неделями и листаешь то что есть в индексе дублированного из 1000 или 5000 товаров, категорий... в кабинете вебмастера. Рубишь всё это тегом "ноуиндекс" и "в роботс/хтацесс"

​Но это же не выход, надо убрать генерацию подобного...

Знаете сколько сайтов я сканировал? Никаких проблем нет, физически этих ссылок не существует в чистом движке. Ищите причину

Есть такая замечательная функция как показать ссылки на страницу

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Т.е. не важно какая категория, не важно какой в конец урла ставить алиас имеющего на сайте бренда, но получается 100500 комбинаций, если подставлять ко всем категориям все бренды по очереди. Здесь однозначно что-то надо изменить в файле seo_pro.php, но каких-либо решений или подсказок  в сети не нашёл.

Кроме того, дубли возможны в таких вариантах:

mysite.com/статья1/категория1

 

Не найдено решение?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

найдено!

заплатить за реализацию

 

категория/бренд я сделал в модуле

а статья/категория и статья/бренд не вижу смысла

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
категория/бренд я сделал в модуле

что за модуль?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

×

Важная информация

На нашем сайте используются файлы cookie и происходит обработка некоторых персональных данных пользователей, чтобы улучшить пользовательский интерфейс. Чтобы узнать для чего и какие персональные данные мы обрабатываем перейдите по ссылке. Если Вы нажмете «Я даю согласие», это означает, что Вы понимаете и принимаете все условия, указанные в этом Уведомлении о Конфиденциальности.