first commit

This commit is contained in:
2023-09-12 21:41:04 +02:00
commit 3361a7f053
13284 changed files with 2116755 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
<?php
class WPML_Page_Builders_Media_Hooks implements IWPML_Action {
/** @var IWPML_PB_Media_Update_Factory $media_update_factory */
private $media_update_factory;
/** @var string $page_builder_slug */
private $page_builder_slug;
/**
* WPML_Page_Builders_Media_Hooks constructor.
*
* @param IWPML_PB_Media_Update_Factory $media_update_factory
* @param string $page_builder_slug
*/
public function __construct( IWPML_PB_Media_Update_Factory $media_update_factory, $page_builder_slug ) {
$this->media_update_factory = $media_update_factory;
$this->page_builder_slug = $page_builder_slug;
}
public function add_hooks() {
add_filter( 'wpml_pb_get_media_updaters', array( $this, 'add_media_updater' ) );
add_filter( 'wpml_media_content_for_media_usage', array( $this, 'add_package_strings_content' ), 10, 2 );
}
/**
* @param IWPML_PB_Media_Update[] $updaters
*
* @return IWPML_PB_Media_Update[]
*/
public function add_media_updater( $updaters ) {
if ( ! array_key_exists( $this->page_builder_slug, $updaters ) ) {
$updaters[ $this->page_builder_slug ] = $this->media_update_factory->create();
}
return $updaters;
}
/**
* @param string $content
* @param WP_Post $post
*
* @return string
*/
public function add_package_strings_content( $content, $post ) {
$packages = apply_filters( 'wpml_st_get_post_string_packages', array(), $post->ID );
/** @var WPML_Package[] $packages */
foreach ( $packages as $package ) {
$strings = $package->get_package_strings();
foreach ( $strings as $string ) {
$content .= PHP_EOL . $string->value;
}
}
return $content;
}
}

View File

@@ -0,0 +1,116 @@
<?php
class WPML_Page_Builders_Media_Translate {
/** @var WPML_Translation_Element_Factory $element_factory */
private $element_factory;
/** @var WPML_Media_Image_Translate $image_translate */
protected $image_translate;
/** @var array $translated_urls */
protected $translated_urls = array();
/** @var (WP_Post|null)[] $translated_posts */
protected $translated_posts = array();
/** @var array $translated_ids */
private $translated_ids = array();
public function __construct(
WPML_Translation_Element_Factory $element_factory,
WPML_Media_Image_Translate $image_translate
) {
$this->element_factory = $element_factory;
$this->image_translate = $image_translate;
}
/**
* @param string $url
* @param string $lang
* @param string $source_lang
*
* @return string
*/
public function translate_image_url( $url, $lang, $source_lang ) {
$key = $url . $lang . $source_lang;
if ( ! array_key_exists( $key, $this->translated_urls ) ) {
$this->translated_urls[ $key ] = $url;
$attachment_id = $this->image_translate->get_attachment_id_by_url( $url, $source_lang );
if ( $attachment_id ) {
$this->add_translated_id( $attachment_id );
$translated_url = $this->image_translate->get_translated_image_by_url( $url, $source_lang, $lang );
$this->translated_urls[ $key ] = $url;
if ( $translated_url ) {
$this->translated_urls[ $key ] = $translated_url;
}
}
}
return $this->translated_urls[ $key ];
}
/**
* @param int $id
* @param string $lang
*
* @return int
*/
public function translate_id( $id, $lang ) {
if ( (int) $id < 1 ) {
return $id;
}
$this->add_translated_id( $id );
$translated_attachment = $this->get_translated_attachment( $id, $lang );
if ( isset( $translated_attachment->ID ) ) {
return $translated_attachment->ID;
}
return $id;
}
/**
* @param int $id
* @param string $lang
*
* @return WP_Post|null
*/
private function get_translated_attachment( $id, $lang ) {
$key = $id . $lang;
if ( ! array_key_exists( $key, $this->translated_posts ) ) {
$this->translated_posts[ $key ] = null;
$element = $this->element_factory->create_post( $id );
$translation = $element->get_translation( $lang );
if ( $translation ) {
$this->translated_posts[ $key ] = $translation->get_wp_object();
}
}
return $this->translated_posts[ $key ];
}
/** @param int $id */
private function add_translated_id( $id ) {
if ( ! in_array( $id, $this->translated_ids, true ) ) {
$this->translated_ids[] = $id;
}
}
public function reset_translated_ids() {
$this->translated_ids = array();
}
/** @return array */
public function get_translated_ids() {
return $this->translated_ids;
}
}

View File

@@ -0,0 +1,29 @@
<?php
class WPML_Page_Builders_Media_Usage {
/** @var WPML_Page_Builders_Media_Translate $media_translate */
private $media_translate;
/** @var WPML_Media_Usage_Factory $media_usage_factory */
private $media_usage_factory;
public function __construct(
WPML_Page_Builders_Media_Translate $media_translate,
WPML_Media_Usage_Factory $media_usage_factory
) {
$this->media_translate = $media_translate;
$this->media_usage_factory = $media_usage_factory;
}
/** @param int $post_id */
public function update( $post_id ) {
$media_ids = $this->media_translate->get_translated_ids();
foreach ( $media_ids as $media_id ) {
$this->media_usage_factory->create( $media_id )->add_post( $post_id );
}
$this->media_translate->reset_translated_ids();
}
}

