File "schema.php"

Full Path: /home/exhehbu/www/wp-content/plugins/eventer/front/schema.php
File size: 10.24 KB
MIME-type: text/x-php
Charset: utf-8

<?php
defined('ABSPATH') or die('No script kiddies please!');

/**
 * 
 */
class Eventer_Schema {

	/**
	 * Hold of the Instances Class
	 *
	 * @var array
	 */
	private static $_instance = null;

	/**
	 * Hold for the fetch data
	 *
	 * @var array
	 */
	protected static $_posts = [];

	/**
	 * Set the of the event structucred data
	 *
	 * @see https://developers.google.com/structured-data/rich-snippets/
	 * @var string
	 */
	public $type = 'Event';

	public static function instance() {
		if ( is_null( self::$_instance ) ) {
			self::$_instance = new self;
		}

		return self::$_instance;
	}

	function __construct() {

		$eventer_event_schema = eventer_get_settings('eventer_event_schema');

		if ( 'on' !== $eventer_event_schema ) {
			return false;
		}

		add_action( 'wp_footer', [ $this, 'markup'] );
	}

	public function markup() {
		if ( ! is_singular( 'eventer' ) ) {
			return false;
		}

		global $post;

		$html = $this->get_markup( $post );

		/**
		 * Allows users to filter the markup of JSON-LD
		 *
		 * @param string The HTML for the JSON LD markup
		 */
		$html = apply_filters( 'eventer/json/markup', $html );
		echo $html;
	}

	public function get_markup( $post ) {

		$data = $this->get_data( $post );

		foreach ( $data as $post_id => $_data ) {
			$this->register( $post_id );
		}

		/**
		 * Allows to add or remove the eveneter schema data.
		 */
		$data = apply_filters( "eventer/json/event/data", $data );

		// Strip the post ID indexing before returning
		$data = array_values( $data );

		if ( ! empty( $data ) ) {
			$html[] = '<script type="application/ld+json">';
			$html[] = str_replace( '\/', '/', json_encode( $data ) );
			$html[] = '</script>';
		}

		return ! empty( $html ) ? implode( "\r\n", $html ) : '';
	}

	public function register( $post_id ) {

		if ( $this->exists( $post_id ) ) {
			return self::$_posts[ $id ];
		}

		self::$_posts[ $post_id ] = get_post( $post_id );
		return self::$_posts[ $post_id ];
	}

	private function format_event_dates( $date ) {

		try {
			$datetime = new DateTime( $date, new DateTimeZone( 'UTC' ) );
			return $datetime->format( 'Y-m-d\TH:i:sP' );
		} catch ( Exception $e ) {
			return $date;
		}
	}

	/**
	 * Get All Updated Data For Schema Markup.
	 *
	 * @param  int|WP_Post|null $post The post/event
	 *
	 * @return array
	 */
	public function get_data( $post = null ) {

		if ( is_numeric( $post ) ) {
			$post = get_post( $post );
		}

		// If we don't have a valid post object, skip to the next item
		if ( ! $post instanceof WP_Post ) {
			return false;
		}

		$data = $this->get_default_data( $post );

		if ( empty( $data ) ) {
			return false;
		}

		// Get Post Id From Object
		$post_id = key( $data );

		// Get schema Data From object
		$data = reset( $data );

		$event_start_date = get_post_meta( $post_id, 'eventer_event_start_dt', true);
        $event_end_date = get_post_meta( $post_id, 'eventer_event_end_dt', true);

        $event_end_date = ($event_end_date != '') ? $event_end_date : $event_start_date;

        $data->startDate = $this->format_event_dates( $event_start_date );
		$data->endDate   = $this->format_event_dates( $event_end_date );

		if ( $this->eventer_has_venue( $post_id ) ) {
			$venue_data     = $this->get_venue_data( $post_id );
			$data->location = $venue_data;
		}

		if ( $this->eventer_has_organizer( $post_id ) ) {
			$organizer_data  = $this->get_organizer_data( $post_id );
			$data->organizer = $organizer_data;
		}

		$data->performer = 'Organization';

		$return[ $post_id ] = $data;

		return $return;
	}

