Files
doitinpoland.com/wp-content/plugins/sitepress-multilingual-cms/classes/menu-elements/class-wpml-translation-tree.php
2023-09-12 21:41:04 +02:00

276 lines
7.5 KiB
PHP

<?php
/**
* Class WPML_Translation_Tree
*
* @package wpml-core
* @subpackage taxonomy-term-translation
*/
class WPML_Translation_Tree extends WPML_SP_User {
private $taxonomy;
private $tree = array();
private $trid_levels;
private $language_order;
private $term_ids;
/**
* @param SitePress $sitepress
* @param string $element_type
* @param object[] $terms
*/
public function __construct( &$sitepress, $element_type, $terms ) {
if ( ! $terms ) {
throw new InvalidArgumentException( 'No terms to order given given' );
}
parent::__construct( $sitepress );
$this->taxonomy = $element_type;
$this->language_order = $this->get_language_order( $terms );
$this->tree = $this->get_tree_from_terms_array( $terms );
}
/**
* Returns all terms in the translation tree, ordered by hierarchy and as well as alphabetically within a level and/or parent term relationship.
*
* @return array
*/
public function get_alphabetically_ordered_list() {
$root_list = $this->sort_trids_alphabetically( $this->tree );
$ordered_list_flattened = array();
foreach ( $root_list as $root_trid_group ) {
$ordered_list_flattened = $this->get_children_recursively( $root_trid_group, $ordered_list_flattened );
}
return $ordered_list_flattened;
}
/**
* @param array $terms
*
* Generates a tree representation of an array of terms objects
*
* @return array|bool
*/
private function get_tree_from_terms_array( $terms ) {
$trids = $this->generate_trid_groups( $terms );
$trid_tree = $this->parse_tree( $trids, false, 0 );
return $trid_tree;
}
/**
* Groups an array of terms objects by their trid and language_code
*
* @param array<\stdClass> $terms
*
* @return array<int>
*/
private function generate_trid_groups( $terms ) {
$trids = array();
foreach ( $terms as $term ) {
$trids [ $term->trid ] [ $term->language_code ] = array(
'ttid' => $term->term_taxonomy_id,
'parent' => $term->parent,
'term_id' => $term->term_id,
);
if ( isset( $term->name ) ) {
$trids [ $term->trid ] [ $term->language_code ]['name'] = $this->get_unique_term_name( $term->name );
}
$this->term_ids[] = $term->term_id;
}
return $trids;
}
/**
* @param string $name
*
* @return string
*/
private function get_unique_term_name( $name ) {
return uniqid( $name . '-' );
}
/**
* @param array<int> $trids
* @param array|bool|false $root_trid_group
* @param int $level current depth in the tree
* Recursively turns an array of unordered trid objects into a tree.
*
* @return array|bool
*/
private function parse_tree( $trids, $root_trid_group, $level ) {
$return = array();
foreach ( $trids as $trid => $trid_group ) {
if ( $this->is_root( $trid_group, $root_trid_group ) ) {
unset( $trids[ $trid ] );
if ( ! isset( $this->trid_levels[ $trid ] ) ) {
$this->trid_levels[ $trid ] = 0;
}
$this->trid_levels[ $trid ] = max( array( $level, $this->trid_levels[ $trid ] ) );
$return [ $trid ] = array(
'trid' => $trid,
'elements' => $trid_group,
'children' => $this->parse_tree( $trids, $trid_group, $level + 1 ),
);
}
}
return empty( $return ) ? false : $return;
}
/**
* @param array|bool $parent
* @param array $children
* Checks if one trid is the root of another. This is the case if at least one parent child
* relationship between both trids exists.
*
* @return bool
*/
private function is_root( $children, $parent ) {
$root = ! (bool) $parent;
foreach ( $this->language_order as $c_lang ) {
if ( ! isset( $children[ $c_lang ] ) ) {
continue;
}
$child_in_lang = $children[ $c_lang ];
if ( $parent === false ) {
$root = ! ( $child_in_lang['parent'] != 0 || in_array( $child_in_lang['parent'], $this->term_ids ) );
break;
} else {
foreach ( (array) $parent as $p_lang => $parent_in_lang ) {
if ( $c_lang == $p_lang && $child_in_lang['parent'] == $parent_in_lang['term_id'] ) {
$root = true;
break;
}
}
}
}
return $root;
}
private function sort_trids_alphabetically( $trid_groups ) {
$terms_in_trids = array();
$ordered_trids = array();
foreach ( $trid_groups as $trid_group ) {
foreach ( $trid_group['elements'] as $lang => $term ) {
if ( ! isset( $terms_in_trids[ $lang ] ) ) {
$terms_in_trids[ $lang ] = array();
}
$trid = $trid_group['trid'];
$term['trid'] = $trid;
$terms_in_trids[ $lang ][ $trid ][] = $term;
}
}
$sorted = array();
foreach ( $this->language_order as $lang ) {
if ( isset( $terms_in_trids[ $lang ] ) ) {
$terms_in_lang_and_trids = $terms_in_trids[ $lang ];
$term_names = array();
$term_names_numerical = array();
foreach ( $terms_in_lang_and_trids as $trid => $terms_in_lang_and_trid ) {
if ( in_array( $trid, $sorted ) ) {
continue;
}
$term_in_lang_and_trid = array_pop( $terms_in_lang_and_trid );
$term_name = $term_in_lang_and_trid['name'];
$term_names [ $term_name ] = $trid;
$term_names_numerical [] = $term_name;
}
natsort( $term_names_numerical );
foreach ( $term_names_numerical as $name ) {
$ordered_trids [] = $trid_groups[ $term_names[ $name ] ];
$sorted[] = $term_names[ $name ];
}
}
}
return $ordered_trids;
}
/**
* @param array $trid_group
* @param array $existing_list
*
* Reads in a trid array and appends it and its children to the input array.
* This is done in the order parent->alphabetically ordered children -> ( alphabetically ordered children's children) ...
*
* @return array
*/
private function get_children_recursively(
$trid_group,
$existing_list = array()
) {
$children = $trid_group['children'];
unset( $trid_group['children'] );
$existing_list [] = $this->add_level_information_to_terms( $trid_group );
if ( is_array( $children ) ) {
$children = $this->sort_trids_alphabetically( $children );
foreach ( $children as $child ) {
$existing_list = $this->get_children_recursively(
$child,
$existing_list
);
}
}
return $existing_list;
}
/**
* Adds the hierarchical depth as a variable to all terms.
* 0 means, that the term has no parent.
*
* @param array $tridgroup
*
* @return array
*/
private function add_level_information_to_terms( $tridgroup ) {
foreach ( $tridgroup['elements'] as $lang => &$term ) {
$level = 0;
$term_id = $term['term_id'];
while ( ( $term_id = wp_get_term_taxonomy_parent_id( $term_id, $this->taxonomy ) ) ) {
$level ++;
}
$term['level'] = $level;
}
return $tridgroup;
}
/**
* Counts the number of terms per language and returns an array of language codes,
* that is ordered by the number of terms in every language.
*
* @param array $terms
*
* @return array
*/
private function get_language_order( $terms ) {
$langs = array();
$default_lang = $this->sitepress->get_default_language();
foreach ( $terms as $term ) {
$term_lang = $term->language_code;
if ( $term_lang === $default_lang ) {
continue;
}
if ( isset( $langs[ $term_lang ] ) ) {
$langs[ $term_lang ] += 1;
} else {
$langs[ $term_lang ] = 1;
}
}
natsort( $langs );
$return = array_keys( $langs );
$return [] = $default_lang;
$return = array_reverse( $return );
return $return;
}
}