/home/blackyak/www/wordpress/wp-content/plugins/wp-travel-engine/includes/classes/Core/SEO.php
<?php
/**
 * Main SEO class.
 *
 * @package WPTravelEngine\Core
 * @since 1119-schema-issue
 */

namespace WPTravelEngine\Core;

use WPTravelEngine\Core\Models\Post\Trip;

class SEO {

	public function __construct() {

		add_action( 'display_wte_rich_snippet', array( $this, 'wp_travel_engine_json_ld' ) );
	}

	public static function wp_travel_engine_json_ld( $post_id = false ) {

		/**
		 * Escaped schema values are stored in $get_schemas variable.
		*/
		$get_schemas = self::wp_travel_engine_schema_values( $post_id );

		foreach ( $get_schemas as $schema ) {
			if ( ! empty( $schema ) ) {
				echo '<script type="application/ld+json">';
				echo wp_json_encode( $schema ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped.
				echo '</script>';
			}
		}
	}

	/**
	 * Get the schema values for the trip.
	 *
	 * @param int $post_id
	 * @return array
	 */
	public static function wp_travel_engine_schema_values( $post_id = false ) {
		// Get basic post data.
		$post_data = self::get_post_data( $post_id );
		$post_id   = $post_data['post_id'];

		// Get trip data.
		$trip  = self::get_trip_basic_data( $post_id, $post_data['post'] );
		$costs = self::get_trip_costs( $trip['settings'], $trip['trip_data'] );

		// Build schemas.
		$itinerary      = self::build_itinerary_schema( $trip['settings'] );
		$faq_schema     = self::build_faq_schema( $trip['settings'], $post_id );
		$trip_schema    = self::build_trip_schema( $post_id, $trip, $costs, $post_data['content'], $itinerary );
		$product_schema = self::build_product_schema( $post_id, $trip, $post_data['content'] );

		// Return final schema array.
		return apply_filters(
			'wp_travel_engine_single_trip_all_schema',
			array(
				'faq'     => $faq_schema,
				'trip'    => $trip_schema,
				'product' => $product_schema,
			),
			$post_id,
			$trip['trip_data'],
			$trip['settings']
		);
	}

	/**
	 * Get information about the post.
	 *
	 * @param int $post_id
	 * @return array
	 */
	private static function get_post_data( $post_id ) {
		if ( empty( $post_id ) ) {
			global $post;
			$post_id = $post->ID;
		}
		$post = get_post( $post_id );
		return array(
			'post'    => $post,
			'content' => strip_tags( strip_shortcodes( $post->post_content ) ),
			'post_id' => $post_id,
		);
	}

	/**
	 * Get basic data about the trip.
	 *
	 * @param int    $post_id
	 * @param object $post
	 * @return array
	 */
	private static function get_trip_basic_data( $post_id, $post ) {
		$obj       = \wte_functions(); // Backward compatibility.
		$trip_data = new Trip( $post_id );

		$price = $trip_data->has_sale() ? $trip_data->get_sale_price() : $trip_data->get_price();

		return array(
			'settings'  => get_post_meta( $post_id, 'wp_travel_engine_setting', true ),
			'thumbnail' => has_post_thumbnail( $post_id ) ? get_the_post_thumbnail_url( $post_id, 'wp_travel_engine_single_trip_feat_img_size' ) : '',
			'blog'      => get_bloginfo( 'name' ),
			'url'       => get_bloginfo( 'url' ),
			'trip_url'  => get_permalink( $post_id ),
			'currency'  => $obj->trip_currency_code( $post ),
			'price'     => $obj->trip_price( $post_id ) ?: $price,
			'trip_data' => $trip_data,
		);
	}

	/**
	 * Get the costs of the trip.
	 *
	 * @param array  $settings
	 * @param object $trip_data
	 * @return array
	 */
	private static function get_trip_costs( $settings, $trip_data ) {
		$prev_cost = $trip_data->get_price();
		$cost      = $trip_data->has_sale() ? $trip_data->get_sale_price() : $prev_cost;

		return array(
			'cost'      => $cost,
			'prev_cost' => $prev_cost,
		);
	}

	/**
	 * Build the itinerary schema.
	 *
	 * @param array $settings
	 * @return array
	 */
	private static function build_itinerary_schema( $settings ) {
		if ( empty( $settings['itinerary']['itinerary_title'] ) ) {
			return array();
		}

		$items         = array();
		$arr_keys      = array_keys( $settings['itinerary']['itinerary_title'] );
		$max_itinerary = max( $arr_keys );

		foreach ( $arr_keys as $value ) {
			if ( ! array_key_exists( $value, $settings['itinerary']['itinerary_title'] ) ) {
				continue;
			}

			$title             = $settings['itinerary']['itinerary_title'][ $value ] ?? '';
			$content_itinerary = $settings['itinerary']['itinerary_content_inner'][ $value ] ??
								$settings['itinerary']['itinerary_content'][ $value ] ?? '';

			$content_itinerary = preg_replace( '/<p\b[^>]*>(.*?)<\/p>/i', '', strip_tags( $content_itinerary ) );

			$items[] = array(
				'@type'    => 'ListItem',
				'position' => esc_attr( $value ),
				'item'     => array(
					'@type'       => 'TouristAttraction',
					'name'        => esc_attr( $title ),
					'description' => esc_attr( $content_itinerary ),
				),
			);
		}

		return array(
			'@type'           => 'ItemList',
			'numberOfItems'   => esc_attr( $max_itinerary ),
			'itemListElement' => $items,
		);
	}

	/**
	 * Build the FAQ schema.
	 *
	 * @param array $settings
	 * @param int   $post_id
	 * @return array|null
	 */
	private static function build_faq_schema( $settings, $post_id ) {
		if ( empty( $settings['faq']['faq_title'] ) || ! is_array( $settings['faq']['faq_title'] ) ) {
			return null;
		}

		$faqs = array();
		foreach ( array_keys( $settings['faq']['faq_title'] ) as $value ) {
			$question = $settings['faq']['faq_title'][ $value ] ?? '';
			$answer   = $settings['faq']['faq_content'][ $value ] ?? '';

			$question = preg_replace( '/<p\b[^>]*>(.*?)<\/p>/i', '', strip_tags( $question ) );
			$answer   = preg_replace( '/<p\b[^>]*>(.*?)<\/p>/i', '', strip_tags( $answer ) );

			$faqs[] = array(
				'@type'          => 'Question',
				'name'           => esc_attr( $question ),
				'acceptedAnswer' => array(
					'@type' => 'Answer',
					'text'  => esc_attr( $answer ),
				),
			);
		}

		return apply_filters(
			'wp_travel_engine_faq_schema_array',
			array(
				'@context'   => 'https://schema.org',
				'@type'      => 'FAQPage',
				'mainEntity' => $faqs,
			),
			$post_id,
			$settings
		);
	}

	/**
	 * Build the trip schema.
	 *
	 * @param int    $post_id
	 * @param array  $trip
	 * @param array  $costs
	 * @param string $content
	 * @param array  $itinerary
	 * @return array
	 */
	private static function build_trip_schema( $post_id, $trip, $costs, $content, $itinerary ) {
		return apply_filters(
			'wp_travel_engine_schema_array',
			array(
				'@context'    => 'https://schema.org',
				'@type'       => 'Trip',
				'name'        => get_the_title( $post_id ),
				'description' => esc_html( $content ),
				'image'       => esc_url( $trip['thumbnail'] ),
				'url'         => esc_url( $trip['trip_url'] ),
				'itinerary'   => $itinerary,
				'provider'    => array(
					'@type' => 'Organization',
					'name'  => esc_html( $trip['blog'] ),
					'url'   => esc_url( $trip['url'] ),
				),
				'offers'      => array(
					'@type'     => 'AggregateOffer',
					'highPrice' => esc_html( $costs['prev_cost'] ),
					'lowPrice'  => esc_html( $costs['cost'] ),
					'offers'    => array(
						'@type'           => 'Offer',
						'name'            => esc_html( get_the_title( $post_id ) ),
						'availability'    => 'https://schema.org/InStock',
						'price'           => esc_html( $trip['price'] ),
						'priceCurrency'   => esc_html( $trip['currency'] ) ?: 'USD',
						'priceValidUntil' => '2030-12-31',
						'url'             => esc_url( $trip['trip_url'] ),
					),
				),
			),
			$post_id,
			$trip['settings']
		);
	}

	/**
	 * Build the product schema.
	 *
	 * @param int    $post_id
	 * @param array  $trip
	 * @param string $content
	 * @return array
	 */
	private static function build_product_schema( $post_id, $trip, $content ) {
		return apply_filters(
			'wp_travel_engine_single_trip_product_schema',
			array(
				'@context'    => 'https://schema.org',
				'@type'       => 'Product',
				'name'        => esc_html( get_the_title( $post_id ) ),
				'description' => esc_html( $content ),
				'image'       => esc_url( $trip['thumbnail'] ),
				'url'         => esc_url( $trip['trip_url'] ),
				'brand'       => array(
					'@type' => 'Brand',
					'name'  => esc_html( get_the_title( $post_id ) ),
				),
				'offers'      => array(
					'@type'           => 'Offer',
					'url'             => esc_url( $trip['trip_url'] ),
					'price'           => esc_html( $trip['price'] ),
					'priceCurrency'   => esc_html( $trip['currency'] ) ?: 'USD',
					'availability'    => 'https://schema.org/InStock',
					'priceValidUntil' => '2030-12-31',
				),
			),
			$post_id,
			$trip['trip_data'],
			$trip['settings']
		);
	}
}