- Implemented StreamInterface, UploadedFileInterface, and UriInterface as per PSR standards. - Added getallheaders function to retrieve HTTP headers in a compatible manner. - Included LICENSE files for ralouphie/getallheaders and symfony/deprecation-contracts. - Introduced function for triggering deprecation notices in Symfony.
247 lines
8.0 KiB
PHP
247 lines
8.0 KiB
PHP
<?php
|
||
/**
|
||
* @package AutoPoly - AI Translation For Polylang (Pro)
|
||
*/
|
||
|
||
/**
|
||
* Handles cloning and translation of taxonomy terms for AI Translation For Polylang.
|
||
*
|
||
* Provides methods to translate taxonomy terms (categories, tags, custom taxonomies)
|
||
* using translation entries, and to assign parent relationships for translated terms.
|
||
*
|
||
* @since 1.0.0
|
||
*/
|
||
class ATFP_Term_Clone {
|
||
|
||
/**
|
||
* Main model for managing languages and translations.
|
||
*
|
||
* @var ATFP_Model
|
||
*/
|
||
private $model;
|
||
|
||
/**
|
||
* Constructor for ATFP_Term_Clone.
|
||
*
|
||
* @since 1.0.0
|
||
*
|
||
* @param ATFP_Settings|ATFP_Admin $polylang Main plugin object containing model and sync references.
|
||
*/
|
||
public function __construct( &$polylang ) {
|
||
$this->model = &$polylang->model;
|
||
}
|
||
|
||
/**
|
||
* Translates a taxonomy term using translation entries.
|
||
*
|
||
* @since 1.0.0
|
||
*
|
||
* @param array $entry Array containing term properties and translation data.
|
||
* @param PLL_Language $target_language Target language object.
|
||
* @return int|WP_Error The translated term ID, or WP_Error on failure.
|
||
*/
|
||
public function translate( array $entry, PLL_Language $target_language ) {
|
||
if ( ! $entry['data'] instanceof Translations ) {
|
||
/* translators: %d is a term ID. */
|
||
return new WP_Error( 'atfp_translate_term_no_translations', sprintf( __( 'The term with ID %d could not be translated.', 'auto-translate-for-polylang' ), (int) $entry['id'] ) );
|
||
}
|
||
|
||
$source_term = get_term( $entry['id'] );
|
||
|
||
if ( ! $source_term instanceof WP_Term ) {
|
||
/* translators: %d is a term ID. */
|
||
return new WP_Error( 'atfp_translate_term_no_source_term', sprintf( __( 'The term with ID %d could not be translated as it doesn\'t exist.', 'auto-translate-for-polylang' ), (int) $entry['id'] ) );
|
||
}
|
||
|
||
$tr_term_name = $this->get_translated_term_name( $source_term, $entry['data'] );
|
||
$tr_term_description = $this->get_translated_term_description( $source_term, $entry['data'] );
|
||
$tr_term_id = $this->model->term->get( $entry['id'], $target_language );
|
||
$tr_term_slug = $this->get_translated_term_slug( $source_term, $entry['data'] );
|
||
|
||
if ( $tr_term_id ) {
|
||
// The translation already exists.
|
||
$args = array();
|
||
// Only update name or description if provided in translations.
|
||
if ( $source_term->name !== $tr_term_name ) {
|
||
$args['name'] = $tr_term_name;
|
||
}
|
||
if ( !empty($source_term->description) && $source_term->description !== $tr_term_description ) {
|
||
$args['description'] = $tr_term_description;
|
||
}
|
||
|
||
$tr_term = $this->model->term->update( $tr_term_id, $args );
|
||
if ( is_wp_error( $tr_term ) ) {
|
||
/* translators: %d is a term ID. */
|
||
return new WP_Error( 'atfp_translate_update_term_failed', sprintf( __( 'The term with ID %d could not be updated.', 'auto-translate-for-polylang' ), (int) $tr_term_id ) );
|
||
}
|
||
} else {
|
||
$args = array(
|
||
'translations' => $this->model->term->get_translations( $source_term->term_id ),
|
||
);
|
||
|
||
if ( !empty( $source_term->description ) ) {
|
||
$args['description'] = $tr_term_description;
|
||
}
|
||
|
||
if ( $tr_term_slug && ! empty( $tr_term_slug ) ) {
|
||
$args['slug'] = $tr_term_slug;
|
||
}
|
||
|
||
$tr_term = $this->model->term->insert( $tr_term_name, $source_term->taxonomy, $target_language, $args );
|
||
if ( is_wp_error( $tr_term ) ) {
|
||
/* translators: %d is a term ID. */
|
||
return new WP_Error( 'atfp_translate_term_failed', sprintf( __( 'The term with ID %d could not be translated.', 'auto-translate-for-polylang' ), (int) $entry['id'] ) );
|
||
}
|
||
$tr_term_id = (int) $tr_term['term_id'];
|
||
}
|
||
|
||
/** @var WP_Term $tr_term */
|
||
$tr_term = get_term( $tr_term_id );
|
||
|
||
/**
|
||
* Fires after a term is saved and its translations are updated.
|
||
*
|
||
* @since 1.0.0
|
||
*
|
||
* @param int $tr_term_id The translated term ID.
|
||
* @param string $taxonomy The taxonomy slug.
|
||
* @param array $translations Array of term translations.
|
||
*/
|
||
do_action( 'atfp_save_term', $tr_term_id, $source_term->taxonomy, $this->model->term->get_translations( $tr_term_id ) );
|
||
|
||
$this->assign_parents( [ $entry['id'] ], $target_language );
|
||
|
||
return $tr_term_id;
|
||
}
|
||
|
||
/**
|
||
* Gets the translated term name, or falls back to the source name.
|
||
*
|
||
* @since 1.0.0
|
||
*
|
||
* @param WP_Term $source_term The source term object.
|
||
* @param Translations $translations Translation data object.
|
||
* @return string The translated name.
|
||
*/
|
||
private function get_translated_term_name( WP_Term $source_term, Translations $translations ) {
|
||
$entry = new Translation_Entry( array( 'singular' => $source_term->name, 'context' => 'name' ) );
|
||
|
||
$translated_entry = $translations->translate_entry( $entry );
|
||
|
||
$translated_text = isset( $translated_entry->translation[0] ) && ! empty( $translated_entry->translation[0] ) ? $translated_entry->translation[0] : $source_term->name;
|
||
|
||
return $translated_text;
|
||
}
|
||
|
||
/**
|
||
* Gets the translated term description, or falls back to the source description.
|
||
*
|
||
* @since 1.0.0
|
||
*
|
||
* @param WP_Term $source_term The source term object.
|
||
* @param Translations $translations Translation data object.
|
||
* @return string The translated description.
|
||
*/
|
||
private function get_translated_term_description( WP_Term $source_term, Translations $translations ) {
|
||
$entry = new Translation_Entry( array( 'singular' => $source_term->description, 'context' => 'description' ) );
|
||
|
||
$translated_entry = $translations->translate_entry( $entry );
|
||
|
||
$translated_text = isset( $translated_entry->translation[0] ) && ! empty( $translated_entry->translation[0] ) ? $translated_entry->translation[0] : '';
|
||
|
||
return $translated_text;
|
||
}
|
||
|
||
/**
|
||
* Gets the translated term slug, or returns an empty string if not available.
|
||
*
|
||
* @since 1.0.0
|
||
*
|
||
* @param WP_Term $source_term The source term object.
|
||
* @param Translations $translations Translation data object.
|
||
* @return string The translated slug.
|
||
*/
|
||
private function get_translated_term_slug( WP_Term $source_term, Translations $translations ) {
|
||
$entry = new Translation_Entry( array( 'singular' => $source_term->slug, 'context' => 'slug' ) );
|
||
|
||
$translated_entry = $translations->translate_entry( $entry );
|
||
|
||
$translated_text = isset( $translated_entry->translation[0] ) && ! empty( $translated_entry->translation[0] ) ? $translated_entry->translation[0] : '';
|
||
|
||
return $translated_text;
|
||
}
|
||
|
||
/**
|
||
* Assigns parent terms to translated terms after import.
|
||
*
|
||
* @since 1.0.0
|
||
*
|
||
* @param int[] $ids Array of source term IDs.
|
||
* @param PLL_Language $target_language Target language object.
|
||
* @return void
|
||
*/
|
||
public function assign_parents( array $ids, PLL_Language $target_language ) {
|
||
// Get the terms with their parents (or 0).
|
||
$terms = get_terms(
|
||
array(
|
||
'include' => $ids,
|
||
'hide_empty' => false,
|
||
'fields' => 'id=>parent',
|
||
)
|
||
);
|
||
|
||
if ( ! is_array( $terms ) ) {
|
||
// No terms with parents.
|
||
return;
|
||
}
|
||
|
||
// ‘id=>parent’ returns an array of numeric strings, so let's cast it into int.
|
||
$terms = array_map( 'intval', array_filter( $terms, 'is_numeric' ) );
|
||
|
||
// Keep only the terms that have a parent.
|
||
$terms = array_filter( $terms );
|
||
|
||
if ( empty( $terms ) ) {
|
||
// No terms with parents.
|
||
return;
|
||
}
|
||
|
||
$tr_ids = array();
|
||
foreach ( $terms as $child => $term_id ) {
|
||
$tr_ids[ $child ] = $this->model->term->get( $child, $target_language->slug );
|
||
}
|
||
$tr_ids = array_filter( $tr_ids );
|
||
|
||
if ( empty( $tr_ids ) ) {
|
||
// No translations.
|
||
return;
|
||
}
|
||
|
||
foreach ( $terms as $child => $term_id ) {
|
||
if ( empty( $tr_ids[ $child ] ) ) {
|
||
// Not translated.
|
||
continue;
|
||
}
|
||
|
||
$tr_parent_term = $this->model->term->get( $term_id, $target_language->slug );
|
||
if ( empty( $tr_parent_term ) ) {
|
||
// The parent term is not translated.
|
||
continue;
|
||
}
|
||
|
||
$tr_term_id = $this->model->term->get( $tr_ids[ $child ], $target_language->slug );
|
||
if ( empty( $tr_term_id ) ) {
|
||
continue;
|
||
}
|
||
|
||
$tr_term = get_term( $tr_term_id );
|
||
if ( ! $tr_term instanceof WP_Term ) {
|
||
continue;
|
||
}
|
||
|
||
// Set term parent for shared slugs.
|
||
$this->model->term->update( $tr_term->term_id, array( 'parent' => $tr_parent_term ) );
|
||
}
|
||
}
|
||
}
|