fixMetaTags( $document, $target ); $this->fixJsonLd( $document, $target ); } /** * Правит ``: адрес страницы и код локали. * * @param HtmlDocument $document Разобранный документ. * @param Language $target Текущий язык. */ private function fixMetaTags( HtmlDocument $document, Language $target ): void { $canonical = $this->urls->canonicalUrlFor( $target ); $seen = array(); foreach ( $document->document()->getElementsByTagName( 'meta' ) as $meta ) { $key = strtolower( trim( (string) $meta->getAttribute( 'property' ) ) ); if ( '' === $key ) { $key = strtolower( trim( (string) $meta->getAttribute( 'name' ) ) ); } if ( in_array( $key, self::URL_META, true ) ) { $meta->setAttribute( 'content', $canonical ); continue; } if ( 'og:locale' === $key ) { $meta->setAttribute( 'content', $this->ogLocale( $target ) ); $seen['og:locale'] = true; } } if ( isset( $seen['og:locale'] ) ) { $this->refreshAlternateLocales( $document, $target ); } } /** * Пересобирает набор `og:locale:alternate`. * * SEO-плагин выводит его для одного языка — своего. Старые значения * убираются целиком, чтобы не остался список от исходной локали. * * @param HtmlDocument $document Разобранный документ. * @param Language $target Текущий язык. */ private function refreshAlternateLocales( HtmlDocument $document, Language $target ): void { $existing = array(); foreach ( $document->document()->getElementsByTagName( 'meta' ) as $meta ) { $key = strtolower( trim( (string) $meta->getAttribute( 'property' ) ) ); if ( 'og:locale:alternate' === $key ) { $existing[] = $meta; } } $parent = null; foreach ( $existing as $meta ) { $parent = $meta->parentNode ?? $parent; if ( null !== $meta->parentNode ) { $meta->parentNode->removeChild( $meta ); } } if ( null === $parent ) { $parent = $document->document()->getElementsByTagName( 'head' )->item( 0 ); } if ( null === $parent ) { return; } foreach ( $this->settings->published() as $language ) { if ( $language->locale === $target->locale ) { continue; } $meta = $document->document()->createElement( 'meta' ); $meta->setAttribute( 'property', 'og:locale:alternate' ); $meta->setAttribute( 'content', $this->ogLocale( $language ) ); $parent->appendChild( $meta ); } } /** * Локаль в формате Open Graph: `ru_RU`, а не `ru-RU` и не голое `ru`. * * Facebook требует полный код `xx_XX` из своего документированного * списка (https://developers.facebook.com/docs/messenger-platform/... — * og:locale); просто заменить дефис на подчёркивание в `bcp47()` * недостаточно, когда код языка в настройках задан без региона * («en», а не «en-US») — тогда получится невалидное голое «en». * * @param Language $language Язык. */ private function ogLocale( Language $language ): string { return Locale::toOgLocale( $language->locale ); } /** * Приводит структурированные данные к текущему языку: адреса страниц * получают префикс, `inLanguage` — код текущего языка. * * Оба прохода — по одному и тому же разобранному графу за один проход * по тегам `