View File

@@ -0,0 +1,57 @@
<?php
class WPML_Page_Builders_Update_Media implements IWPML_PB_Media_Update {
/** @var WPML_Page_Builders_Update $pb_update */
private $pb_update;
/** @var WPML_Translation_Element_Factory $element_factory */
private $element_factory;
/** @var IWPML_PB_Media_Nodes_Iterator $node_iterator */
protected $node_iterator;
/** @var WPML_Page_Builders_Media_Usage|null $media_usage */
protected $media_usage;
public function __construct(
WPML_Page_Builders_Update $pb_update,
WPML_Translation_Element_Factory $element_factory,
IWPML_PB_Media_Nodes_Iterator $node_iterator,
WPML_Page_Builders_Media_Usage $media_usage = null
) {
$this->pb_update = $pb_update;
$this->element_factory = $element_factory;
$this->node_iterator = $node_iterator;
$this->media_usage = $media_usage;
}
/**
* @param WP_Post $post
*/
public function translate( $post ) {
$element = $this->element_factory->create_post( $post->ID );
$source_element = $element->get_source_element();
if ( ! $source_element ) {
return;
}
$lang = $element->get_language_code();
$source_lang = $source_element->get_language_code();
$original_post_id = $source_element->get_id();
$converted_data = $this->pb_update->get_converted_data( $post->ID );
if ( ! $converted_data ) {
return;
}
$converted_data = $this->node_iterator->translate( $converted_data, $lang, $source_lang );
$this->pb_update->save( $post->ID, $original_post_id, $converted_data );
if ( $this->media_usage ) {
$this->media_usage->update( $original_post_id );
}
}
}

View File

@@ -0,0 +1,6 @@
<?php
interface IWPML_PB_Media_Nodes_Iterator {
public function translate( $data, $lang, $source_lang );
}

View File

@@ -0,0 +1,7 @@
<?php
interface IWPML_PB_Media_Update_Factory {
/** @return IWPML_PB_Media_Update */
public function create();
}

View File

@@ -0,0 +1,9 @@
<?php
interface IWPML_PB_Media_Update {
/**
* @param WP_Post $post
*/
public function translate( $post );
}

View File

@@ -0,0 +1,55 @@
<?php
class WPML_Page_Builders_Media_Shortcodes_Update_Factory implements IWPML_PB_Media_Update_Factory {
/** @var WPML_PB_Config_Import_Shortcode WPML_PB_Config_Import_Shortcode */
private $page_builder_config_import;
/** @var WPML_Translation_Element_Factory|null $element_factory */
private $element_factory;
/** @var WPML_Page_Builders_Media_Translate|null $media_translate */
private $media_translate;
public function __construct( WPML_PB_Config_Import_Shortcode $page_builder_config_import ) {
$this->page_builder_config_import = $page_builder_config_import;
}
public function create() {
$media_shortcodes = new WPML_Page_Builders_Media_Shortcodes(
$this->get_media_translate(),
$this->page_builder_config_import->get_media_settings()
);
return new WPML_Page_Builders_Media_Shortcodes_Update(
$this->get_element_factory(),
$media_shortcodes,
new WPML_Page_Builders_Media_Usage( $this->get_media_translate(), new WPML_Media_Usage_Factory() )
);
}
/** @return WPML_Translation_Element_Factory */
private function get_element_factory() {
global $sitepress;
if ( ! $this->element_factory ) {
$this->element_factory = new WPML_Translation_Element_Factory( $sitepress );
}
return $this->element_factory;
}
/** @return WPML_Page_Builders_Media_Translate */
private function get_media_translate() {
global $sitepress;
if ( ! $this->media_translate ) {
$this->media_translate = new WPML_Page_Builders_Media_Translate(
$this->get_element_factory(),
new WPML_Media_Image_Translate( $sitepress, new WPML_Media_Attachment_By_URL_Factory() )
);
}
return $this->media_translate;
}
}

View File

