Перейти к содержимому


Правила форума

Внимание!!! Если не можете скачать, пожалуйста ознакомьтесь с условиями получения доступа с файлам форума. Правила форума


Боремся с дублями - canonical


Сообщений в теме: 13

#1 badisoft

    Продвинутый пользователь

  • VIP
  • 4 943 сообщений
Репутация: 745
Мастер

Отправлено 27 марта 2017 - 19:06

Дополнение для создания "канонических" ссылок.
Кратко - https://yandex.ru/su...l.xml#canonical
Более полно - весь интернет к услугам. Очень много информации.

На первую-вторую-десятую страницу категории каноникал-ссылка одна и та же - без offset-а.
Т.е. первая (или единственная) страница категории.
На "показать все" - с &show_all=yes, т.е. ВСЕ товары категории. Хочется по другому - поменяйте.
Остальное более-менее банально и однозначно, т.е. вне зависимости от типа ссылки (динамическая index.php?blablaID=123 или статическая /blabla123.html) в canonical пишется выбранный в "Общих настройках" вариант.

Если в "общих настройках" выбраны динамические ссылки (точнее, не выбраны "псевдостатические", которые по умолчанию выбраны), то оно особо и не надо нигде кроме категорий (там sort и direction создают дубли). Все равно везде index.php?blabla123.html.

А вот если оставлены дефолтовые псевдостатические (как обычно у всех и есть, я только одного клиента знаю с динамическими), то это полезно, т.к. ссылки на сайте присутствуют в обоих видах. Например, на странице товара /product123.html есть ссылка на обсуждения товара /index.php?productID=123&discuss=yes, а на странице обсуждения обратная ссылка на страницу товара, которая уже - тадададам! - /index.php?productID=123.
И такого много, насколько я помню.

В общем, не так давно Яндекс на моем сайте начал выкидывать такие дубли из поиска вообще (или оставлять вовсе не то вариант, который надо) и я озадачился. Помогло. Реально помогло, причем довольно быстро. Хотя, возможно, причина вовсе и не в добавлении canonical, а что-то они откатили обратно в СВОЕМ алгоритме.

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

Установка:
=========

1. в /core/includes/ создаем файл canonical.php
<?php
if (isset($_GET['categoryID']))
	$smarty->assign('canonical', (CONF_MOD_REWRITE?('category_'.(int)$_GET['categoryID'].'.html'):('/index.php?categoryID='.(int)$_GET['categoryID'])).
								 (isset($_GET['show_all'])?'?show_all=yes':''));
elseif (isset($_GET['productID']))
	$smarty->assign('canonical', CONF_MOD_REWRITE?('product_'.(int)$_GET['productID'].'.html'):('/index.php?productID='.(int)$_GET['productID']));
elseif ( isset($_GET['show_aux_page']) )
	$smarty->assign('canonical', CONF_MOD_REWRITE?('page_'.(int)$_GET['show_aux_page'].'.html'):('/index.php?show_aux_page='.(int)$_GET['show_aux_page']));
elseif (isset($_GET['fullnews']))
	$smarty->assign('canonical', CONF_MOD_REWRITE?('show_news_'.(int)$_GET['fullnews'].'.html'):('/index.php?fullnews='.(int)$_GET['fullnews']));
elseif (isset($_GET['news']))
	$smarty->assign('canonical', CONF_MOD_REWRITE?('news.html'):('/index.php?news=yes'));
elseif (isset($_GET['show_price']))
	$smarty->assign('canonical', CONF_MOD_REWRITE?('price.html'):('/index.php?show_price=yes'));
elseif (isset($_GET['feedback']))
	$smarty->assign('canonical', CONF_MOD_REWRITE?('feedback.html'):('/index.php?feedback=yes'));
elseif (isset($_GET['shopping_cart']))
	$smarty->assign('canonical', CONF_MOD_REWRITE?('cart.html'):('/index.php?shopping_cart=yes'));
?>


2. в файл head.tpl.html вставляем
{* BEGIN canonical *}
{if $canonical}<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}{$canonical}"/>{/if}
{* END canonical *}

http://cpu.badisoft.ru (тестовый сайт), http://badisoft.ru (модули)

#2 Den

    Продвинутый пользователь

  • Assistent vsupport.ru
  • PipPipPip
  • 111 сообщений
Репутация: 0
Начинающий

Отправлено 29 марта 2017 - 13:06

badisoft, очень своевременно!
А для "счастливых" обладателей ЧПУ от трикивеба сможете сделать мод? Оплачу.

