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` — код текущего языка.
*
* Оба прохода — по одному и тому же разобранному графу за один проход
* по тегам `