	public function get_venue_data( $post_id ) {
		$google_map_api = eventer_get_settings('google_apikey');
		$specific_address = get_post_meta( $post_id, 'eventer_event_specific_venue', true );

		$data = (object) [];

		$data->{'@type'} = 'Place';

		if ( ! empty( $specific_address ) ) {
			$data->name = $specific_address;
		}

		if ( $google_map_api ) {
			$eventer_venue = get_the_terms( $post_id, 'eventer-venue' );
			$venue_name = '';

			if ( empty( $eventer_venue ) || is_wp_error( $eventer_venue ) ) {
				return [];
			}

			foreach ( $eventer_venue as $venue ) {
				$location_address = get_term_meta( $venue->term_id, 'venue_address', true );
				$location_coordinates = get_term_meta( $venue->term_id, 'venue_coordinates', true );
				$address = '';

				if ( $location_address ) {
					$address = $this->geocode( $location_address );
				} elseif ( $location_coordinates ) {
					$address = $this->geocode( explode( ',', $location_coordinates ) );
				}

				if ( $address ) {
					$data->address = [];

					$data->address['@type'] = 'PostalAddress';
					if ( ! empty( $address['meta'] ) ) {
						$data->address['streetAddress'] = $address['meta']['street_number'];
						$data->address['addressLocality'] = $address['meta']['sublocality'];
						$data->address['addressRegion'] = $address['meta']['administrative_area_level_1'];
						$data->address['postalCode'] = $address['meta']['postal_code'];
						$data->address['addressCountry'] = $address['meta']['country'];
					}

					$data->address = (object) array_filter( $data->address );
				}
			}
		}

		return $data;
	}

	public function get_organizer_data( $post_id ) {
		$event_organizer = get_the_terms( $post_id, 'eventer-organizer' );
		$organizer_phone = get_term_meta($event_organizer[0]->term_id, 'organizer_phone', true);
		$organizer_website = get_term_meta($event_organizer[0]->term_id, 'organizer_website', true);

		$data = (object) [];

		$data->{'@type'} = 'Organization';

		$data->{'name'} = $event_organizer[0]->name;

		if ( $organizer_phone ) {
			$data->{'telephone'} = $organizer_phone;
		}

		if ( $organizer_website ) {
			$data->{'url'} = $organizer_website;
			$data->{'sameAs'} = $organizer_website;
		}

		return $data;
	}

	public function eventer_has_organizer( $post_id ) {
		$event_organizer = get_the_terms( $post_id, 'eventer-organizer' );

		if ( empty( $event_organizer ) || is_wp_error( $event_organizer ) ) {
			return false;
		}

		return true;
	}

	public function eventer_has_venue( $post_id ) {
		$eventer_venue = get_the_terms( $post_id, 'eventer-venue' );
		$specific_address = get_post_meta( $post_id, 'eventer_event_specific_venue', true );
		$venue_name = '';

		if ( empty( $eventer_venue ) || is_wp_error( $eventer_venue ) ) {
			return false;
		}

		foreach ( $eventer_venue as $venue ) {
			$location_address = get_term_meta( $venue->term_id, 'venue_address', true );
			$location_coordinates = get_term_meta( $venue->term_id, 'venue_coordinates', true );
			$address = '';

			$venue_name = $venue->name;
			if ( $location_coordinates != '' ) {
				$elocation = $location_coordinates;
			} elseif ( $location_address != '' ) {
				$elocation = $location_address;
			} else {
				$elocation = $venue->name;
			}

			$venue_name = $venue_name;
			break;
		}

		return ($venue_name != '') ? $venue_name : $specific_address;
	}