#3 badisoft

    Продвинутый пользователь

  • VIP
  • 4 943 сообщений
Репутация: 745
Мастер

Отправлено 29 марта 2017 - 14:59

Цитата

А для "счастливых" обладателей ЧПУ от трикивеба сможете сделать мод? Оплачу
Могу. В личку.
http://cpu.badisoft.ru (тестовый сайт), http://badisoft.ru (модули)

#4 Den

    Продвинутый пользователь

  • Assistent vsupport.ru
  • PipPipPip
  • 111 сообщений
Репутация: 0
Начинающий

Отправлено 29 марта 2017 - 17:33

Сделал сам. Привожу строки для категорий, товаров, обсуждений и новостей:
if (isset($_GET['categoryID']))
	$smarty->assign('canonical', (CONF_MOD_REWRITE?($uri . '/'):('/index.php?categoryID='.(int)$_GET['categoryID'])).(isset($_GET['show_all'])?'?show_all=yes':'')); //категории ЧПУ trickywebs
elseif (isset($_GET['productID']))
	$smarty->assign('canonical', CONF_MOD_REWRITE?($_GET['catUri'].'/'.$uri.'.html'):('/index.php?productID='.(int)$_GET['productID'])); //товар ЧПУ trickywebs						
elseif (isset($_GET['discuss']))
	$smarty->assign('canonical', (CONF_MOD_REWRITE?('index.php?productID='.(int)$_GET['productID']):('/index.php?productID='.(int)$_GET['productID'])).(isset($_GET['discuss'])?'&discuss=yes':''));   //обсуждения ЧПУ trickywebs
elseif (isset($_GET['fullnews']))
	$smarty->assign('canonical', CONF_MOD_REWRITE?('news/'.$uri.'.html'):('/index.php?fullnews='.(int)$_GET['fullnews'])); //просмотр новости ЧПУ trickywebs


#5 badisoft

    Продвинутый пользователь

  • VIP
  • 4 943 сообщений
Репутация: 745
Мастер

Отправлено 29 марта 2017 - 19:31

Цитата

Сделал сам
1. При заходе по ссылке /index.php?productID=xxx (а в этом основной смысл canonical) какая будет ссылка в canonical?
2. Зачем усложняющая код двувариантность от CONF_MOD_REWRITE, если при модуле ЧПУ вариант все равно один?
3. ветка с elseif (isset($_GET['discuss'])) никогда не выполнится, т.к. когда есть $_GET['discuss'], то есть и $_GET['productID'], а он перехвачен более ранним if.
4. что за бред? В ветке elseif (isset($_GET['discuss'])) далее ветвление isset($_GET['discuss'])?'&discuss=yes':''. Очевидно, что в ветвлении НИКОГДА не выполнится второй вариант.

5. Для трикивебовского ЧПУ PHP-часть вообще не нужна, достаточно видоизменить код в head.tpl.html. В принципе, и без ЧПУ можно было сделать так, но для трикивебовского ЧПУ оно УДОБНЕЕ И ПРОЩЕ ПО КОДУ.

Это так, с ходу, особо не копая. Да тут и копать-то негде, десять строчек. Зато сэкономили 20$ :).
http://cpu.badisoft.ru (тестовый сайт), http://badisoft.ru (модули)

#6 Den

    Продвинутый пользователь

  • Assistent vsupport.ru
  • PipPipPip
  • 111 сообщений
Репутация: 0
Начинающий

Отправлено 30 марта 2017 - 09:41

Цитата

1. При заходе по ссылке /index.php?productID=xxx (а в этом основной смысл canonical) какая будет ссылка в canonical?
такой страницы нет, срабатывает редирект на ЧПУ-версию. Есть страница /index.php?uri=XXX&catUri=YYY&uriFor=product, открыв которую вижу в каноникал правильный ЧПУ URL

Цитата

2. Зачем усложняющая код двувариантность от CONF_MOD_REWRITE, если при модуле ЧПУ вариант все равно один?
не подумал

Цитата

3. ветка с elseif (isset($_GET['discuss'])) никогда не выполнится, т.к. когда есть $_GET['discuss'], то есть и $_GET['productID'], а он перехвачен более ранним if.
4. что за бред? В ветке elseif (isset($_GET['discuss'])) далее ветвление isset($_GET['discuss'])?'&discuss=yes':''. Очевидно, что в ветвлении НИКОГДА не выполнится второй вариант.
не знаю как, делал интуитивно. Но как ни странно работает, а значит выполняется. У меня в файле эта ветка идет выше чем продукт, может поэтому...

Цитата

