robotstxt-ai-translator/includes/class-ai-translator-mlp-integration.php
2026-05-25 17:12:22 +00:00

174 lines
5.6 KiB
PHP

<?php
/**
* MultilingualPress integration for AI Translator.
*
* When MultilingualPress creates a new connected post (i.e. the editor saves
* a source post and MLP syncs it to another site for the first time), this
* class translates the source post's fields into the target site's language
* and writes the result back to the newly created remote post.
*
* The hook `multilingualpress.metabox_after_update_remote_post` fires while
* WordPress is already switched to the remote site, so wp_update_post() can
* be called directly without an additional switch_to_blog().
*
* This integration only activates when:
* 1. MultilingualPress is active (class_exists guard in bootstrap).
* 2. "Auto-translate on MLP sync" is enabled in the plugin settings.
* 3. An AI provider is configured for text generation.
*
* @package ROBOTSTXT\AI_Translator
* @since 1.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'AI_Translator_MLP_Integration' ) ) {
/**
* Hooks into MultilingualPress post synchronization to auto-translate
* newly connected posts.
*
* @since 1.1.0
*/
class AI_Translator_MLP_Integration {
/**
* Settings handler.
*
* @since 1.1.0
* @var AI_Translator_Settings
*/
private $settings;
/**
* Translator handler.
*
* @since 1.1.0
* @var AI_Translator_Translator
*/
private $translator;
/**
* Constructor.
*
* @since 1.1.0
*
* @param AI_Translator_Settings $settings Settings handler.
* @param AI_Translator_Translator $translator Translator handler.
*/
public function __construct( AI_Translator_Settings $settings, AI_Translator_Translator $translator ) {
$this->settings = $settings;
$this->translator = $translator;
}
/**
* Registers WordPress hooks.
*
* @since 1.1.0
*
* @return void
*/
public function register() {
add_action(
'multilingualpress.metabox_after_update_remote_post',
array( $this, 'on_mlp_after_update_remote_post' ),
10,
3
);
}
/**
* Translates the source post and updates the newly created remote post.
*
* Fires while WordPress is switched to the remote site, so
* wp_update_post() can be called directly.
*
* Only acts when:
* - $operation is 'new' (first connection, not an update).
* - The "auto_translate_on_mlp_create" setting is enabled.
* - An AI provider is configured for text generation.
*
* @since 1.1.0
*
* @param \Inpsyde\MultilingualPress\TranslationUi\Post\RelationshipContext $context MLP relationship context.
* @param array<string,scalar|null> $post Post data used to create the remote post.
* @param string $operation 'new' = first connection, 'leave' = update.
*
* @return void
*/
public function on_mlp_after_update_remote_post( $context, $post, $operation ) {
unset( $post );
if ( 'new' !== $operation ) {
return;
}
$settings = $this->settings->get_settings();
if ( empty( $settings['auto_translate_on_mlp_create'] ) ) {
return;
}
if ( ! $this->translator->is_supported() ) {
return;
}
// We are already on the remote site (MLP switched before firing this hook).
// get_blog_option() with the explicit site ID is safe and avoids relying
// on locale globals that may not be updated after switch_to_blog().
$raw_locale = get_blog_option( $context->remoteSiteId(), 'WPLANG' );
$target_locale = is_string( $raw_locale ) && '' !== $raw_locale ? $raw_locale : 'en_US';
// sourcePost() performs switch_to_blog internally and restores afterward.
$source_post = $context->sourcePost();
if ( ! $source_post instanceof WP_Post ) {
return;
}
$remote_post_id = $context->remotePostId();
$update = array( 'ID' => $remote_post_id );
$has_changes = false;
// ── Translate title ──────────────────────────────────────────────
if ( ! empty( $settings['translate_title'] ) && '' !== trim( $source_post->post_title ) ) {
$translated = $this->translator->translate( $source_post->post_title, $target_locale );
if ( ! is_wp_error( $translated ) && '' !== $translated ) {
$update['post_title'] = $translated;
$has_changes = true;
}
}
// ── Translate content ────────────────────────────────────────────
if ( ! empty( $settings['translate_content'] ) && '' !== trim( $source_post->post_content ) ) {
$translated = $this->translator->translate( $source_post->post_content, $target_locale );
if ( ! is_wp_error( $translated ) && '' !== $translated ) {
$update['post_content'] = $translated;
$has_changes = true;
}
}
// ── Translate excerpt ────────────────────────────────────────────
if ( ! empty( $settings['translate_excerpt'] )
&& '' !== trim( $source_post->post_excerpt )
&& post_type_supports( $source_post->post_type, 'excerpt' )
) {
$translated = $this->translator->translate( $source_post->post_excerpt, $target_locale );
if ( ! is_wp_error( $translated ) && '' !== $translated ) {
$update['post_excerpt'] = $translated;
$has_changes = true;
}
}
if ( $has_changes ) {
// Already on the remote site — no switch_to_blog() needed.
wp_update_post( wp_slash( $update ) );
}
}
}
}