@@ -0,0 +1,61 @@
<?php
class WPML_Page_Builders_Media_Shortcodes_Update implements IWPML_PB_Media_Update {
/** @var WPML_Translation_Element_Factory $element_factory */
private $element_factory;
/** @var WPML_Page_Builders_Media_Shortcodes $media_shortcodes*/
private $media_shortcodes;
/** @var WPML_Page_Builders_Media_Usage $media_usage */
private $media_usage;
public function __construct(
WPML_Translation_Element_Factory $element_factory,
WPML_Page_Builders_Media_Shortcodes $media_shortcodes,
WPML_Page_Builders_Media_Usage $media_usage
) {
$this->element_factory = $element_factory;
$this->media_shortcodes = $media_shortcodes;
$this->media_usage = $media_usage;
}
/**
* @param WP_Post $post
*/
public function translate( $post ) {
if ( ! $this->media_shortcodes->has_media_shortcode( $post->post_content ) ) {
return;
}
$element = $this->element_factory->create_post( $post->ID );
if ( ! $element->get_source_language_code() ) {
return;
}
$post->post_content = $this->media_shortcodes->set_target_lang( $element->get_language_code() )
->set_source_lang( $element->get_source_language_code() )
->translate( $post->post_content );
$this->media_usage->update( $element->get_source_element()->get_id() );
/**
* The function wp_update_post() can modify post tag.
* The code below sends tags by IDs to prevent this.
*
* @see wpmlcore-5947
* @see https://core.trac.wordpress.org/ticket/45121
*/
$tag_ids = wp_get_post_tags( $post->ID, array( 'fields' => 'ids' ) );
$postarr = array(
'ID' => $post->ID,
'post_content' => $post->post_content,
'tags_input' => $tag_ids,
);
kses_remove_filters();
wpml_update_escaped_post( $postarr );
kses_init();
}
}

View File

@@ -0,0 +1,170 @@
<?php
class WPML_Page_Builders_Media_Shortcodes {
const TYPE_URL = 'media-url';
const TYPE_IDS = 'media-ids';
/** @var WPML_Page_Builders_Media_Translate $media_translate */
private $media_translate;
/** @var string $target_lang */
private $target_lang;
/** @var string $source_lang */
private $source_lang;
/** @var array $config */
private $config;
public function __construct( WPML_Page_Builders_Media_Translate $media_translate, array $config ) {
$this->media_translate = $media_translate;
$this->config = $config;
}
/**
* @param string $content
*
* @return string
*/
public function translate( $content ) {
foreach ( $this->config as $shortcode ) {
$shortcode = $this->sanitize_shortcode( $shortcode );
$tag_name = isset( $shortcode['tag']['name'] ) ? $shortcode['tag']['name'] : '';
if ( ! empty( $shortcode['attributes'] ) ) {
$content = $this->translate_attributes( $content, $tag_name, $shortcode['attributes'] );
}
if ( ! empty( $shortcode['content'] ) ) {
$content = $this->translate_content( $content, $tag_name, $shortcode['content'] );
}
}
return $content;
}
/**
* @param string $content
*
* @return bool
*/
public function has_media_shortcode( $content ) {
if ( false === strpos( $content, '[' ) ) {
return false;
};
foreach ( $this->config as $shortcode ) {
$shortcode = $this->sanitize_shortcode( $shortcode );
$tag_name = isset( $shortcode['tag']['name'] ) ? $shortcode['tag']['name'] : '';
if ( $tag_name && false !== strpos( $content, '[' . $tag_name ) ) {
return true;
}
}
return false;
}
/**
* @param array $shortcode
*
* @return array
*/
private function sanitize_shortcode( array $shortcode ) {
$defaults = array(
'attributes' => null,
);
return array_merge( $defaults, $shortcode );
}
/**
* @param string $content
* @param string $tag
* @param array $attributes
*
* @return string
*/
private function translate_attributes( $content, $tag, array $attributes ) {
foreach ( $attributes as $attribute => $data ) {
$pattern = '/(\[' . $tag . '(?: [^\]]* | )' . $attribute . '=(?:"|\'))([^"\']*)/';
$type = isset( $data['type'] ) ? $data['type'] : '';
$content = preg_replace_callback( $pattern, array( $this, $this->get_callback( $type ) ), $content );
}
return $content;
}
/**
* @param string $content
* @param string $tag
* @param array $data
*
* @return string
*/
private function translate_content( $content, $tag, array $data ) {
$pattern = '/(\[(?:' . $tag . ')[^\]]*\])([^\[]+)/';
$type = isset( $data['type'] ) ? $data['type'] : '';
return preg_replace_callback( $pattern, array( $this, $this->get_callback( $type ) ), $content );
}
/**
* @param string $type
*
* @return string
*/
private function get_callback( $type ) {
if ( self::TYPE_URL === $type ) {
return 'replace_url_callback';
}
return 'replace_ids_callback';
}
/**
* @param array $matches
*
* @return string
*/
private function replace_url_callback( array $matches ) {
$translated_url = $this->media_translate->translate_image_url( $matches[2], $this->target_lang, $this->source_lang );
return $matches[1] . $translated_url;
}
/**
* @param array $matches
*
* @return string
*/
private function replace_ids_callback( array $matches ) {
$ids = explode( ',', $matches[2] );
foreach ( $ids as &$id ) {
$id = $this->media_translate->translate_id( (int) $id, $this->target_lang );
}
return $matches[1] . implode( ',', $ids );
}
/**
* @param string $target_lang
*
* @return self
*/
public function set_target_lang( $target_lang ) {
$this->target_lang = $target_lang;
return $this;
}
/**
* @param string $source_lang
*
* @return self
*/
public function set_source_lang( $source_lang ) {
$this->source_lang = $source_lang;
return $this;
}
}