HEX
Server: Apache
System: Linux digivps 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC 2025 x86_64
User: root (0)
PHP: 8.3.15
Disabled: passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv
Upload Files
File: /www/wwwroot/biographybirthday.com/wp-content/plugins/term-management-tools/classes/class-WPML.php
<?php

namespace CNMD\TMT;

/**
 * Class WPML
 *
 * Adds WPML support.
 *
 * Currently supports "Change Taxonomy" only.
 *
 * @package CNMD\TMT
 */
class WPML extends Base {

	private $site_languages = array();
	private $translation_records;


	/**
	 * WPML constructor.
	 */
	public function __construct() { }


	/**
	 * If WPML is active, then set it up do the right thing..
	 *
	 * @codeCoverageIgnore
	 */
	public function init() {
		$this->set_hooks();
	}


	/**
	 * Adds the required hooks.
	 *
	 * @codeCoverageIgnore
	 */
	private function set_hooks() {
		/*
		 * Add the term IDs for the translations for the user-selected terms.
		 */
		add_filter(
			'term_management_tools_changed_taxonomy__terms_and_child_terms',
			array(
				$this,
				'add_translated_terms_to_supplied_list',
			),
			10,
			3
		);

		/*
		 * Adjust the parentage resetsRelink the translations
		 */
		add_action(
			'term_management_tools_changed_taxonomy__reset_parent_for',
			array( $this, 'adjust_parentage' ),
			10,
			3
		);

		/*
		 * Relink the translations
		 */
		add_action(
			'term_management_tools_term_changed_taxonomy',
			array( $this, 'relink_translations_after_move' ),
			10,
			3
		);
	}


	/**
	 * Adds the translations' term IDs to the list of terms to move, and creates the translation linkages record.
	 *
	 * When the list of terms is supplied to this method, we know that this list of terms contains two things.
	 * 1. The list of terms manually selected by the user
	 * 2. Any child terms of the manually selected ones
	 *
	 * What it doesn't have is any of the translations' term IDs, or their children. We'll do that here.
	 *
	 * @param        $term_ids
	 * @param string $new_taxonomy   The target taxonomy.
	 * @param string $old_taxonomy   The source taxonomy.
	 *
	 * @return array
	 */
	public function add_translated_terms_to_supplied_list( $term_ids, string $new_taxonomy, string $old_taxonomy ) : array {

		// If this is not a translatable taxonomy, we don't need to do any of this.
		if ( ! $this->is_taxonomy_translatable( $old_taxonomy ) ) {
			return $term_ids;
		}

		$this->store_translation_records( $old_taxonomy );

		global $sitepress;
		// The language active in the admin when the terms were manually selected
		$active_lang = $sitepress->get_current_language();

		$all_terms_including_translations = array();
		foreach ( $this->get_site_languages() as $current_lang ) {
			// This is the key to how i works. This switches the site into each of the registered languages, which
			// makes all calls relative to this lang only, which is what we want.
			$sitepress->switch_lang( $current_lang );

			// This is retrieved for the current lang after the switch.
			$term_hierarchy                                   = $this->get_term_hierarchy( $old_taxonomy );
			$current_term_and_all_child_terms_in_current_lang = array();

			foreach ( $term_ids as $current_term ) {
				// Since we are going through each language, and since $current_term is the term ID in a single language
				// that may or may not be the site default language, we first need to get this term in the current lang.
				$current_term_id_in_current_lang = (int) apply_filters( 'wpml_object_id', $current_term, $old_taxonomy, false, $current_lang );
				if ( 0 === $current_term_id_in_current_lang ) {
					// This happens when a $current_lang translation does not exist for $current_term.
					continue;
				}
				// Get all of the children for $current_term_id_in_current_lang. You might think that $term_ids would
				// contain all the children already and so we only need to store each $current_term_and_all_child_terms_in_current_lang,
				// but there are cases where a term exists as an untranslated child in a language other than the one
				// active in the admin at the time they were manually selected. So we have to get all children manually
				// for all terms in all languages,
				$current_term_and_all_child_terms_in_current_lang   = array_merge( $current_term_and_all_child_terms_in_current_lang, $this->get_all_child_terms_for( $current_term_id_in_current_lang, $old_taxonomy, $term_hierarchy ) );
				$current_term_and_all_child_terms_in_current_lang[] = $current_term_id_in_current_lang;
			}
			// Clean out any dupes, because there almost always is.
			$current_term_and_all_child_terms_in_current_lang = array_unique( $current_term_and_all_child_terms_in_current_lang );

			// With the translation linkages done, we build up the array of simple term IDs.
			$all_terms_including_translations = array_merge( $all_terms_including_translations, $current_term_and_all_child_terms_in_current_lang );
		}
		// With all that done, switch back to whatever language was active in the admin.
		$sitepress->switch_lang( $active_lang );
		// return a unique array of ints, which is the full list of all terms in all languages to be moved.
		return array_unique( array_map( 'absint', $all_terms_including_translations ) );
	}


