class-wpml-score-hierarchy.php 3.31 KB
<?php

class WPML_Score_Hierarchy {

	private $data  = array();
	private $slugs = array();

	/**
	 * WPML_Score_Hierarchy constructor.
	 *
	 * @param object[] $data_set
	 * @param string[] $slugs
	 */
	public function __construct( $data_set, $slugs ) {
		$this->data  = $data_set;
		$this->slugs = $slugs;
	}

	/**
	 * Array of best matched post_ids. Better matches have a lower index!
	 *
	 * @return int[]
	 */
	public function get_possible_ids_ordered() {
		$pages_with_name = $this->data;
		$slugs           = $this->slugs;
		$parent_slugs    = array_slice( $slugs, 0, - 1 );

		foreach ( $this->data as $key => $page ) {
			if ( $page->parent_name ) {
				$slug_pos     = array_keys( $slugs, $page->post_name, true );
				$par_slug_pos = array_keys( $slugs, $page->parent_name, true );
				if ( (bool) $par_slug_pos !== false
					 && (bool) $slug_pos !== false
				) {
					$remove = true;
					foreach ( $slug_pos as $child_slug_pos ) {
						if ( in_array( $child_slug_pos - 1, $par_slug_pos ) ) {
							$remove = false;
							break;
						}
					}
					if ( $remove === true ) {
						unset( $pages_with_name[ $key ] );
					}
				}
			}
		}
		$related_ids  = array();
		$matching_ids = array();
		foreach ( $pages_with_name as $key => $page ) {
			$correct_slug = end( $slugs );
			if ( $page->post_name === $correct_slug ) {
				if ( $this->is_exactly_matching_all_slugs_in_order( $page ) ) {
					$matching_ids[] = (int) $page->ID;
				} else {
					$related_ids[ $page->ID ] = $this->calculate_score( $parent_slugs, $pages_with_name, $page );
				}
			}
		}

		arsort( $related_ids );
		$related_ids = array_keys( $related_ids );

		return array(
			'matching_ids' => $matching_ids,
			'related_ids'  => $related_ids,
		);
	}

	/**
	 * Get page object by its id.
	 *
	 * @param int $id
	 *
	 * @return false|object
	 */
	private function get_page_by_id( $id ) {
		foreach ( $this->data as $page ) {
			if ( (int) $page->ID === (int) $id ) {
				return $page;
			}
		}

		return false;
	}

	/**
	 * @param string[] $parent_slugs
	 * @param object[] $pages_with_name
	 * @param object   $page
	 *
	 * @return int
	 */
	private function calculate_score( $parent_slugs, $pages_with_name, $page ) {
		$parent_positions = array_keys( $parent_slugs, $page->parent_name, true );
		$new_score        = (bool) $parent_positions === true ? max( $parent_positions ) + 1 : ( $page->post_parent ? - 1 : 0 );
		if ( $page->post_parent ) {
			foreach ( $pages_with_name as $parent ) {
				if ( $parent->ID == $page->post_parent ) {
					$new_score += $this->calculate_score( array_slice( $parent_slugs, 0, count( $parent_slugs ) - 1 ), $pages_with_name, $parent );
					break;
				}
			}
		}

		return $new_score;
	}

	/**
	 * @param object $page
	 *
	 * @return bool
	 */
	private function is_exactly_matching_all_slugs_in_order( $page ) {
		return $this->slugs === $this->get_slugs_for_page( $page );
	}

	/**
	 * @param object $current_page
	 *
	 * @return array
	 */
	private function get_slugs_for_page( $current_page ) {
		$slugs = array();

		while ( $current_page && $current_page->post_name ) {
			$slugs[]      = $current_page->post_name;
			$parent_name  = $current_page->parent_name;
			$current_page = $this->get_page_by_id( $current_page->post_parent );

			if ( ! $current_page && $parent_name ) {
				$slugs[] = $parent_name;
			}
		}

		return array_reverse( $slugs );
	}
}