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