HEX
Server: Apache
System: Linux beta.alfanet.ee 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: busines1 (1252)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: //proc/thread-self/cwd/wp-content/plugins/wp-seo-multilingual/classes/Presentation/Hooks.php
<?php

namespace WPML\WPSEO\Presentation;

use WPML\FP\Logic;
use WPML\FP\Maybe;
use WPML\FP\Obj;
use WPML\WPSEO\Utils;
use Yoast\WP\SEO\Presentations\Indexable_Presentation;
use function WPML\FP\pipe;

class Hooks implements \IWPML_Frontend_Action {

	const OPTION_KEY = 'wpseo_titles';

	/**
	 * Add hooks.
	 */
	public function add_hooks() {
		add_filter( 'wpseo_title', [ $this, 'translateTitle' ], 10, 2 );
		add_filter( 'wpseo_metadesc', [ $this, 'translateDescription' ], 10, 2 );

		add_action( 'init', [ $this, 'init' ] );

		add_filter( 'wpseo_breadcrumb_indexables', [ $this, 'translateBreadcrumbs' ] );

		add_filter( 'wpseo_frontend_presentation', [ $this, 'translatePermalinks' ] );

		add_filter( 'wpseo_frontend_presentation', [ $this, 'setSchemaGraphData' ], 10, 2 );
	}

	public function init() {
		if ( ! Utils::isFrontPageWithPosts() ) {
			add_filter( 'wpseo_opengraph_title', [ $this, 'translateTitle' ], 10, 2 );
			add_filter( 'wpseo_opengraph_desc', [ $this, 'translateDescription' ], 10, 2 );
		}
	}

	/**
	 * Translates a title.
	 *
	 * @param string                 $title        The title in the default language.
	 * @param Indexable_Presentation $presentation The presentation class.
	 *
	 * @return string
	 */
	public function translateTitle( $title, $presentation ) {
		return $this->translate( 'title', $title, $presentation );
	}

	/**
	 * Translates a description.
	 *
	 * @param string                 $description  The description in the default language.
	 * @param Indexable_Presentation $presentation The presentation class.
	 *
	 * @return string
	 */
	public function translateDescription( $description, $presentation ) {
		return $this->translate( 'metadesc', $description, $presentation );
	}

	/**
	 * Translates a breadcrumb title.
	 *
	 * @param string                 $title        The title in the default language.
	 * @param Indexable_Presentation $presentation The presentation class.
	 *
	 * @return string
	 */
	public function translateBreadcrumbTitle( $title, $presentation ) {
		return $this->translate( 'bctitle', $title, $presentation );
	}

	/**
	 * Get the translations from the options table, which will include the translated admin-texts.
	 *
	 * @param string                 $type         The object type of the Indesable, used as a prefix for the option name.
	 * @param string                 $text         The text in the default language.
	 * @param Indexable_Presentation $presentation The presentation class.
	 *
	 * @return string
	 */
	private function translate( $type, $text, $presentation ) {
		$translation = Obj::prop( $this->getOptionKey( $type, $presentation ), get_option( self::OPTION_KEY, [] ) );

		if ( $translation ) {
			$text = wpseo_replace_vars( $translation, $presentation );
		}

		return $text;
	}

	/**
	 * Returns the option key for the object being translated.
	 *
	 * @param string                 $type         How to prefix the option name.
	 * @param Indexable_Presentation $presentation The presentation class.
	 *
	 * @return string
	 */
	private function getOptionKey( $type, $presentation ) {
		$systemPageSubType = wpml_collect( [
			'search-result' => 'search',
		] )->get( $presentation->model->object_sub_type, $presentation->model->object_sub_type );

		return wpml_collect(
			[
				'post-type-archive' => $type . '-ptarchive-' . $presentation->model->object_sub_type,
				'system-page'       => $type . '-' . $systemPageSubType . '-wpseo',
				'home-page'         => $type . '-home-wpseo',
			]
		)->get( $presentation->model->object_type, '' );
	}

