<?php
/**
 * Open Graph
 * 
 * Формирует мета данные по стандарту Open Graph для единичных записей и таксономий.
 *
 * @name Open Graph Builder 
 * @description Generates meta data according to the standard Open Graph
 *
 * @param object $semantic_kernel
 *
 * @author veselka.ua
 * @version 2.0
 *
 * @package veselka_ua/themes
 */

class SeoOpengraph {

	/**
	 * Объект семантического ядра.
	 * @type object
	 */
	private $semantic_kernel;
	/**
	 * Регистр - флаги и данные необходимые для работы.
	 * @type array
	 */
	private $registry;
	/**
	 * Список элементов.
	 * @type array
	 */
	private $list;
	/**
	 * Результат работы.
	 * @type string
	 */
	private $result_set = '';


	public function __construct( &$semantic_kernel = false ) {

		// Флаг инициализации объекта
		$this->registry['load'] = false;
		$this->registry['instance'] = false;

		/**
		 * Объект семантического ядра.
		 */
		if( $semantic_kernel && is_object($semantic_kernel) ) {
			$this->semantic_kernel = $semantic_kernel;
			$this->registry['load'] = true;
		}

		// В крючке вызывается метод генерации мета данных
		add_action( 'wp_head', [$this, 'get_data'], 2, 0 );
	}


//////////////////// Публичные методы ////////////////////


	/**
	 * Обертка для получения результата работы объекта.
	 *
	 * @param void
	 * @return string
	 */
	final public function get_data() {
		if( $this->load() ) {
			$this->construct_og_metadata();
			echo $this->result_set;
		}
	}


//////////////////// Приватные методы ////////////////////


	/**
	 * Инициализация.
	 * 
	 * @param void
	 * @return bool
	 */
	private function load() {
		// Индикатор подключения объекта недвижимости
		if( !$this->registry['load'] ) {
			return false;
		}
		// Если индикатор сущности ложь, объкт не вызывался
		if( $this->registry['instance'] ) {
			return true;
		}
		// Текущее состояние семантического ядра и сбор данных
		$this->semantic_kernel->load();

		// Переменные
		$this->registry['max_images'] = 3; // Facebook принимает не более трех изображений

		// Инициализация завершена
		$this->registry['instance'] = true;
		return true;
	}


	/**
	 * Построение разметки метаданных.
	 * 
	 * @param void
	 * @return void
	 */
	private function construct_og_metadata() {
		// Общие метаданные для всех стрниц
		$this->common_og_construct();
		// Формирование имени метода в зависимости от состояния системы.
		$method_name = $this->semantic_kernel->registry['mode'] . '_og_construct';
		// Вызов соответствующего метода для формирования данных.

		if( method_exists( $this, $method_name ) ) {
			$this->{$method_name}();
		}
		$this->list['description'] = apply_filters('the_content', $this->list['description']);
		$this->list['description'] = strip_tags( strip_shortcodes( $this->list['description'] ) );
		$this->list['description'] = $this->text_shorten( $this->list['description'] );
		// HTML обертка
		$this->og_list_to_html();
	}


	/**
	 * Метаданные для главной страницы.
	 * 
	 * @param void
	 * @return void
	 */
	private function home_og_construct() {
		// Перенаправление
		$this->singular_og_construct();
	}


	/**
	 * Метаданные для единичной страницы/записи.
	 * 
	 * @param void
	 * @return void
	 */
	private function singular_og_construct() {
		$id = $this->semantic_kernel->registry['id'];
		// Массив метаданных
		$this->singular_image_construct();
		// Статья или страница - тип article
		if( in_array($this->semantic_kernel->registry['singular'],['post','page']) ) {
			$this->list['type']			= 'article';
			$this->list['prefix']		= 'http://ogp.me/ns/article#';
			// Дата/время
			$this->list['article:published_time'] = get_the_time( 'c', $id );
			$this->list['article:modified_time'] = get_the_modified_time( 'c', $id );
		}
		if( $this->semantic_kernel->registry['singular'] = 'post' ) {
			// Теги
			$tags = wp_get_object_terms( $id, 'post_tag' );
			if( $tags && is_array( $tags ) ) {
				foreach( $tags as $tag ) {
					$this->list['article:tag'][] = $tag->name;
				}
			}
			// Категории
			$categories = wp_get_object_terms( $id, 'category' );
			if( $categories && is_array($categories) ) {
				$this->list['article:section'][] = current($categories)->name;
			}
		}
		$post = get_post($id);
		$this->list['description']		= $post->post_excerpt;
		if( empty($this->list['description']) ) {
			$this->list['description']	= $post->post_content;
		}
	}


	/**
	 * Метаданные для архивов.
	 * 
	 * @param void
	 * @return void
	 */
	private function archive_og_construct() {
		// Массив метаданных
		$this->archive_image_construct();
		// Описание
		$this->list['description'] = term_description();
		if( $this->list['description'] == '' ) {
			$this->list['description'] = $this->site_description_construct();
		}
		// Архив автора - тип profile
		if( $this->semantic_kernel->registry['archive'] == 'author' ) {
			$user_info = get_userdata($this->semantic_kernel->registry['id']);
			$this->list['type']					= 'profile';
			$this->list['prefix']				= 'http://ogp.me/ns/profile#';
			$this->list['profile:first_name']	= $user_info->first_name;
			$this->list['profile:last_name']	= $user_info->last_name;
			$this->list['profile:username']		= $user_info->user_login;
		}
	}