5. Для трикивебовского ЧПУ PHP-часть вообще не нужна, достаточно видоизменить код в head.tpl.html. В принципе, и без ЧПУ можно было сделать так, но для трикивебовского ЧПУ оно УДОБНЕЕ И ПРОЩЕ ПО КОДУ.
хмм... попробую

Цитата

Это так, с ходу, особо не копая. Да тут и копать-то негде, десять строчек. Зато сэкономили 20$ :).
как и сказал ранее - благодарность за мной.

#7 badisoft

    Продвинутый пользователь

  • VIP
  • 4 943 сообщений
Репутация: 745
Мастер

Отправлено 30 марта 2017 - 11:12

Цитата

У меня в файле эта ветка идет выше чем продукт, может поэтому...
Да, именно поэтому. Сначала (!) обрабатывается ситуация с $_GET['discuss'], а только если она не обработана, то уже с $_GET['productID'].
Хотя если с ProductID идет редирект, то ситуация с $_GET['productID'] без $_GET['discuss'] вообще никогда не возникнет.
http://cpu.badisoft.ru (тестовый сайт), http://badisoft.ru (модули)

#8 Den

    Продвинутый пользователь

  • Assistent vsupport.ru
  • PipPipPip
  • 111 сообщений
Репутация: 0
Начинающий

Отправлено 30 марта 2017 - 11:42

выбросил лишнее из тех строк:
if (isset($_GET['categoryID']))
	$smarty->assign('canonical', ($uri . '/'));							
elseif (isset($_GET['discuss']))
	$smarty->assign('canonical', ('index.php?productID='.(int)$_GET['productID'].'&discuss=yes'));			  
elseif (isset($_GET['productID']))
	$smarty->assign('canonical', ($_GET['catUri'].'/'.$uri.'.html'));  
elseif (isset($_GET['fullnews']))
	$smarty->assign('canonical', ('news/'.$uri.'.html'));
elseif ( isset($_GET['show_aux_page']) )
	$smarty->assign('canonical', ('pages/'.$uri.'.html'));

а в head.tpl.html добавил так:
{if $main_content_template == "home.tpl.html"}
<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}"/>
{elseif $smarty.server.REQUEST_URI == "/404.html"}
<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}/404.html"/>
{else}
{if $canonical}
<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}{$canonical}"/>
{/if}
{/if}

P.S. кстати в robots.txt по-умолчанию страницам cart.html и feedback.html стоит директива disallow, а google рекомендует не указывать канонические страницы в этом файле. Так что их лучше или убрать из canonical.php или из robots.txt

#9 badisoft

    Продвинутый пользователь

  • VIP
  • 4 943 сообщений
Репутация: 745
Мастер

Отправлено 30 марта 2017 - 13:29

Вариант для Трикивебовского ЧПУ.
Вставлять в head.tpl.html, PHP-часть не требуется.
Написано умозрительно (глянув в код этого ЧПУ), проверить негде.
{* BEGIN canonical *}
{if $smarty.get.categoryID && $selected_category && !$smarty.get.productID && !$smarty.get.search_with_change_category_ability} {* катeгория *}
<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}{$selected_category|@fu_make_url}{*if $smarty.get.show_all}?show_all=yes{/if*}"/>
{elseif $smarty.get.productID && $product_info} {* товар *}
<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}{$product_info|@fu_make_url}"/>
{elseif $smarty.get.news} {* новости (список) *}
<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}news.html"/>
{elseif $smarty.get.fullnews && $news_full_array} {* новость *}
<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}{$news_full_array|@fu_make_url_news}"/>
{elseif $smarty.get.show_aux_page && $show_aux_page} {* страница *}
<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}{$show_aux_page|@fu_make_url_pages}"/>
{elseif $smarty.get.show_price} {* прайс *}
<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}price.html"/>
{elseif $smarty.get.feedback} {* feedback *}
<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}feedback.html"/>
{elseif $smarty.get.shopping_cart} {* корзина *}
<link rel="canonical" href="{$smarty.const.CONF_FULL_SHOP_URL}cart.html"/>
{/if}
{* END canonical *}

http://cpu.badisoft.ru (тестовый сайт), http://badisoft.ru (модули)

#10 Den

    Продвинутый пользователь

  • Assistent vsupport.ru
  • PipPipPip
  • 111 сообщений
Репутация: 0
Начинающий

Отправлено 30 марта 2017 - 14:44

badisoft, кода вроде бы меньше, а с точки зрения нагрузки на сервер тоже легче будет?

Просмотр сообщенияbadisoft сказал:

Написано умозрительно (глянув в код этого ЧПУ), проверить негде.
все работает, только для страницы с обсуждениями товара каноничный URL - страница товара (впрочем в изначальном модуле также).

#11 badisoft

    Продвинутый пользователь

  • VIP
  • 4 943 сообщений
Репутация: 745
Мастер

Отправлено 30 марта 2017 - 14:59

Просмотр сообщенияDen сказал:

с точки зрения нагрузки на сервер тоже легче будет?
С точки зрения нагрузки на сервер это ничто относительно всего остального кода с SQL-запросами.
Какая разница, на 0.001% увеличилась нагрузка или на 0.002%?

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

Пример: есть довольно известный код горизонтального меню, красивый и удобный в подгонке дизайна. Не знаю, чей. Так вот он очень сильно тормозит как только категорий становится больше сотни. И дело вовсе не в том, что обработка условий сделана в TPL.HTML вместо PHP, а в том, что в цикле по списку категорий есть вложенный цикл по списку категорий. А при определенном условии (уже не помню, каком) во вложенном цикле есть еще один (ТРЕТИЙ!) цикл по списку категорий.
Т.е. при ста категориях получается цикл на 100*100*100=миллион проходов. А при 1000 категорий и вообще кранты - миллиард проходов, меню строится несколько минут.
http://cpu.badisoft.ru (тестовый сайт), http://badisoft.ru (модули)

#12 badisoft

    Продвинутый пользователь

  • VIP
  • 4 943 сообщений
Репутация: 745
Мастер

Отправлено 07 апреля 2017 - 14:06

Просмотр сообщенияDen сказал:

все работает, только для страницы с обсуждениями товара каноничный URL - страница товара (впрочем в изначальном модуле также).
Добавьте в условие && !$smarty.request.discuss (либо && !isset($_REQUEST['discuss']) в изначальном модуле), чтобы на странице дискуссии не было canonical от страницы товара.

Если копнуть глубже, то это из за... эээ... ну, не совсем чтобы ошибки, но штатной кривости в коде ShopCMS.
В файле product_detailed.php создаются данные для страницы товара.
В том числе и массив $product_info, по которому (кроме наличия $_GET['productID']) у меня сделана проверка вывода canonical для товара.
Но проверка "надо ли создавать данные для страницы товара" в product_detailed.php выглядит как
if (isset($productID) && $productID>0 && !isset($_POST["add_topic"]) && !isset($_POST["discuss"]) )

А страница дискуссии (пока не добавлено нового сообщения) не содержит $_POST["discuss"], только $_GET["discuss"], т.е. на странице дискуссии все равно создается нигде не используемый массив $product_info и куча других данных от страницы товара.
Другими словами, правильнее запретить создание $product_info (т.е. выполнение кода в product.dtetailed.php) для всего, что не страница товара, заменив $_POST["discuss"] на $_REQUEST["disscuss"].

PS. А зачем там еще и isset($_POST["add_topic"]) я вообще не понимаю, ведь $_POST["add_topic"] без $_POST["discuss"] не бывает, т.к. эти два inputa находятся в одной форме.
http://cpu.badisoft.ru (тестовый сайт), http://badisoft.ru (модули)

#13 Den

    Продвинутый пользователь

  • Assistent vsupport.ru
  • PipPipPip
  • 111 сообщений
Репутация: 0
Начинающий

Отправлено 10 апреля 2017 - 11:12

Изучаю в логах посещения гуглбота.
Из свеженького: GET /index.php?do=filter&filter=1 HTTP/1.0 (по ссылке открывается блок Ajax фильтра :)
В индексе пока нет, но не исключено, что появится со временем... Вот откуда он их берет и что с этим делать?

#14 badisoft

    Продвинутый пользователь

  • VIP
  • 4 943 сообщений
Репутация: 745
Мастер

Отправлено 10 апреля 2017 - 14:33

Просмотр сообщенияDen сказал:

Вот откуда он их берет и что с этим делать?
Эта ссылка - AJAX-запрос из моего AJAX-фильтра. Зачем гугл по ней ходит и что с этим делать - вопросы к Гуглу. Я не знаю. Она находится в яваскрипт-коде и не является ссылкой для клиентского перехода.
Стандартный способ обмана слишком умных роботов - разбиение сссылки в яваскрипте на куски.
Т.е. вместо "http://mysite.ru" пишем что-нибудь типа "htt"+"p://mysite.ru" или еще как-то убираем из кода лежащую в прямом виде ссылку. Думаю, идея понятна.
http://cpu.badisoft.ru (тестовый сайт), http://badisoft.ru (модули)