	/**
	 * Translate titles and links for home and archives.
	 *
	 * @param Indexable[] $indexables An array of Indexable objects representing the breacrumbs.
	 *
	 * @return Indexable[]
	 */
	public function translateBreadcrumbs( $indexables ) {
		foreach ( $indexables as &$indexable ) {
			if ( 'post-type-archive' === $indexable->object_type ) {
				$getDefaultLabel = function( $indexable ) {
					$post_object = get_post_type_object( $indexable->object_sub_type );
					return $post_object ? $post_object->labels->name : $indexable->breadcrumb_title;
				};

				$getYoastLabel = function( $indexable ) {
					return $this->translateBreadcrumbTitle(
						$indexable->breadcrumb_title,
						(object) [ 'model' => $indexable ]
					);
				};

				$indexable->breadcrumb_title = $getDefaultLabel( $indexable );
				$indexable->breadcrumb_title = $getYoastLabel( $indexable );
				$indexable->permalink        = self::getPostTypeArchiveLink( $indexable->object_sub_type, $indexable->permalink );
			}
			if ( 'term' === $indexable->object_type ) {
				$term                        = apply_filters( 'wpml_object_id', $indexable->object_id, $indexable->object_sub_type, true );
				$indexable->permalink        = self::getTermLink( $term, $indexable->permalink );
				$indexable->breadcrumb_title = Obj::prop( 'name', get_term( $term ) ) ?: $indexable->breadcrumb_title;
			} else {
				$indexable->permalink = apply_filters( 'wpml_permalink', $indexable->permalink );
			}
		}

		return $indexables;
	}

	/**
	 * Translate permalinks.
	 *
	 * @param Indexable_Presention $presentation The indexable presentation.
	 *
	 * @return Indexable_Presention
	 */
	public function translatePermalinks( $presentation ) {
		$newLink      = null;
		$originalLink = Obj::path( [ 'model', 'permalink' ], $presentation );
		$objectType   = Obj::path( [ 'model', 'object_type' ], $presentation );

		if ( 'post' === $objectType ) {
			$newLink = self::getPermalink( $presentation->model->object_id, $originalLink );
		} elseif ( 'term' === $objectType ) {
			$newLink = self::getTermLink( $presentation->model->object_id, $originalLink );
		} elseif ( 'post-type-archive' === $objectType ) {
			$newLink = self::getPostTypeArchiveLink( $presentation->model->object_sub_type, $originalLink );
		}

		if ( $newLink ) {
			return Obj::assocPath( [ 'model', 'permalink' ], $newLink, $presentation );
		}

		return $presentation;
	}

	/**
	 *
	 * @param Indexable_Presention $presentation The indexable presentation.
	 * @param object               $context      The Meta Tags Context.
	 *
	 * @return Indexable_Presention
	 */
	public function setSchemaGraphData( $presentation, $context ) {
		$context->site_url = apply_filters( 'wpml_permalink', $context->site_url );

		if ( Utils::isUsingDomains() && ! empty( $context->company_logo_meta ) ) {
			$translateImg                      = wp_get_attachment_image_src( $context->company_logo_meta['id'], 'full' );
			$context->company_logo_meta['url'] = ! empty( $translateImg[0] ) ? $translateImg[0] : $context->company_logo_meta['url'];
		}

		return $presentation;
	}

	/**
	 * @param \WP_Post|int $post
	 * @param string       $fallback
	 *
	 * @return string
	 */
	private static function getPermalink( $post, $fallback ) {
		return Maybe::fromNullable( get_permalink( $post ) )
			->getOrElse( $fallback );
	}

	/**
	 * @param \WP_Term|int $term
	 * @param string       $fallback
	 *
	 * @return string
	 */
	private static function getTermLink( $term, $fallback ) {
		return Maybe::fromNullable( get_term_link( $term ) )
			->filter( pipe( 'is_wp_error', Logic::not() ) )
			->getOrElse( $fallback );
	}

	/**
	 * @param string $postType
	 * @param string $fallback
	 *
	 * @return string
	 */
	private static function getPostTypeArchiveLink( $postType, $fallback ) {
		return Maybe::fromNullable( get_post_type_archive_link( $postType ) )
			->getOrElse( $fallback );
	}
}