	/**
	 * Метаданные для неидентифицированных объектов.
	 * 
	 * @param void
	 * @return void
	 */
	private function other_og_construct() {
		// Массив метаданных
		$this->list['image']		=	$this->site_image_construct();
		$this->list['description']	=	$this->site_description_construct();
	}


	/**
	 * Общие метаданные для всех стрниц.
	 * 
	 * @param void
	 * @return void
	 */
	private function common_og_construct() {
		// Массив метаданных
		$this->list['locale']		=	get_locale();
		$this->list['type']			=	'website';
		$this->list['prefix']		=	'http://ogp.me/ns#';
		$this->list['site_name']	=	get_bloginfo('name');
		$this->list['url']			=	$this->semantic_kernel->registry['link'];
		$this->list['title']		=	$this->semantic_kernel->registry['h1'];
	}


//////////////////// Вспомогательные методы ////////////////////


	/**
	 * Текст нужной длинны для описания.
	 * 
	 * @param string $text
	 * @return string
	 */
	private function text_shorten( $text ) {
		$excerpt_length = apply_filters( 'excerpt_length', 55 );
		$excerpt_more = apply_filters( 'excerpt_more', ' [...]' );
		return wp_trim_words( $text, $excerpt_length, $excerpt_more );
	}


	/**
	 * Получение id изобржений для единичной записи.
	 * 
	 * @param void
	 * @return void
	 */
	private function singular_image_construct() {
		// Предустановки
		$id = $this->semantic_kernel->registry['id'];
		$image_ids = [];

		// Миниатюра
		if( function_exists( 'has_post_thumbnail' ) && has_post_thumbnail( $id ) ) {
			$image_ids[] = get_post_thumbnail_id( $id );
		}
		// Список любых добавленных к записи изображений
		$attachments = get_children(
			[
				'post_parent'		=> $id,
				'post_status'		=> 'inherit',
				'post_type'			=> 'attachment',
				'post_mime_type'	=> 'image',
				'order'				=> 'ASC',
				'orderby'			=> 'menu_order ID',
			]
		);
		// Дополнение списка изобажений, прикрепленными
		foreach( $attachments as $attachment ) {
			if( !in_array( $attachment->ID, $image_ids ) ) {
				$image_ids[] = $attachment->ID;
				if( sizeof( $image_ids ) >= $this->registry['max_images'] ) {
					break;
				}
			}
		}
		// Страница изображения
		if( is_attachment() && wp_attachment_is_image() ) {
			$image_ids = [$id];
		}
		// Запись результата
		$this->write_image_urls($image_ids);
	}


	/**
	 * Получение id изобржений для архива.
	 * 
	 * @param void
	 * @return void
	 */
	private function archive_image_construct() {
		// Предустановки
		$image_ids = [];
		// Метаданные
		$term_id = $this->semantic_kernel->registry['id'];
		$tax_data = get_term_meta( $term_id );

		// Миниатюра
		if( isset($tax_data['cat_thumb'][0]) && $tax_data['cat_thumb'][0] != '' ) {
			$image_ids[] = $tax_data['cat_thumb'][0];
		}
		// Галерея
		if( isset($tax_data['cat_gallery'][0]) && $tax_data['cat_gallery'][0] != '' ) {
			$gallery = explode(',',$tax_data['cat_gallery'][0]);
			// Дополнение списка изобажений, прикрепленными
			foreach( $gallery as $attachment ) {
				if( !in_array( $attachment->ID, $image_ids ) ) {
					$image_ids[] = $attachment->ID;
					if( sizeof( $image_ids ) >= $this->registry['max_images'] ) {
						break;
					}
				}
			}
		}
		// Запись результата
		$this->write_image_urls($image_ids);
	}


	/**
	 * Получение метаданных изобржения из иконок.
	 * 
	 * @param void
	 * @return array
	 */
	private function site_image_construct() {
		// Получить иконку заданного размера
		return apply_filters('open_graph_icon_construct', false);
	}


	/**
	 * Запись метаданных изображений.
	 * 
	 * @param void
	 * @return void
	 */
	private function write_image_urls($image_ids=[]) {
		// Ссылки на изображения
		$this->list['image'] = [];
		// Нет идентификаторов, указать иконку
		if( empty($image_ids) ) {
			$this->list['image'] = $this->site_image_construct();
		}
		// Полученмие ссылок на изображения
		foreach( $image_ids as $id ) {
			$thumbnail = wp_get_attachment_image_src( $id, 'full' );
			if( $thumbnail ) {
				$this->list['image'][] = $thumbnail[0];
			}
		}
	}


	/**
	 * Конструктор описания.
	 * 
	 * @param void
	 * @return array
	 */
	private function site_description_construct() {
		// Получить иконку заданного размера
		return $this->list['title'] . '. ' . get_bloginfo('name') . ' - ' . get_bloginfo('description');
	}


	/**
	 * HTML обертка для метаданных.
	 * 
	 * @param void
	 * @return void
	 */
	private function og_list_to_html() {
		$result_set = '';
		// Обертка для метаданных
		foreach( $this->list as $property => $items ) {
			if( !is_array($items) ) {
				$items = (array)$items;
			}
			foreach( $items as $item ) {
				if( !$item || $item == '' ) {
					continue;
				}
				$result_set .= "\t" . '<meta property="og:' . $property . '" content="' . $item . '">' . PHP_EOL;
			}
		}
		// Общая обертка
		if( (bool)$result_set ) {
			$result_set = PHP_EOL . "\t" . '<!-- OG -->' . PHP_EOL . $result_set;
		}
		// Запись результата
		$this->result_set = $result_set;
	}


} //end SeoOpengraph
?>