parent::run
* При наследовании у меня выдавалось по 2 одинаковых link prev/link next
* Поэтому ядро виджета я вернул в исходное состояние, поменял use во всех местах на свой, мой является
* как минимум на 50% дописанным/переписанным вариантом для линии
* ====================================================================================================================|
*/
namespace frontend\widgets;
use Yii;
use common\components\Substringer;
use yii\helpers\Url;
use yii\base\Widget;
use yii\data\Pagination;
use yii\helpers\VarDumper as d;
class SeoLinks extends Widget
{
/**
* @var null | Pagination
* @var null | \common\components\SeoComponent
*/
public $pagination = null;
public $canonical = true;
public $firstpageWithoutParameter = false;
public $seo = null;
/**
* @inheritdoc
*/
/**
* ============================================================================================================|
* Правка от Саши
* 1) Если есть параметры в урле, Canonical должен вести на страницу без параметров,
* за исключением Пагинации и сортировки. И next/prev чтобы были без этих параметров
* Пример страницы
* https://www.linija-svitla.ua/catalog/ulichnoe-osveshchenie?page_num=3&fcatlist=3268%2C&sort=test_test&3269%2C3270%2C3272%2C3273%2C3274%2C3275&page=50&per-page=18
* ************************************************************************************************************
* 2) link prev со 2й страницы должен ссылатся на первую, НО ,
* a) там должна отсутствовать пагинация б) должна остатся сортировка
* Прим
* Было https://www.linija-svitla.ua/catalog/ulichnoe-osveshchenie?page=1&per=page=18&sort=title_asc
* Стало https://www.linija-svitla.ua/catalog/ulichnoe-osveshchenie?sort=title_asc
* ============================================================================================================|
* 3) При 301 редирректе от НеЧПУ продуктам/фильтрам к ЧПУ, теги prev/next ссылаются на старые НеЧПУ
* страницы
* ============================================================================================================|
*/
public function run()
{
# 0 изменяем ссылку, оставляя в ней только пагинацию и сортировку
$firstRegex = '/(\??|&?)page=\d{1,5}&per-page=\d{1,5}/';
$secondRegex = '/(\?|&)sort=[a-zA-z_]+/';
$requiredDelimiter = '?';
$firstConcatenateSymbol = '?';
$secondConcatenateSymbol = '&';
$links = $this->pagination->getLinks();
if ($this->canonical and ($this->seo->getRobots() != 'noindex,nofollow' and $this->seo->getRobots() != 'noindex,follow' and $this->seo->getRobots() != 'noindex, nofollow' and $this->seo->getRobots() != 'noindex, follow')
) {
# 0
$cannonicalLink = Substringer::changeStringByRegex(
Yii::$app->request->getAbsoluteUrl(),
$firstRegex,
$secondRegex,
$requiredDelimiter,
$firstConcatenateSymbol,
$secondConcatenateSymbol
);
# 1 В канониклах должна присутствовать только пагинация, удаляю всё, что не есть пагинацией
if ((strpos($cannonicalLink, '?page'))) {
$cannonicalLink = Substringer::simpleStringSubstring($cannonicalLink, '&sort');
} else {
$cannonicalLink = Substringer::changeStringByRegex(
Yii::$app->request->getAbsoluteUrl(),
$firstRegex,
$secondRegex,
$requiredDelimiter,
$firstConcatenateSymbol,
$secondConcatenateSymbol
);
$cannonicalLink = Substringer::simpleStringSubstring($cannonicalLink, '&sort');
/**
* Сейчас ссылка имеет вид: www.siteName.com?page=X&per-page=X
*/
# 1.1 Если в результате у нас остается URL вида www.siteName.com?
# обрезаем этот ?
if (strpos($cannonicalLink, '?') && !strpos($cannonicalLink, '?page')) {
$cannonicalLink = stristr($cannonicalLink, '?', true);
}
# 1.2 если ссылка содержит в себе пагинацию, НО она по каким-то причинам не первая,
# удаляем все GET параметры до неё, и заменяем & на ?
if (strpos($cannonicalLink, '?page') !== false) {
$cannonicalLinkRigth = stristr($cannonicalLink, '&page');
$cannonicalLinkRigth = substr($cannonicalLinkRigth, 1);
$cannonicalLinkRigth = '?' . $cannonicalLinkRigth;
$cannonicalLink = stristr($cannonicalLink, '?', true);
$cannonicalLink .= $cannonicalLinkRigth;
}
}
# если нашем очищенном каноникле есть ? в конце(www.siteName.com?page=X&per-page=X?), убираем его
$cannonicalLink = ($cannonicalLink[strlen($cannonicalLink) - 1] !== '?') ? $cannonicalLink : rtrim(
$cannonicalLink,
'?'
);
# 1.3 в каноникле должна сохранятся очередность нужных GET параметров
# берём финальную ссылку и если нужно, перерисовываем её
$seoCuttedLink = $this->changeLinksToRequestView($cannonicalLink, Yii::$app->request->getAbsoluteUrl());
$this->view->registerLinkTag(
[
'rel' => 'canonical',
'href' => $cannonicalLink,
]
);
}
/**
* =========================================================================================================
* То же самое для тега next
* =========================================================================================================
*/
if (key_exists('next', $links)) {
#2.1 Обрезаем ссылку справа по заданным GET regexp-ам
$nextPageGetQueryString = stristr(
Substringer::changeStringByRegex(
$links['next'],
$firstRegex,
$secondRegex,
$requiredDelimiter,
$firstConcatenateSymbol,
$secondConcatenateSymbol
),
'?'
);
# 2.2 сливаем левую и правую часть
$nextLinkTitle = Substringer::simpleStringSubstring(
Yii::$app->request->url,
'?'
) . $nextPageGetQueryString;
# 2.3 перестраиваем сслыку согласно входящему стилю
$nextLinkTitle = $this->changeLinksToRequestView($nextLinkTitle, Yii::$app->request->url);
$this->view->registerLinkTag(
[
'rel' => 'next',
'href' => $nextLinkTitle,
]
);
}
if ($this->firstpageWithoutParameter and $this->pagination->page == 1) {
if (key_exists('prev', $links)) {
$link = stristr(\Yii::$app->request->url, '?', true);
/**
* @var \artbox\catalog\models\Filter $filter
*/
$filter = \Yii::$app->get('filter')->filterObj;
if (key_exists($link, $filter->getReplacedFilters())) {
$link = $filter->getReplacedFilters()[$link];
}
$seoCuttedLink = $this->changeLinksToRequestView($link, Yii::$app->request->url);
$this->view->registerLinkTag(
[
'rel' => 'prev',
'href' => $seoCuttedLink,
]
);
}
} else {
if (key_exists('prev', $links)) {
# правка 3 Я не ломаю старых наработок, а просто прокидываю новый(если был редирект) URL prev для
// предыдущих правок
$prevPageGetQueryString = stristr(
Substringer::changeStringByRegex(
$links['prev'],
$firstRegex,
$secondRegex,
$requiredDelimiter,
$firstConcatenateSymbol,
$secondConcatenateSymbol
),
'?'
);
$prevLinkTitle = Substringer::simpleStringSubstring(
Yii::$app->request->url,
'?'
) . $prevPageGetQueryString;
# правка 2
$seoStringStart = $prevLinkTitle;
$seoCuttedLink = $seoStringStart;
$seoCuttedLink = Substringer::changeStringByRegex(
$seoCuttedLink,
$firstRegex,
$secondRegex,
$requiredDelimiter,
$firstConcatenateSymbol,
$secondConcatenateSymbol
);
if (strpos($seoStringStart, '?page=1')) {
/**
* Правка для категории/блога
* У них разное к-во страниц, поэтому на замену конкретной срезки URL(?page=1&per-page=18) как было раньше,
* я буду автоматически пересматривать currentPageSizeParam для странички
*/
$perPageParam = false;
# если в $seoCuttredLink уже есть пагинация, то паршу строку и достаю реальное к-во записей для страницы
if (strpos($seoCuttedLink, 'per-page')) {
$perPageParam = parse_str($seoCuttedLink, $params);
$perPageParam = (isset ($params['per-page'])) ? $params['per-page'] : false;
}
# или же ставлю размер как в frontend/views/category,
# потому что большая часть кода здесь заточена именно под currentPerPageSizeParam=18
$perPageParam = ($perPageParam === false) ? 18 : $perPageParam;
$seoCuttedLink = str_replace('?page=1&per-page=' . $perPageParam, '?', $seoCuttedLink);
$seoCuttedLink = str_replace('&', '', $seoCuttedLink);
$strlen = mb_strlen($seoCuttedLink);
if ($seoCuttedLink[$strlen - 1] == '?') {
$seoCuttedLink = str_replace('?', '', $seoCuttedLink);
}
} else {
$seoCuttedLink = $seoStringStart;
}
# правка 2
if (strpos($seoCuttedLink, '?sort')) {
if (strpos($seoCuttedLink, '&page=1')) {
$seoCuttedLink = Substringer::simpleStringSubstring($seoCuttedLink, '&page=1&per-page');
}
}
$seoCuttedLink = Substringer::changeStringByRegex(
$seoCuttedLink,
$firstRegex,
$secondRegex,
$requiredDelimiter,
$firstConcatenateSymbol,
$secondConcatenateSymbol
);
# поправляем URL выдачи, если он после всего имеет такой вид:
if (preg_match('/\d+sort=/', $seoCuttedLink) != false) {
$seoCuttedLinkRigth = stristr($seoCuttedLink, 'sort=');
$seoCuttedLink = stristr($seoCuttedLink, 'sort=', true) . '&' . $seoCuttedLinkRigth;
}
# то же самое, если в пагинации URL пропущен & ==> www.site.com?page=Xper-page=X
if (preg_match('/\d+per-page=/', $seoCuttedLink) != false) {
$seoCuttedLinkRigth = stristr($seoCuttedLink, 'per-page=');
$seoCuttedLink = stristr($seoCuttedLink, 'per-page=', true) . '&' . $seoCuttedLinkRigth;
}
$seoCuttedLink = $this->changeLinksToRequestView($seoCuttedLink, Yii::$app->request->url);
$this->view->registerLinkTag(
[
'rel' => 'prev',
'href' => $seoCuttedLink,
]
);
}
}
parent::run();
}
/**
* @param string $link
* @param string $requestUrl
* =========================================================================================================
* Метод, который берет строку(URL), и преобразовывает его в вид, в котором он поступал. Написан для тегов
* next/prev/cannonical
* =========================================================================================================
* К нам приходит сюда(в данный виджет) URL, из которого нужно сформировать данные 3 линка. По всем Саниным
* правкам, они должны быть в одном из форматов:
* + новенькийЧпу?page=X&per-page=X&sort=param_val
* + новенькийЧпу?sort=param_val&page=X&per-page=X
* Метод берет текущий URL, смотрит какая из 2 вариаций пришла, и не меняя уже написанной логики
* возвращает обработанную конечтную строку,идентичную входящей
*Если в текущем URL отсутствует погинация, НО присутствует сортировка,
* делает ссылку типа www.siteName.com?sort=var_param&page=X&per-page=X
* =========================================================================================================
*
* @return string
*/
private function changeLinksToRequestView(string $link, string $requestUrl)
{
$positionSort = (strpos($requestUrl, 'sort=') !== false) ? strpos($requestUrl, 'sort=') : 0;
$positionPagination = (strpos($requestUrl, 'page=') !== false) ? strpos($requestUrl, 'page=') : 0;
$regex1 = '/(\??|&?)page=\d{1,5}&per-page=\d{1,5}/';
$regex2 = '/(\??|&)sort=[a-zA-z_]+&?/';
/*
* У нас 5 вариантов:
* sort>page ===> пагинация идёт первой
* sort перввая сортировка
* !sort
* !page
* !sort !page
*/
$option = $positionSort - $positionPagination;
if ($option > 0 && $positionPagination != 0)// первая пагинация
{
$link = Substringer::changeStringByRegex($link, $regex1, $regex2, '?', '?', '&');
} elseif ($option > 0 && $positionPagination == 0)//есть сортировка, но нету пагинации
{
$link = Substringer::changeStringByRegex($link, $regex2, $regex1, '?', '?', '&');
} elseif ($option < 0)// page>sort
{
$link = Substringer::changeStringByRegex($link, $regex2, $regex1, '?', '?', '&');
} else // нету ни сортировки, ни пагинации
{
$link = Substringer::changeStringByRegex($link, $regex2, $regex1, '?', '?', '&');
}
$result = $link;
return $result;
}
}