	public function geocode( $location ) {
		if ( is_array( $location ) ) {
			$latitude = $location[0] ?? null;
			$longitude = $location[1] ?? null;
			if ( ! is_numeric( $latitude ) || ! is_numeric( $longitude ) ) {
				return false;
			}
		} elseif ( ! is_string( $location ) || empty( trim( $location ) ) ) {
			return false;
		}

		$response = $this->client_geocode( $location );
		$address = $this->transform_response( $response );
		return $address;
	}

	protected function client_geocode( $location ) {
		$google_map_api = eventer_get_settings('google_apikey');

		$params = [
			'key' 		=> $google_map_api,
			'language' 	=> 'en',
		];

		if ( is_array( $location ) ) {
			$params['latlng'] = join( ',', array_map( 'floatval', $location ) );
		} else {
			$params['address'] = (string) $location;
		}

		$request = wp_remote_get( sprintf( 'https://maps.googleapis.com/maps/api/geocode/json?%s', http_build_query( $params ) ), [
			'httpversion' => '1.1',
			'sslverify' => false,
		] );

		if ( is_wp_error( $request ) ) {
			return false;
		}

		$response = json_decode( wp_remote_retrieve_body( $request ) );

		if ( ! is_object( $response ) || $response->status !== 'OK' || empty( $response->results ) ) {
			return false;
			// throw new \Exception( sprintf(
			// 	'(%s) %s',
			// 	$response->status ?? 'REQUEST_FAILED',
			// 	$response->error_message ?? 'Geocoding request failed.'
			// ) );
		}

		return $response->results[0];
	}

	protected function transform_response( $response ) {
		$feature = [
			'latitude'  => $response->geometry->location->lat,
			'longitude' => $response->geometry->location->lng,
			'address'   => $response->formatted_address,
			'meta'      => [],
		];

		if ( ! empty( $response->address_components ) ) {
			foreach ( $response->address_components as $component ) {
				if ( empty( $component->types ) ) {
					continue;
				}

				foreach ( $component->types as $component_type ) {
					$feature['meta'][ $component_type ] = $component->long_name;
				}
			}
		}

		return $feature;
	}

	public function get_default_data( $post ) {
		if ( ! $post->ID ) {
			return false;
		}

		// This Stop when the page has already schema markup.
		if ( $this->exists( $post->ID ) ) {
			return false;
		}

		$data = (object) [];

		$data->{'@context'} = 'http://schema.org';

		$data->{'@type'} = $this->type;

		$data->name        = esc_js( get_the_title( $post ) );
		$data->description = esc_js( $this->has_post_excerpt( $post ) );

		if ( has_post_thumbnail( $post ) ) {
			$data->image = wp_get_attachment_url( get_post_thumbnail_id( $post ) );
		}

		$data->url = esc_url_raw( $this->get_link( $post ) );

		$type = strtolower( esc_attr( $this->type ) );

		return [ $post->ID => $data ];
	}

	protected function get_link( $post ) {
		return get_the_permalink( $post );
	}

	function has_post_excerpt( $post ) {
		if ( ! is_numeric( $post ) && ! $post instanceof WP_Post ) {
			$post = get_the_ID();
		}

		if ( is_numeric( $post ) ) {
			$post = WP_Post::get_instance( $post );
		}

		if ( ! $post instanceof WP_Post ) {
			return null;
		}

		$excerpt = has_excerpt( $post->ID )
			? $post->post_excerpt
			: wp_trim_words( $post->post_content );

		return wpautop( $excerpt );
	}

	public function exists( $post ) {
	    if ( is_object( $post ) && isset( $post->ID ) ) {
	        return isset( self::$_posts[ $post->ID ] );
	    } else {
	        // Handle the case where $post is not an object or doesn't have an "ID" property.
	        return false; // or perform an alternative action as needed
	    }
	}
}

Eventer_Schema::instance();