	/**
	 * If the from and to tax are both hierarchical, then we want to reset the parentage for terms, but only the
	 * top-most terms in our list. So if any term has a parent, and that parent is not also being moved, it should
	 * be reset to 0 (none).
	 *
	 * This is called via term_management_tools_changed_taxonomy__reset_parent_for filter
	 *
	 * @param array  $all_term_ids
	 * @param string $hierarchy
	 * @param array  $terms_to_reset_parentage_for
	 *
	 * @return array
	 */
	public function adjust_parentage( array $terms_to_reset_parentage_for, array $all_term_ids, string $hierarchy ) : array {
		global $sitepress;
		// The language active in the admin when the terms were manually selected
		$active_lang = $sitepress->get_current_language();

		// We build these up from scratch, so no need to keep what was sent
		$terms_to_reset_parentage_for = array();
		foreach ( $this->get_site_languages() as $current_lang ) {
			// This is the key to how i works. This switches the site into each of the registered languages, which
			// makes all calls relative to this lang only, which is what we want.
			$sitepress->switch_lang( $current_lang );

			// This is retrieved for the current lang after the switch.
			$term_hierarchy                                   = $this->get_term_hierarchy( $hierarchy );
			$current_term_and_all_child_terms_in_current_lang = array();

			foreach ( $all_term_ids as $term_id ) {
				$parent_term_id = (int) $this->get_parent_term_id( $term_id, $term_hierarchy );
				if ( $parent_term_id && ! in_array( $parent_term_id, $all_term_ids, true ) ) {
					$terms_to_reset_parentage_for[] = $term_id;

				}
			}
		}
		$sitepress->switch_lang( $active_lang );
		return $terms_to_reset_parentage_for;
	}


	/**
	 * Relink the moved terms to their translations.
	 *
	 * @param string $term_ids       CSV list of term IDs to move.
	 * @param string $new_taxonomy   The target taxonomy.
	 * @param string $old_taxonomy   The source taxonomy.
	 */
	public function relink_translations_after_move( $term_ids, string $new_taxonomy, string $old_taxonomy ) {
		$wpml_element_type     = apply_filters( 'wpml_element_type', $new_taxonomy );
		$wpml_parent_term_info = array();
		$terms_to_relink       = explode( ',', $term_ids );
		foreach ( $terms_to_relink as $term_to_relink ) {
			$translation_record = $this->get_translation_record( (int) $term_to_relink );
			if ( isset( $translation_record ) ) {
				// We have a translation
				$set_translation_args = array(
					'element_id'           => $translation_record->element_id,
					'element_type'         => $wpml_element_type,
					'trid'                 => $translation_record->trid,
					'language_code'        => $translation_record->language_code,
					'source_language_code' => $translation_record->source_language_code,
				);
				do_action( 'wpml_set_element_language_details', $set_translation_args );
			}
		}
	}


	/**
	 * Get an array of all active site languages.
	 *
	 * @return array
	 */
	private function get_site_languages() : array {
		if ( empty( $this->site_languages ) ) {
			$langs = apply_filters( 'wpml_active_languages', null, 'orderby=id&order=desc' );
			if ( isset( $langs ) ) {
				$this->site_languages = $langs;
			}
		}
		return wp_list_pluck( $this->site_languages, 'code' );
	}


	/**
	 * Build the stored translation records by pulling them directly from the database.
	 *
	 * @param string $taxonomy
	 *
	 * @return bool
	 */
	private function store_translation_records( string $taxonomy ) : bool {
		global $wpdb;
		$wpml_taxonomy             = apply_filters( 'wpml_element_type', $taxonomy );
		$this->translation_records = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}icl_translations WHERE element_type = %s",
				$wpml_taxonomy
			)
		);
		if ( $this->translation_records ) {
			return true;
		}
		return false;
	}

	/**
	 * Get the translation record for the supplied term.
	 *
	 * @param int $term_id
	 *
	 * @return object|null
	 */
	private function get_translation_record( int $term_id ) :? object {
		foreach ( $this->translation_records as $link_record ) {
			if ( $term_id === (int) $link_record->element_id ) {
				return $link_record;
			}
		}
		return null;
	}


	/**
	 * Determine if the supplied taxonomy has been set to be translatable.
	 *
	 * @src https://wpml.org/wpml-hook/wpml_sub_setting/
	 *
	 * @param string $taxonomy  Taxonomy id.
	 *
	 * @return bool             true if it is translatable, false otherwise.
	 */
	private function is_taxonomy_translatable( string $taxonomy ) : bool {
		return (bool) apply_filters( 'wpml_sub_setting', false, 'taxonomies_sync_option', $taxonomy );
	}


}