first commit
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Batch_Url_Translation
|
||||
*/
|
||||
abstract class WPML_Media_Batch_Url_Translation {
|
||||
|
||||
const BATCH_SIZE = 10;
|
||||
|
||||
const BATCH_SIZE_FACTOR_ALL_MEDIA = 1;
|
||||
const BATCH_SIZE_FACTOR_SPECIFIC_MEDIA = 10;
|
||||
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
protected $wpdb;
|
||||
|
||||
/**
|
||||
* WPML_Media_Batch_Url_Translation constructor.
|
||||
*
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( wpdb $wpdb ) {
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wp_ajax_' . $this->get_ajax_action(), array( $this, 'run_batch' ) );
|
||||
}
|
||||
|
||||
public function run_batch() {
|
||||
$offset = isset( $_POST['offset'] ) ? (int) $_POST['offset'] : 0;
|
||||
$attachment_id = isset( $_POST['attachment_id'] ) ? (int) $_POST['attachment_id'] : 0;
|
||||
$all_media = ! empty( $_POST['global'] );
|
||||
|
||||
if ( $all_media ) {
|
||||
$number_of_elements_left = $this->process_batch( $offset );
|
||||
} else {
|
||||
$number_of_elements_left = $this->process_batch_for_selected_media( $offset, $attachment_id );
|
||||
}
|
||||
$batch_size_factor = $all_media ? self::BATCH_SIZE_FACTOR_ALL_MEDIA : self::BATCH_SIZE_FACTOR_SPECIFIC_MEDIA;
|
||||
$response = array(
|
||||
'offset' => $offset + $this->get_batch_size( $batch_size_factor ),
|
||||
'continue' => (int) ( $number_of_elements_left > 0 ),
|
||||
'message' => $this->get_response_message( $number_of_elements_left ),
|
||||
);
|
||||
|
||||
wp_send_json_success( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $number_of_elements_left
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_response_message( $number_of_elements_left );
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract protected function process_batch( $offset );
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @param int $attachment_id
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
abstract protected function process_batch_for_selected_media( $offset, $attachment_id );
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function get_ajax_error_message();
|
||||
|
||||
/**
|
||||
* @param int $batch_size_factor
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_batch_size( $batch_size_factor = self::BATCH_SIZE_FACTOR_ALL_MEDIA ) {
|
||||
return $batch_size_factor * self::BATCH_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_ajax_action();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Custom_Field_Batch_Url_Translation_Factory
|
||||
*/
|
||||
class WPML_Media_Custom_Field_Batch_Url_Translation_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
if ( WPML_Media_Custom_Field_Batch_Url_Translation::is_ajax_request() ) {
|
||||
|
||||
$translatable_custom_fields = $sitepress->get_custom_fields_translation_settings(
|
||||
$sitepress->get_wp_api()->constant( 'WPML_TRANSLATE_CUSTOM_FIELD' )
|
||||
);
|
||||
|
||||
$custom_field_images_translation_factory = new WPML_Media_Custom_Field_Images_Translation_Factory();
|
||||
|
||||
return new WPML_Media_Custom_Field_Batch_Url_Translation(
|
||||
$custom_field_images_translation_factory->create(),
|
||||
$wpdb,
|
||||
$translatable_custom_fields
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Custom_Field_Batch_Url_Translation
|
||||
*/
|
||||
class WPML_Media_Custom_Field_Batch_Url_Translation extends WPML_Media_Batch_Url_Translation implements IWPML_Action {
|
||||
|
||||
const AJAX_ACTION = 'wpml_media_translate_media_url_in_custom_fields';
|
||||
|
||||
/**
|
||||
* @var WPML_Media_Custom_Field_Images_Translation
|
||||
*/
|
||||
private $custom_field_translation;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $translatable_custom_fields;
|
||||
|
||||
/**
|
||||
* WPML_Media_Custom_Field_Batch_Url_Translation constructor.
|
||||
*
|
||||
* @param WPML_Media_Custom_Field_Images_Translation $custom_field_translation
|
||||
* @param wpdb $wpdb
|
||||
* @param array $translatable_custom_fields
|
||||
*/
|
||||
public function __construct(
|
||||
WPML_Media_Custom_Field_Images_Translation $custom_field_translation,
|
||||
wpdb $wpdb,
|
||||
array $translatable_custom_fields
|
||||
) {
|
||||
parent::__construct( $wpdb );
|
||||
$this->custom_field_translation = $custom_field_translation;
|
||||
$this->translatable_custom_fields = $translatable_custom_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_ajax_action() {
|
||||
return self::AJAX_ACTION;
|
||||
}
|
||||
|
||||
public static function is_ajax_request() {
|
||||
return isset( $_POST['action'] ) && self::AJAX_ACTION === $_POST['action'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $number_of_custom_fields_left
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_response_message( $number_of_custom_fields_left ) {
|
||||
return sprintf(
|
||||
__( 'Translating media urls in custom field translations: %s', 'wpml-media' ),
|
||||
$number_of_custom_fields_left > 0 ?
|
||||
sprintf( __( '%d left', 'wpml-media' ), $number_of_custom_fields_left ) :
|
||||
__( 'done!', 'wpml-media' )
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_ajax_error_message() {
|
||||
return array(
|
||||
'key' => 'wpml_media_batch_urls_update_error_custom_fields',
|
||||
'value' => esc_js( __( 'Translating media urls in custom fields translations failed: Please try again (%s)', 'wpml-media' ) ),
|
||||
);
|
||||
}
|
||||
|
||||
protected function process_batch( $offset ) {
|
||||
|
||||
if ( $this->translatable_custom_fields ) {
|
||||
$translatable_custom_fields_where_in = wpml_prepare_in( $this->translatable_custom_fields );
|
||||
$custom_fields = $this->wpdb->get_results(
|
||||
"
|
||||
SELECT SQL_CALC_FOUND_ROWS t.element_id AS post_id, p.meta_id, p.meta_key, p.meta_value
|
||||
FROM {$this->wpdb->prefix}icl_translations t
|
||||
JOIN {$this->wpdb->prefix}postmeta p ON t.element_id = p.post_id
|
||||
WHERE t.element_type LIKE 'post_%'
|
||||
AND t.element_type <> 'post_attachment'
|
||||
AND t.source_language_code IS NULL
|
||||
AND p.meta_key IN ({$translatable_custom_fields_where_in})
|
||||
ORDER BY t.element_id ASC
|
||||
LIMIT {$offset}, " . self::BATCH_SIZE
|
||||
);
|
||||
|
||||
$number_of_all_custom_fields = (int) $this->wpdb->get_var( 'SELECT FOUND_ROWS()' );
|
||||
|
||||
foreach ( $custom_fields as $custom_field ) {
|
||||
$this->custom_field_translation->translate_images(
|
||||
$custom_field->meta_id,
|
||||
$custom_field->post_id,
|
||||
$custom_field->meta_key,
|
||||
$custom_field->meta_value
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$number_of_all_custom_fields = 0;
|
||||
}
|
||||
|
||||
return $number_of_all_custom_fields - $offset - self::BATCH_SIZE;
|
||||
}
|
||||
|
||||
protected function process_batch_for_selected_media( $offset, $attachment_id ) {
|
||||
$media_url = wpml_like_escape( wp_get_attachment_url( $attachment_id ) );
|
||||
if ( ! $media_url ) {
|
||||
return 0;
|
||||
}
|
||||
preg_match( '/(.+)\.([a-z]+)$/', $media_url, $match );
|
||||
$media_url_no_extension = wpml_like_escape( $match[1] );
|
||||
$extension = wpml_like_escape( $match[2] );
|
||||
|
||||
$batch_size = $this->get_batch_size( parent::BATCH_SIZE_FACTOR_SPECIFIC_MEDIA );
|
||||
if ( $this->translatable_custom_fields ) {
|
||||
$translatable_custom_fields_where_in = wpml_prepare_in( $this->translatable_custom_fields );
|
||||
$custom_fields = $this->wpdb->get_results(
|
||||
"
|
||||
SELECT SQL_CALC_FOUND_ROWS t.element_id AS post_id, p.meta_id, p.meta_key, p.meta_value
|
||||
FROM {$this->wpdb->prefix}icl_translations t
|
||||
JOIN {$this->wpdb->prefix}postmeta p ON t.element_id = p.post_id
|
||||
WHERE t.element_type LIKE 'post_%'
|
||||
AND t.element_type <> 'post_attachment'
|
||||
AND t.source_language_code IS NULL
|
||||
AND p.meta_key IN ({$translatable_custom_fields_where_in})
|
||||
AND (
|
||||
p.meta_value LIKE '%{$media_url}%' OR
|
||||
p.meta_value LIKE '%{$media_url_no_extension}-%x%.{$extension}%'
|
||||
)
|
||||
ORDER BY t.element_id ASC
|
||||
LIMIT {$offset}, " . $batch_size
|
||||
);
|
||||
|
||||
$number_of_all_custom_fields = (int) $this->wpdb->get_var( 'SELECT FOUND_ROWS()' );
|
||||
|
||||
foreach ( $custom_fields as $custom_field ) {
|
||||
$this->custom_field_translation->translate_images(
|
||||
$custom_field->meta_id,
|
||||
$custom_field->post_id,
|
||||
$custom_field->meta_key,
|
||||
$custom_field->meta_value
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$number_of_all_custom_fields = 0;
|
||||
}
|
||||
|
||||
return $number_of_all_custom_fields - $offset - $batch_size;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Post_Batch_Url_Translation_Factory
|
||||
*/
|
||||
class WPML_Media_Post_Batch_Url_Translation_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $wpdb;
|
||||
|
||||
if ( WPML_Media_Post_Batch_Url_Translation::is_ajax_request() ) {
|
||||
$post_images_translation_factory = new WPML_Media_Post_Images_Translation_Factory();
|
||||
|
||||
return new WPML_Media_Post_Batch_Url_Translation( $post_images_translation_factory->create(), $wpdb );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Post_Batch_Url_Translation
|
||||
*/
|
||||
class WPML_Media_Post_Batch_Url_Translation extends WPML_Media_Batch_Url_Translation implements IWPML_Action {
|
||||
|
||||
const AJAX_ACTION = 'wpml_media_translate_media_url_in_posts';
|
||||
|
||||
/**
|
||||
* @var WPML_Media_Post_Images_Translation
|
||||
*/
|
||||
private $post_image_translation;
|
||||
|
||||
/**
|
||||
* WPML_Media_Post_Batch_Url_Translation constructor.
|
||||
*
|
||||
* @param WPML_Media_Post_Images_Translation $post_image_translation
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( WPML_Media_Post_Images_Translation $post_image_translation, wpdb $wpdb ) {
|
||||
parent::__construct( $wpdb );
|
||||
$this->post_image_translation = $post_image_translation;
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_ajax_action() {
|
||||
return self::AJAX_ACTION;
|
||||
}
|
||||
|
||||
public static function is_ajax_request() {
|
||||
return isset( $_POST['action'] ) && self::AJAX_ACTION === $_POST['action'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $number_of_posts_left
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_response_message( $number_of_posts_left ) {
|
||||
return sprintf(
|
||||
__( 'Translating media urls in post translations: %s', 'wpml-media' ),
|
||||
$number_of_posts_left > 0 ?
|
||||
sprintf( __( '%d left', 'wpml-media' ), $number_of_posts_left ) :
|
||||
__( 'done!', 'wpml-media' )
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_ajax_error_message() {
|
||||
return array(
|
||||
'key' => 'wpml_media_batch_urls_update_errors_posts',
|
||||
'value' => esc_js( __( 'Translating media urls in posts translations failed: Please try again (%s)', 'wpml-media' ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function process_batch( $offset ) {
|
||||
|
||||
$posts = $this->wpdb->get_col( "
|
||||
SELECT SQL_CALC_FOUND_ROWS element_id AS id
|
||||
FROM {$this->wpdb->prefix}icl_translations
|
||||
WHERE element_type LIKE 'post_%'
|
||||
AND element_type <> 'post_attachment'
|
||||
AND source_language_code IS NULL
|
||||
ORDER BY element_id ASC
|
||||
LIMIT {$offset}, " . self::BATCH_SIZE );
|
||||
|
||||
$number_of_all_posts = (int) $this->wpdb->get_var( "SELECT FOUND_ROWS()" );
|
||||
|
||||
foreach ( $posts as $post_id ) {
|
||||
$this->post_image_translation->translate_images( $post_id );
|
||||
}
|
||||
|
||||
return $number_of_all_posts - $offset - self::BATCH_SIZE;
|
||||
}
|
||||
|
||||
protected function process_batch_for_selected_media( $offset, $attachment_id ) {
|
||||
$media_url = wpml_like_escape( wp_get_attachment_url( $attachment_id ) );
|
||||
if ( ! $media_url ) {
|
||||
return 0;
|
||||
}
|
||||
preg_match( "/(.+)\.([a-z]+)$/", $media_url, $match );
|
||||
$media_url_no_extension = wpml_like_escape( $match[1] );
|
||||
$extension = wpml_like_escape( $match[2] );
|
||||
|
||||
$batch_size = $this->get_batch_size( parent::BATCH_SIZE_FACTOR_SPECIFIC_MEDIA );
|
||||
|
||||
$posts = $this->wpdb->get_col( "
|
||||
SELECT SQL_CALC_FOUND_ROWS element_id AS id
|
||||
FROM {$this->wpdb->prefix}icl_translations t
|
||||
JOIN {$this->wpdb->posts} p ON t.element_id = p.ID
|
||||
WHERE element_type LIKE 'post_%'
|
||||
AND element_type <> 'post_attachment'
|
||||
AND source_language_code IS NULL
|
||||
AND (
|
||||
post_content LIKE '%{$media_url}%' OR
|
||||
post_content LIKE '%{$media_url_no_extension}-%x%.{$extension}%'
|
||||
)
|
||||
ORDER BY element_id ASC
|
||||
LIMIT {$offset}, " . $batch_size );
|
||||
|
||||
$number_of_all_posts = (int) $this->wpdb->get_var( "SELECT FOUND_ROWS()" );
|
||||
|
||||
foreach ( $posts as $post_id ) {
|
||||
$this->post_image_translation->translate_images( $post_id );
|
||||
}
|
||||
|
||||
return $number_of_all_posts - $offset - $batch_size;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_String_Batch_Url_Translation
|
||||
*/
|
||||
class WPML_Media_String_Batch_Url_Translation_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $wpdb;
|
||||
|
||||
if ( WPML_Media_String_Batch_Url_Translation::is_ajax_request() ) {
|
||||
$string_factory = new WPML_ST_String_Factory( $wpdb );
|
||||
|
||||
return new WPML_Media_String_Batch_Url_Translation( $wpdb, $string_factory );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_String_Batch_Url_Translation
|
||||
*/
|
||||
class WPML_Media_String_Batch_Url_Translation extends WPML_Media_Batch_Url_Translation implements IWPML_Action {
|
||||
|
||||
const BATCH_SIZE = 500;
|
||||
const AJAX_ACTION = 'wpml_media_translate_media_url_in_strings';
|
||||
|
||||
/**
|
||||
* @var WPML_ST_String_Factory
|
||||
*/
|
||||
private $string_factory;
|
||||
|
||||
/**
|
||||
* WPML_Media_String_Batch_Url_Translation constructor.
|
||||
*
|
||||
* @param wpdb $wpdb
|
||||
* @param WPML_ST_String_Factory $string_factory
|
||||
*/
|
||||
public function __construct(
|
||||
wpdb $wpdb,
|
||||
WPML_ST_String_Factory $string_factory
|
||||
) {
|
||||
parent::__construct( $wpdb );
|
||||
$this->string_factory = $string_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $batch_size_factor
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_batch_size( $batch_size_factor = self::BATCH_SIZE_FACTOR_ALL_MEDIA ) {
|
||||
return $batch_size_factor * self::BATCH_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_ajax_action() {
|
||||
return self::AJAX_ACTION;
|
||||
}
|
||||
|
||||
public static function is_ajax_request() {
|
||||
return isset( $_POST['action'] ) && self::AJAX_ACTION === $_POST['action'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $number_of_strings_left
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_response_message( $number_of_strings_left ) {
|
||||
return sprintf(
|
||||
__( 'Translating media urls in string translations: %s', 'wpml-media' ),
|
||||
$number_of_strings_left > 0 ?
|
||||
sprintf( __( '%d left', 'wpml-media' ), $number_of_strings_left ) :
|
||||
__( 'done!', 'wpml-media' )
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_ajax_error_message() {
|
||||
return array(
|
||||
'key' => 'wpml_media_batch_urls_update_error_strings',
|
||||
'value' => esc_js( __( 'Translating media urls in string translations failed: Please try again (%s)', 'wpml-media' ) ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function process_batch( $offset ) {
|
||||
|
||||
$original_strings = $this->wpdb->get_col(
|
||||
"
|
||||
SELECT SQL_CALC_FOUND_ROWS id, language
|
||||
FROM {$this->wpdb->prefix}icl_strings
|
||||
ORDER BY id ASC
|
||||
LIMIT {$offset}, " . self::BATCH_SIZE
|
||||
);
|
||||
|
||||
$number_of_all_strings = (int) $this->wpdb->get_var( 'SELECT FOUND_ROWS()' );
|
||||
|
||||
foreach ( $original_strings as $string_id ) {
|
||||
$string = $this->string_factory->find_by_id( $string_id );
|
||||
$string_translations = $string->get_translations();
|
||||
foreach ( $string_translations as $string_translation ) {
|
||||
if ( $string_translation->value ) {
|
||||
$string->set_translation( $string_translation->language, $string_translation->value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $number_of_all_strings - $offset - self::BATCH_SIZE;
|
||||
}
|
||||
|
||||
protected function process_batch_for_selected_media( $offset, $attachment_id ) {
|
||||
|
||||
$media_url = wpml_like_escape( wp_get_attachment_url( $attachment_id ) );
|
||||
if ( ! $media_url ) {
|
||||
return 0;
|
||||
}
|
||||
preg_match( '/(.+)\.([a-z]+)$/', $media_url, $match );
|
||||
$media_url_no_extension = wpml_like_escape( $match[1] );
|
||||
$extension = wpml_like_escape( $match[2] );
|
||||
|
||||
$batch_size = $this->get_batch_size( parent::BATCH_SIZE_FACTOR_SPECIFIC_MEDIA );
|
||||
|
||||
$original_strings = $this->wpdb->get_col(
|
||||
"
|
||||
SELECT SQL_CALC_FOUND_ROWS id, language
|
||||
FROM {$this->wpdb->prefix}icl_strings
|
||||
WHERE (
|
||||
value LIKE '%{$media_url}%' OR
|
||||
value LIKE '%{$media_url_no_extension}-%x%.{$extension}%'
|
||||
)
|
||||
ORDER BY id ASC
|
||||
LIMIT {$offset}, " . $batch_size
|
||||
);
|
||||
|
||||
$number_of_all_strings = (int) $this->wpdb->get_var( 'SELECT FOUND_ROWS()' );
|
||||
|
||||
foreach ( $original_strings as $string_id ) {
|
||||
$string = $this->string_factory->find_by_id( $string_id );
|
||||
$string_translations = $string->get_translations();
|
||||
foreach ( $string_translations as $string_translation ) {
|
||||
if ( $string_translation->value ) {
|
||||
$string->set_translation( $string_translation->language, $string_translation->value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $number_of_all_strings - $offset - $batch_size;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Attachment_By_URL_Factory {
|
||||
|
||||
public function create( $url, $language ) {
|
||||
global $wpdb;
|
||||
|
||||
return new WPML_Media_Attachment_By_URL( $wpdb, $url, $language );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Attachment_By_URL {
|
||||
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $url;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $language;
|
||||
|
||||
const SIZE_SUFFIX_REGEXP = '/-([0-9]+)x([0-9]+)\.([a-z]{3,4})$/';
|
||||
|
||||
const CACHE_KEY_PREFIX = 'attachment-id-from-guid-';
|
||||
const CACHE_GROUP = 'wpml-media-setup';
|
||||
const CACHE_EXPIRATION = 1800;
|
||||
|
||||
public $cache_hit_flag = null;
|
||||
|
||||
/**
|
||||
* WPML_Media_Attachment_By_URL constructor.
|
||||
*
|
||||
* @param wpdb $wpdb
|
||||
* @param string $url
|
||||
* @param string $language
|
||||
*/
|
||||
public function __construct( wpdb $wpdb, $url, $language ) {
|
||||
$this->url = $url;
|
||||
$this->language = $language;
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
public function get_id() {
|
||||
if ( ! $this->url ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$cache_key = self::CACHE_KEY_PREFIX . md5( $this->language . '#' . $this->url );
|
||||
|
||||
$attachment_id = wp_cache_get( $cache_key, self::CACHE_GROUP, false, $this->cache_hit_flag );
|
||||
if ( ! $this->cache_hit_flag ) {
|
||||
$attachment_id = $this->get_id_from_guid();
|
||||
if ( ! $attachment_id ) {
|
||||
$attachment_id = $this->get_id_from_meta();
|
||||
}
|
||||
|
||||
wp_cache_add( $cache_key, $attachment_id, self::CACHE_GROUP, self::CACHE_EXPIRATION );
|
||||
}
|
||||
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
private function get_id_from_guid() {
|
||||
$attachment_id = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
"
|
||||
SELECT ID FROM {$this->wpdb->posts} p
|
||||
JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = p.ID
|
||||
WHERE t.element_type='post_attachment' AND t.language_code=%s AND p.guid=%s
|
||||
",
|
||||
$this->language,
|
||||
$this->url
|
||||
)
|
||||
);
|
||||
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
private function get_id_from_meta() {
|
||||
|
||||
$uploads_dir = wp_get_upload_dir();
|
||||
$relative_path = ltrim( preg_replace( '@^' . $uploads_dir['baseurl'] . '@', '', $this->url ), '/' );
|
||||
|
||||
// using _wp_attached_file
|
||||
$attachment_id = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
"
|
||||
SELECT post_id
|
||||
FROM {$this->wpdb->postmeta} p
|
||||
JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = p.post_id
|
||||
WHERE p.meta_key='_wp_attached_file' AND p.meta_value=%s
|
||||
AND t.element_type='post_attachment' AND t.language_code=%s
|
||||
",
|
||||
$relative_path,
|
||||
$this->language
|
||||
)
|
||||
);
|
||||
|
||||
// using attachment meta (fallback)
|
||||
if ( ! $attachment_id && preg_match( self::SIZE_SUFFIX_REGEXP, $relative_path ) ) {
|
||||
$attachment_id = $this->get_attachment_image_from_meta_fallback( $relative_path );
|
||||
}
|
||||
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
private function get_attachment_image_from_meta_fallback( $relative_path ) {
|
||||
$attachment_id = null;
|
||||
|
||||
$relative_path_original = preg_replace( self::SIZE_SUFFIX_REGEXP, '.$3', $relative_path );
|
||||
$attachment_id_original = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
"
|
||||
SELECT p.post_id
|
||||
FROM {$this->wpdb->postmeta} p
|
||||
JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = p.post_id
|
||||
WHERE p.meta_key='_wp_attached_file' AND p.meta_value=%s
|
||||
AND t.element_type='post_attachment' AND t.language_code=%s
|
||||
",
|
||||
$relative_path_original,
|
||||
$this->language
|
||||
)
|
||||
);
|
||||
// validate size
|
||||
if ( $attachment_id_original ) {
|
||||
$attachment_meta_data = wp_get_attachment_metadata( $attachment_id_original );
|
||||
if ( $this->validate_image_size( $relative_path, $attachment_meta_data ) ) {
|
||||
$attachment_id = $attachment_id_original;
|
||||
}
|
||||
}
|
||||
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
private function validate_image_size( $path, $attachment_meta_data ) {
|
||||
$valid = false;
|
||||
$file_name = basename( $path );
|
||||
|
||||
foreach ( $attachment_meta_data['sizes'] as $size ) {
|
||||
if ( $file_name === $size['file'] ) {
|
||||
$valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Attachments_Query_Factory
|
||||
*/
|
||||
class WPML_Media_Attachments_Query_Factory implements IWPML_Frontend_Action_Loader, IWPML_Backend_Action_Loader {
|
||||
|
||||
/**
|
||||
* @return IWPML_Action|WPML_Media_Attachments_Query
|
||||
*/
|
||||
public function create() {
|
||||
return new WPML_Media_Attachments_Query();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Attachments_Query
|
||||
*/
|
||||
class WPML_Media_Attachments_Query implements IWPML_Action {
|
||||
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'pre_get_posts', array( $this, 'adjust_attachment_query' ), 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set `suppress_filters` to false if attachment is displayed.
|
||||
*
|
||||
* @param WP_Query $query
|
||||
*
|
||||
* @return WP_Query
|
||||
*/
|
||||
public function adjust_attachment_query( $query ) {
|
||||
if ( isset( $query->query['post_type'] ) && 'attachment' === $query->query['post_type'] ) {
|
||||
$query->set( 'suppress_filters', false );
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Factory
|
||||
*/
|
||||
class WPML_Media_Factory implements IWPML_Frontend_Action_Loader, IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $sitepress, $wpdb;
|
||||
|
||||
$wpml_wp_api = $sitepress->get_wp_api();
|
||||
|
||||
$template_service_loader = new WPML_Twig_Template_Loader(
|
||||
array( $wpml_wp_api->constant( 'WPML_MEDIA_PATH' ) . '/templates/menus/' )
|
||||
);
|
||||
$wpml_media_menus_factory = new WPML_Media_Menus_Factory();
|
||||
|
||||
return new WPML_Media( $sitepress, $wpdb, $wpml_media_menus_factory );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_File_Factory
|
||||
*/
|
||||
class WPML_Media_File_Factory {
|
||||
|
||||
/**
|
||||
* @param $attachment_id
|
||||
*
|
||||
* @return WPML_Media_File
|
||||
*/
|
||||
public function create( $attachment_id ) {
|
||||
global $wpdb;
|
||||
|
||||
return new WPML_Media_File( $attachment_id, $this->get_wp_filesystem(), $wpdb );
|
||||
}
|
||||
|
||||
private function get_wp_filesystem() {
|
||||
global $wp_filesystem;
|
||||
if ( null === $wp_filesystem ) {
|
||||
WP_Filesystem();
|
||||
}
|
||||
|
||||
return $wp_filesystem;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_File {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $attachment_id;
|
||||
/**
|
||||
* @var WP_Filesystem_Base
|
||||
*/
|
||||
private $wp_filesystem;
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
|
||||
public function __construct( $attachment_id, WP_Filesystem_Base $wp_filesystem, wpdb $wpdb ) {
|
||||
$this->wp_filesystem = $wp_filesystem;
|
||||
$this->attachment_id = $attachment_id;
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
public function delete() {
|
||||
$relative_file_path = get_post_meta( $this->attachment_id, '_wp_attached_file', true );
|
||||
|
||||
if ( $relative_file_path && ! $this->file_is_shared( $relative_file_path, $this->attachment_id ) ) {
|
||||
|
||||
$file_path = $this->get_full_file_upload_path( $relative_file_path );
|
||||
|
||||
$this->wp_filesystem->delete( $file_path, false, 'f' );
|
||||
|
||||
$attachment_meta_data = wp_get_attachment_metadata( $this->attachment_id );
|
||||
if ( $attachment_meta_data ) {
|
||||
$subdir = dirname( $attachment_meta_data['file'] );
|
||||
foreach ( $attachment_meta_data['sizes'] as $key => $size ) {
|
||||
$file_path = $this->get_full_file_upload_path( $subdir . '/' . $size['file'] );
|
||||
$this->wp_filesystem->delete( $file_path, false, 'f' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function get_full_file_upload_path( $relative_file_path ) {
|
||||
$upload_dir = wp_upload_dir();
|
||||
$relative_file_path = trim( $relative_file_path, ' /' );
|
||||
$file_path = $upload_dir['basedir'] . '/' . $relative_file_path;
|
||||
|
||||
return $file_path;
|
||||
}
|
||||
|
||||
private function file_is_shared( $relative_file_path, $attachment_id ) {
|
||||
|
||||
$sql = "SELECT post_id FROM {$this->wpdb->postmeta}
|
||||
WHERE post_id <> %d AND meta_key='_wp_attached_file' AND meta_value=%s";
|
||||
|
||||
return $this->wpdb->get_var( $this->wpdb->prepare( $sql, $attachment_id, $relative_file_path ) );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,441 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media
|
||||
*/
|
||||
class WPML_Media implements IWPML_Action {
|
||||
const SETUP_RUN = 'setup_run';
|
||||
const SETUP_STARTED = 'setup_started';
|
||||
|
||||
private static $settings;
|
||||
private static $settings_option_key = '_wpml_media';
|
||||
private static $default_settings = array(
|
||||
'version' => false,
|
||||
'media_files_localization' => array(
|
||||
'posts' => true,
|
||||
'custom_fields' => true,
|
||||
'strings' => true,
|
||||
),
|
||||
'wpml_media_2_3_migration' => true,
|
||||
self::SETUP_RUN => false,
|
||||
);
|
||||
|
||||
public $languages;
|
||||
public $parents;
|
||||
public $unattached;
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* @var WPML_Media_Menus_Factory
|
||||
*/
|
||||
private $menus_factory;
|
||||
|
||||
/**
|
||||
* WPML_Media constructor.
|
||||
*
|
||||
* @param SitePress $sitepress
|
||||
* @param wpdb $wpdb
|
||||
* @param WPML_Media_Menus_Factory $menus_factory
|
||||
*/
|
||||
public function __construct( SitePress $sitepress, wpdb $wpdb, WPML_Media_Menus_Factory $menus_factory ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->wpdb = $wpdb;
|
||||
$this->menus_factory = $menus_factory;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wpml_loaded', array( $this, 'loaded' ), 2 );
|
||||
}
|
||||
|
||||
public static function has_settings() {
|
||||
return get_option( self::$settings_option_key );
|
||||
}
|
||||
|
||||
public function loaded() {
|
||||
global $sitepress;
|
||||
if ( ! isset( $sitepress ) || ! $sitepress->get_setting( 'setup_complete' ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->plugin_localization();
|
||||
|
||||
if ( is_admin() ) {
|
||||
WPML_Media_Upgrade::run();
|
||||
}
|
||||
|
||||
self::init_settings();
|
||||
|
||||
global $sitepress_settings, $pagenow;
|
||||
|
||||
$active_languages = $sitepress->get_active_languages();
|
||||
|
||||
$this->languages = null;
|
||||
|
||||
if ( $this->is_admin_or_xmlrpc() && ! $this->is_uploading_plugin_or_theme() ) {
|
||||
|
||||
add_action( 'wpml_admin_menu_configure', array( $this, 'menu' ) );
|
||||
|
||||
if ( 1 < count( $active_languages ) ) {
|
||||
|
||||
if ( $pagenow == 'media-upload.php' ) {
|
||||
add_action( 'pre_get_posts', array( $this, 'filter_media_upload_items' ), 10, 1 );
|
||||
}
|
||||
|
||||
if ( $pagenow == 'media.php' ) {
|
||||
add_action( 'admin_footer', array( $this, 'media_language_options' ) );
|
||||
}
|
||||
|
||||
add_action( 'wp_ajax_wpml_media_scan_prepare', array( $this, 'batch_scan_prepare' ) );
|
||||
|
||||
add_action( 'wp_ajax_find_posts', array( $this, 'find_posts_filter' ), 0 );
|
||||
}
|
||||
} else {
|
||||
if ( WPML_LANGUAGE_NEGOTIATION_TYPE_DOMAIN === (int) $sitepress_settings['language_negotiation_type'] ) {
|
||||
// Translate media url when in front-end and only when using custom domain
|
||||
add_filter( 'wp_get_attachment_url', array( $this, 'wp_get_attachment_url' ), 10, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
add_filter( 'WPML_filter_link', array( $this, 'filter_link' ), 10, 2 );
|
||||
add_filter( 'icl_ls_languages', array( $this, 'icl_ls_languages' ), 10, 1 );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function is_admin_or_xmlrpc() {
|
||||
$is_admin = is_admin();
|
||||
$is_xmlrpc = ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST );
|
||||
|
||||
return $is_admin || $is_xmlrpc;
|
||||
}
|
||||
|
||||
function is_uploading_plugin_or_theme() {
|
||||
global $action;
|
||||
|
||||
return ( isset( $action ) && ( $action == 'upload-plugin' || $action == 'upload-theme' ) );
|
||||
}
|
||||
|
||||
function plugin_localization() {
|
||||
load_plugin_textdomain( 'wpml-media', false, WPML_MEDIA_FOLDER . '/locale' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Needed by class init and by all static methods that use self::$settings
|
||||
*/
|
||||
public static function init_settings() {
|
||||
if ( ! self::$settings ) {
|
||||
self::$settings = get_option( self::$settings_option_key, array() );
|
||||
}
|
||||
|
||||
self::$settings = array_merge( self::$default_settings, self::$settings );
|
||||
}
|
||||
|
||||
public static function has_setup_run() {
|
||||
return self::get_setting( self::SETUP_RUN );
|
||||
}
|
||||
|
||||
public static function set_setup_run( $value = 1 ) {
|
||||
return self::update_setting( self::SETUP_RUN, $value );
|
||||
}
|
||||
|
||||
public static function has_setup_started() {
|
||||
return self::get_setting( self::SETUP_STARTED );
|
||||
}
|
||||
|
||||
public static function set_setup_started( $value = 1 ) {
|
||||
return self::update_setting( self::SETUP_STARTED, $value );
|
||||
}
|
||||
|
||||
public static function get_setting( $name, $default = false ) {
|
||||
self::init_settings();
|
||||
if ( ! isset( self::$settings[ $name ] ) || ! self::$settings[ $name ] ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return self::$settings[ $name ];
|
||||
}
|
||||
|
||||
public static function update_setting( $name, $value ) {
|
||||
self::init_settings();
|
||||
self::$settings[ $name ] = $value;
|
||||
|
||||
return update_option( self::$settings_option_key, self::$settings );
|
||||
}
|
||||
|
||||
function batch_scan_prepare() {
|
||||
global $wpdb;
|
||||
|
||||
$response = array();
|
||||
$wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'wpml_media_processed' ) );
|
||||
|
||||
$response['message'] = __( 'Started...', 'wpml-media' );
|
||||
|
||||
echo wp_json_encode( $response );
|
||||
exit;
|
||||
}
|
||||
|
||||
static function is_valid_post_type( $post_type ) {
|
||||
global $wp_post_types;
|
||||
|
||||
$post_types = array_keys( (array) $wp_post_types );
|
||||
|
||||
return in_array( $post_type, $post_types );
|
||||
}
|
||||
|
||||
function find_posts_filter() {
|
||||
add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ) );
|
||||
}
|
||||
|
||||
function pre_get_posts( $query ) {
|
||||
$query->query['suppress_filters'] = 0;
|
||||
$query->query_vars['suppress_filters'] = 0;
|
||||
}
|
||||
|
||||
function media_language_options() {
|
||||
global $sitepress;
|
||||
$att_id = filter_input( INPUT_GET, 'attachment_id', FILTER_SANITIZE_NUMBER_INT, FILTER_NULL_ON_FAILURE );
|
||||
$translations = $sitepress->get_element_translations( $att_id, 'post_attachment' );
|
||||
$current_lang = '';
|
||||
foreach ( $translations as $lang => $id ) {
|
||||
if ( $id == $att_id ) {
|
||||
$current_lang = $lang;
|
||||
unset( $translations[ $lang ] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$active_languages = icl_get_languages( 'orderby=id&order=asc&skip_missing=0' );
|
||||
$lang_links = '';
|
||||
|
||||
if ( $current_lang ) {
|
||||
|
||||
$lang_links = '<strong>' . $active_languages[ $current_lang ]['native_name'] . '</strong>';
|
||||
|
||||
}
|
||||
|
||||
foreach ( $translations as $lang => $id ) {
|
||||
$lang_links .= ' | <a href="' . admin_url( 'media.php?attachment_id=' . $id . '&action=edit' ) . '">' . $active_languages[ $lang ]['native_name'] . '</a>';
|
||||
}
|
||||
|
||||
echo '<div id="icl_lang_options" style="display:none">' . $lang_links . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes _wpml_media_* meta fields with all translations
|
||||
*
|
||||
* @param int $meta_id
|
||||
* @param int $object_id
|
||||
* @param string $meta_key
|
||||
* @param string|mixed $meta_value
|
||||
*/
|
||||
function updated_postmeta( $meta_id, $object_id, $meta_key, $meta_value ) {
|
||||
if ( in_array( $meta_key, array( '_wpml_media_duplicate', '_wpml_media_featured' ) ) ) {
|
||||
global $sitepress;
|
||||
$el_type = 'post_' . get_post_type( $object_id );
|
||||
$trid = $sitepress->get_element_trid( $object_id, $el_type );
|
||||
$translations = $sitepress->get_element_translations( $trid, $el_type, true, true );
|
||||
foreach ( $translations as $translation ) {
|
||||
if ( $translation->element_id != $object_id ) {
|
||||
$t_meta_value = get_post_meta( $translation->element_id, $meta_key, true );
|
||||
if ( $t_meta_value != $meta_value ) {
|
||||
update_post_meta( $translation->element_id, $meta_key, $meta_value );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a filter to fix the links for attachments in the language switcher so
|
||||
* they point to the corresponding pages in different languages.
|
||||
*/
|
||||
function filter_link( $url, $lang_info ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
function wp_get_attachment_url( $url, $post_id ) {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->convert_url( $url );
|
||||
}
|
||||
|
||||
function icl_ls_languages( $w_active_languages ) {
|
||||
static $doing_it = false;
|
||||
|
||||
if ( is_attachment() && ! $doing_it ) {
|
||||
$doing_it = true;
|
||||
// Always include missing languages.
|
||||
$w_active_languages = icl_get_languages( 'skip_missing=0' );
|
||||
$doing_it = false;
|
||||
}
|
||||
|
||||
return $w_active_languages;
|
||||
}
|
||||
|
||||
function get_post_metadata( $value, $object_id, $meta_key, $single ) {
|
||||
if ( $meta_key == '_thumbnail_id' ) {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$thumbnail_prepared = $wpdb->prepare(
|
||||
"SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = %s",
|
||||
array(
|
||||
$object_id,
|
||||
$meta_key,
|
||||
)
|
||||
);
|
||||
$thumbnail = $wpdb->get_var( $thumbnail_prepared );
|
||||
|
||||
if ( $thumbnail == null ) {
|
||||
// see if it's available in the original language.
|
||||
|
||||
$post_type_prepared = $wpdb->prepare( "SELECT post_type FROM {$wpdb->posts} WHERE ID = %d", array( $object_id ) );
|
||||
$post_type = $wpdb->get_var( $post_type_prepared );
|
||||
$trid_prepared = $wpdb->prepare(
|
||||
"SELECT trid, source_language_code FROM {$wpdb->prefix}icl_translations WHERE element_id=%d AND element_type = %s",
|
||||
array(
|
||||
$object_id,
|
||||
'post_' . $post_type,
|
||||
)
|
||||
);
|
||||
$trid = $wpdb->get_row( $trid_prepared );
|
||||
if ( $trid ) {
|
||||
|
||||
global $sitepress;
|
||||
|
||||
$translations = $sitepress->get_element_translations( $trid->trid, 'post_' . $post_type );
|
||||
if ( isset( $translations[ $trid->source_language_code ] ) ) {
|
||||
$translation = $translations[ $trid->source_language_code ];
|
||||
// see if the original has a thumbnail.
|
||||
$thumbnail_prepared = $wpdb->prepare(
|
||||
"SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = %s",
|
||||
array(
|
||||
$translation->element_id,
|
||||
$meta_key,
|
||||
)
|
||||
);
|
||||
$thumbnail = $wpdb->get_var( $thumbnail_prepared );
|
||||
if ( $thumbnail ) {
|
||||
$value = $thumbnail;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$value = $thumbnail;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $menu_id
|
||||
*/
|
||||
public function menu( $menu_id ) {
|
||||
if ( 'WPML' !== $menu_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$menu_label = __( 'Media Translation', 'wpml-media' );
|
||||
$menu = array();
|
||||
$menu['order'] = 600;
|
||||
$menu['page_title'] = $menu_label;
|
||||
$menu['menu_title'] = $menu_label;
|
||||
$menu['capability'] = 'edit_others_posts';
|
||||
$menu['menu_slug'] = 'wpml-media';
|
||||
$menu['function'] = array( $this, 'menu_content' );
|
||||
|
||||
do_action( 'wpml_admin_menu_register_item', $menu );
|
||||
}
|
||||
|
||||
public function menu_content() {
|
||||
$menus = $this->menus_factory->create();
|
||||
$menus->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ids
|
||||
* @param $target_language
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
public function translate_attachment_ids( $ids, $target_language ) {
|
||||
global $sitepress;
|
||||
$return_string = false;
|
||||
if ( ! is_array( $ids ) ) {
|
||||
$attachment_ids = explode( ',', $ids );
|
||||
$return_string = true;
|
||||
}
|
||||
|
||||
$translated_ids = array();
|
||||
if ( ! empty( $attachment_ids ) ) {
|
||||
foreach ( $attachment_ids as $attachment_id ) {
|
||||
// Fallback to the original ID
|
||||
$translated_id = $attachment_id;
|
||||
|
||||
// Find the ID translation
|
||||
$trid = $sitepress->get_element_trid( $attachment_id, 'post_attachment' );
|
||||
if ( $trid ) {
|
||||
$id_translations = $sitepress->get_element_translations( $trid, 'post_attachment', false, true );
|
||||
foreach ( $id_translations as $language_code => $id_translation ) {
|
||||
if ( $language_code == $target_language ) {
|
||||
$translated_id = $id_translation->element_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$translated_ids[] = $translated_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $return_string ) {
|
||||
return implode( ',', $translated_ids );
|
||||
}
|
||||
|
||||
return $translated_ids;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update query for media-upload.php page.
|
||||
*
|
||||
* @param object $query WP_Query
|
||||
*/
|
||||
public function filter_media_upload_items( $query ) {
|
||||
$current_lang = $this->sitepress->get_current_language();
|
||||
$ids = icl_cache_get( '_media_upload_attachments' . $current_lang );
|
||||
|
||||
if ( false === $ids ) {
|
||||
$tbl = $this->wpdb->prefix . 'icl_translations';
|
||||
$db_query = "
|
||||
SELECT posts.ID
|
||||
FROM {$this->wpdb->posts} as posts, $tbl as icl_translations
|
||||
WHERE posts.post_type = 'attachment'
|
||||
AND icl_translations.element_id = posts.ID
|
||||
AND icl_translations.language_code = %s
|
||||
";
|
||||
|
||||
$posts = $this->wpdb->get_results( $this->wpdb->prepare( $db_query, $current_lang ) );
|
||||
$ids = array();
|
||||
if ( ! empty( $posts ) ) {
|
||||
foreach ( $posts as $post ) {
|
||||
$ids[] = absint( $post->ID );
|
||||
}
|
||||
}
|
||||
|
||||
icl_cache_set( '_media_upload_attachments' . $current_lang, $ids );
|
||||
}
|
||||
|
||||
$query->set( 'post__in', $ids );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Add_To_Basket_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $sitepress;
|
||||
if ( isset( $_POST['icl_tm_action'] ) && 'add_jobs' === $_POST['icl_tm_action'] ) {
|
||||
return new WPML_Media_Add_To_Basket( $sitepress );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Add_To_Basket implements IWPML_Action {
|
||||
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* WPML_Media_Add_To_Basket constructor.
|
||||
*/
|
||||
public function __construct( SitePress $sitepress ) {
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter(
|
||||
'pre_update_option_' . $this->sitepress->get_wp_api()->constant( 'TranslationProxy_Basket::ICL_TRANSLATION_JOBS_BASKET' ),
|
||||
array( $this, 'add_media' )
|
||||
);
|
||||
}
|
||||
|
||||
public function add_media( $data ) {
|
||||
|
||||
if ( ! empty( $data['post'] ) ) {
|
||||
foreach ( $data['post'] as $post_id => $post ) {
|
||||
if ( $media = $this->get_post_media( $post_id ) ) {
|
||||
$data['post'][ $post_id ]['media-translation'] = $media;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function get_post_media( $post_id ) {
|
||||
return isset( $_POST['post'][ $post_id ]['media-translation'] ) ?
|
||||
array_map( 'intval', $_POST['post'][ $post_id ]['media-translation'] ) :
|
||||
array();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Selector_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $sitepress;
|
||||
|
||||
$wpml_wp_api = $sitepress->get_wp_api();
|
||||
$wpml_media_path = $wpml_wp_api->constant( 'WPML_MEDIA_PATH' );
|
||||
|
||||
return new WPML_Media_Selector(
|
||||
$sitepress,
|
||||
new WPML_Twig_Template_Loader( array( $wpml_media_path . '/templates/media-selector/' ) ),
|
||||
new WPML_Media_Post_With_Media_Files_Factory(),
|
||||
new WPML_Translation_Element_Factory( $sitepress )
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Selector implements IWPML_Action {
|
||||
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
/**
|
||||
* @var WPML_Twig_Template_Loader
|
||||
*/
|
||||
private $template_loader;
|
||||
/**
|
||||
* @var WPML_Media_Post_With_Media_Files_Factory
|
||||
*/
|
||||
private $post_with_media_files_factory;
|
||||
/**
|
||||
* @var WPML_Media_Post_With_Media_Files_Factory
|
||||
*/
|
||||
private $translation_element_factory;
|
||||
|
||||
|
||||
const USER_META_HIDE_POST_MEDIA_SELECTOR = '_wpml_media_hide_post_media_selector';
|
||||
|
||||
public function __construct(
|
||||
SitePress $sitepress,
|
||||
WPML_Twig_Template_Loader $template_loader,
|
||||
WPML_Media_Post_With_Media_Files_Factory $post_with_media_files_factory,
|
||||
WPML_Translation_Element_Factory $translation_element_factory
|
||||
) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->template_loader = $template_loader;
|
||||
$this->post_with_media_files_factory = $post_with_media_files_factory;
|
||||
$this->translation_element_factory = $translation_element_factory;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_res' ) );
|
||||
add_action( 'wp_ajax_wpml_media_load_image_selector', array( $this, 'load_images_selector' ) );
|
||||
add_action( 'wp_ajax_wpml_media_toogle_show_media_selector', array( $this, 'toggle_show_media_selector' ) );
|
||||
|
||||
add_filter( 'wpml_translation_dashboard_row_data', array( $this, 'add_media_data_to_dashboard_row' ), 10, 2 );
|
||||
add_action( 'wpml_tm_after_translation_dashboard_documents', array( $this, 'add_media_selector_preloader' ) );
|
||||
}
|
||||
|
||||
public function enqueue_res() {
|
||||
$current_screen = get_current_screen();
|
||||
|
||||
if ( $current_screen->id === 'wpml_page_' . $this->sitepress->get_wp_api()->constant( 'WPML_TM_FOLDER' ) . '/menu/main' ) {
|
||||
$wpml_media_url = $this->sitepress->get_wp_api()->constant( 'WPML_MEDIA_URL' );
|
||||
wp_enqueue_script( 'wpml-media-selector', $wpml_media_url . '/res/js/media-selector.js', array( 'jquery' ), false, true );
|
||||
wp_enqueue_style( 'wpml-media-selector', $wpml_media_url . '/res/css/media-selector.css', array() );
|
||||
}
|
||||
}
|
||||
|
||||
public function load_images_selector() {
|
||||
$post_id = (int) $_POST['post_id'];
|
||||
if ( isset( $_POST['languages'] ) && is_array( $_POST['languages'] ) ) {
|
||||
$languages = array_map( 'sanitize_text_field', $_POST['languages'] );
|
||||
} else {
|
||||
$languages = array();
|
||||
}
|
||||
|
||||
$media_files_list = $this->get_media_files_list( $post_id, $languages );
|
||||
$media_files_count = count( $media_files_list );
|
||||
|
||||
$model = array(
|
||||
'files' => $media_files_list,
|
||||
'post_id' => $post_id,
|
||||
);
|
||||
|
||||
$html = $this->template_loader->get_template()->show( $model, 'media-selector.twig' );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'html' => $html,
|
||||
'media_files_count' => $media_files_count,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param array $languages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_media_files_list( $post_id, $languages ) {
|
||||
|
||||
$media_files_list = array();
|
||||
|
||||
$post_with_media = $this->post_with_media_files_factory->create( $post_id );
|
||||
|
||||
$media_ids = $post_with_media->get_media_ids();
|
||||
|
||||
foreach ( $media_ids as $attachment_id ) {
|
||||
|
||||
$media_files_list[ $attachment_id ] = array(
|
||||
'thumbnail' => wp_get_attachment_thumb_url( $attachment_id ),
|
||||
'name' => get_post_field( 'post_title', $attachment_id ),
|
||||
'translated' => $this->media_file_is_translated( $attachment_id, $languages ),
|
||||
);
|
||||
}
|
||||
|
||||
return $media_files_list;
|
||||
}
|
||||
|
||||
private function media_file_is_translated( $attachment_id, $languages ) {
|
||||
$post_element = $this->translation_element_factory->create( $attachment_id, 'post' );
|
||||
foreach ( $languages as $language ) {
|
||||
$translation = $post_element->get_translation( $language );
|
||||
if ( null === $translation || get_post_meta( $attachment_id, '_wp_attached_file', true )
|
||||
=== get_post_meta( $translation->get_id(), '_wp_attached_file', true ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function toggle_show_media_selector() {
|
||||
$current_value = get_user_meta( get_current_user_id(), self::USER_META_HIDE_POST_MEDIA_SELECTOR, true );
|
||||
update_user_meta( get_current_user_id(), self::USER_META_HIDE_POST_MEDIA_SELECTOR, ! $current_value );
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $row_data
|
||||
* @param stdClass $doc_data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_media_data_to_dashboard_row( $row_data, $doc_data ) {
|
||||
if ( 0 !== strpos( $doc_data->translation_element_type, 'post_' ) ) {
|
||||
return $row_data;
|
||||
}
|
||||
|
||||
$row_data = $this->add_post_has_media_flag( $row_data, $doc_data->ID );
|
||||
$row_data = $this->add_post_type_attribute_data( $row_data, $doc_data->ID );
|
||||
|
||||
return $row_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function add_post_has_media_flag( array $data, $post_id ) {
|
||||
$data['has-media'] = get_post_meta( $post_id, WPML_Media_Set_Posts_Media_Flag::HAS_MEDIA_POST_FLAG, true );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function add_post_type_attribute_data( $data, $post_id ) {
|
||||
$post_type = get_post_type( $post_id );
|
||||
$post_type_object = get_post_type_object( $post_type );
|
||||
|
||||
$data['post-type'] = strtolower( $post_type_object->labels->singular_name );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function add_media_selector_preloader() {
|
||||
$model = array(
|
||||
'strings' => array(
|
||||
'has_posts' => sprintf(
|
||||
__(
|
||||
'Choose which media to translate with this %s',
|
||||
'wpml-media'
|
||||
),
|
||||
'%POST_TYPE%'
|
||||
),
|
||||
'loading' => __( 'Loading...', 'wpml-media' ),
|
||||
),
|
||||
'hide_selector' => get_user_meta( get_current_user_id(), self::USER_META_HIDE_POST_MEDIA_SELECTOR, true ),
|
||||
);
|
||||
echo $this->template_loader->get_template()->show( $model, 'media-selector-preloader.twig' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Submitted_Basket_Notice_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $sitepress;
|
||||
if ( $sitepress->get_wp_api()->is_tm_page( 'basket' ) && $this->basket_has_media() ) {
|
||||
$template_loader = new WPML_Twig_Template_Loader( array( WPML_MEDIA_PATH . '/templates/media-selector/' ) );
|
||||
|
||||
return new WPML_Media_Submitted_Basket_Notice( $template_loader );
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private function basket_has_media() {
|
||||
$basket = TranslationProxy_Basket::get_basket( true );
|
||||
$item_types = TranslationProxy_Basket::get_basket_items_types();
|
||||
|
||||
foreach ( $item_types as $item_type => $type_type ) {
|
||||
if ( isset( $basket[ $item_type ] ) ) {
|
||||
foreach ( $basket[ $item_type ] as $item ) {
|
||||
if ( ! empty( $item['media-translation'] ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Submitted_Basket_Notice implements IWPML_Action {
|
||||
/**
|
||||
* @var WPML_Twig_Template_Loader
|
||||
*/
|
||||
private $template_loader;
|
||||
|
||||
public function __construct( WPML_Twig_Template_Loader $template_loader ) {
|
||||
$this->template_loader = $template_loader;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wpml_tm_scripts_enqueued', array( $this, 'load_js' ) );
|
||||
add_action( 'wpml_translation_basket_page_after', array( $this, 'load_dialog_template' ) );
|
||||
}
|
||||
|
||||
public function load_js() {
|
||||
$script_handle = 'submitted-basket-notice';
|
||||
wp_enqueue_script(
|
||||
$script_handle,
|
||||
WPML_MEDIA_URL . '/res/js/submitted-basket-notice.js',
|
||||
array( 'jquery-ui-dialog' ),
|
||||
WPML_MEDIA_VERSION,
|
||||
false
|
||||
);
|
||||
|
||||
$wpml_media_basket_notice_data = array(
|
||||
'button_label' => __( 'Continue', 'wpml_media' ),
|
||||
);
|
||||
wp_localize_script( $script_handle, 'wpml_media_basket_notice_data', $wpml_media_basket_notice_data );
|
||||
}
|
||||
|
||||
public function load_dialog_template() {
|
||||
|
||||
/* translators: WPML plugin name */
|
||||
$wpml_plugin_name = __( 'WPML', 'wpml-media' );
|
||||
/* translators: WPML Media Translation saddon/section name */
|
||||
$media_translation_name = __( 'Media Translation', 'wpml-media' );
|
||||
|
||||
$media_translation_url = admin_url( 'admin.php?page=wpml-media' );
|
||||
$media_translation_link = sprintf(
|
||||
'<a href="%s" target="_blank" rel="noopener" class="wpml-external-link">%s » %s</a>',
|
||||
$media_translation_url,
|
||||
$wpml_plugin_name,
|
||||
$media_translation_name
|
||||
);
|
||||
|
||||
/* translators: media file string used in "if you want to use a different media file for each language..." */
|
||||
$media_file_string = __( 'media file', 'wpml-media' );
|
||||
$redirect_url = '#';
|
||||
|
||||
if ( defined( 'WPML_TM_FOLDER' ) ) {
|
||||
$redirect_url = add_query_arg( 'page', WPML_TM_FOLDER . '/menu/main.php', admin_url( 'admin.php' ) );
|
||||
}
|
||||
|
||||
$model = array(
|
||||
'strings' => array(
|
||||
'dialog_title' => __( 'Media sent to translation', 'wpml-media' ),
|
||||
'content_with_media_sent' => __( 'You have sent content which contains media attachments for translation.', 'wpml-media' ),
|
||||
'media_texts_translated' => sprintf( __( 'Translators will translate all your %1$smedia texts%2$s.', 'wpml-media' ), '<strong>', '</strong>' ),
|
||||
'use_different_media' => sprintf(
|
||||
__( 'If you want to use a different %1$s for each language, you can set them in: %2$s.', 'wpml-media' ),
|
||||
'<strong>' . $media_file_string . '</strong>',
|
||||
$media_translation_link
|
||||
),
|
||||
'learn_more' => __( 'Learn more about Media Translation', 'wpml-media' ),
|
||||
'wpml' => _x( 'WPML', 'plugin name', 'wpml-media' ),
|
||||
'media_translation' => _x( 'Media Translation', 'wpml addon name', 'wpml-media' ),
|
||||
),
|
||||
|
||||
'learn_more_url' => 'https://wpml.org/?page_id=113610',
|
||||
'redirect_url' => $redirect_url,
|
||||
);
|
||||
|
||||
echo $this->template_loader->get_template()->show( $model, 'submitted-basket-notice.twig' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Add_To_Translation_Package_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
return new WPML_Media_Add_To_Translation_Package( new WPML_Media_Post_With_Media_Files_Factory() );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Add_To_Translation_Package implements IWPML_Action {
|
||||
|
||||
const ALT_PLACEHOLDER = '{%ALT_TEXT%}';
|
||||
const CAPTION_PLACEHOLDER = '{%CAPTION%}';
|
||||
|
||||
/** @var WPML_Media_Post_With_Media_Files_Factory $post_media_factory */
|
||||
private $post_media_factory;
|
||||
|
||||
public function __construct( WPML_Media_Post_With_Media_Files_Factory $post_media_factory ) {
|
||||
$this->post_media_factory = $post_media_factory;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
|
||||
add_action( 'wpml_tm_translation_job_data', array( $this, 'add_media_strings' ), PHP_INT_MAX, 2 );
|
||||
}
|
||||
|
||||
public function add_media_strings( $package, $post ) {
|
||||
|
||||
$basket = TranslationProxy_Basket::get_basket( true );
|
||||
|
||||
$bundled_media_data = $this->get_bundled_media_to_translate( $post );
|
||||
if ( $bundled_media_data ) {
|
||||
|
||||
foreach ( $bundled_media_data as $attachment_id => $data ) {
|
||||
foreach ( $data as $field => $value ) {
|
||||
if (
|
||||
isset( $basket['post'][ $post->ID ]['media-translation'] ) &&
|
||||
! in_array( $attachment_id, $basket['post'][ $post->ID ]['media-translation'] )
|
||||
) {
|
||||
$options = array(
|
||||
'translate' => 0,
|
||||
'data' => true,
|
||||
'format' => '',
|
||||
);
|
||||
} else {
|
||||
$options = array(
|
||||
'translate' => 1,
|
||||
'data' => base64_encode( $value ),
|
||||
'format' => 'base64',
|
||||
);
|
||||
}
|
||||
$package['contents'][ 'media_' . $attachment_id . '_' . $field ] = $options;
|
||||
}
|
||||
|
||||
if (
|
||||
isset( $basket['post'][ $post->ID ]['media-translation'] ) &&
|
||||
in_array( $attachment_id, $basket['post'][ $post->ID ]['media-translation'] )
|
||||
) {
|
||||
$package['contents'][ 'should_translate_media_image_' . $attachment_id ] = array(
|
||||
'translate' => 0,
|
||||
'data' => true,
|
||||
'format' => '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$package = $this->add_placeholders_for_duplicate_fields( $package, $bundled_media_data );
|
||||
|
||||
}
|
||||
|
||||
return $package;
|
||||
}
|
||||
|
||||
private function get_bundled_media_to_translate( $post ) {
|
||||
|
||||
$post_media = $this->post_media_factory->create( $post->ID );
|
||||
$bundled_media_data = array();
|
||||
|
||||
foreach ( $post_media->get_media_ids() as $attachment_id ) {
|
||||
$attachment = get_post( $attachment_id );
|
||||
|
||||
if ( $attachment->post_title ) {
|
||||
$bundled_media_data[ $attachment_id ]['title'] = $attachment->post_title;
|
||||
}
|
||||
if ( $attachment->post_excerpt ) {
|
||||
$bundled_media_data[ $attachment_id ]['caption'] = $attachment->post_excerpt;
|
||||
}
|
||||
if ( $attachment->post_content ) {
|
||||
$bundled_media_data[ $attachment_id ]['description'] = $attachment->post_content;
|
||||
}
|
||||
if ( $alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) ) {
|
||||
$bundled_media_data[ $attachment_id ]['alt_text'] = $alt;
|
||||
}
|
||||
}
|
||||
|
||||
return $bundled_media_data;
|
||||
|
||||
}
|
||||
|
||||
private function add_placeholders_for_duplicate_fields( $package, $bundled_media_data ) {
|
||||
|
||||
$caption_parser = new WPML_Media_Caption_Tags_Parse();
|
||||
|
||||
foreach ( $package['contents'] as $field => $data ) {
|
||||
if ( $data['translate'] && 'base64' === $data['format'] ) {
|
||||
$original = $content = base64_decode( $data['data'] );
|
||||
|
||||
$captions = $caption_parser->get_captions( $content );
|
||||
|
||||
foreach ( $captions as $caption ) {
|
||||
$caption_id = $caption->get_id();
|
||||
$caption_shortcode = $new_caption_shortcode = $caption->get_shortcode_string();
|
||||
|
||||
if ( isset( $bundled_media_data[ $caption_id ] ) ) {
|
||||
|
||||
if ( isset( $bundled_media_data[ $caption_id ]['caption'] ) && $bundled_media_data[ $caption_id ]['caption'] === $caption->get_caption() ) {
|
||||
$new_caption_shortcode = $this->replace_caption_with_placeholder( $new_caption_shortcode, $caption );
|
||||
}
|
||||
|
||||
if ( isset( $bundled_media_data[ $caption_id ]['alt_text'] ) && $bundled_media_data[ $caption_id ]['alt_text'] === $caption->get_image_alt() ) {
|
||||
$new_caption_shortcode = $this->replace_alt_text_with_placeholder( $new_caption_shortcode, $caption );
|
||||
}
|
||||
|
||||
if ( $new_caption_shortcode !== $caption_shortcode ) {
|
||||
$content = str_replace( $caption_shortcode, $new_caption_shortcode, $content );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $content !== $original ) {
|
||||
$package['contents'][ $field ]['data'] = base64_encode( $content );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $package;
|
||||
}
|
||||
|
||||
private function replace_caption_with_placeholder( $caption_shortcode, WPML_Media_Caption $caption ) {
|
||||
$caption_content = $caption->get_content();
|
||||
$search_pattern = '/(>\s?)(' . preg_quote( $caption->get_caption(), '/' ) . ')/';
|
||||
$new_caption_content = preg_replace( $search_pattern, '$1' . self::CAPTION_PLACEHOLDER, $caption_content, 1 );
|
||||
|
||||
return str_replace( $caption_content, $new_caption_content, $caption_shortcode );
|
||||
|
||||
}
|
||||
|
||||
private function replace_alt_text_with_placeholder( $caption_shortcode, WPML_Media_Caption $caption ) {
|
||||
|
||||
$alt_text = $caption->get_image_alt();
|
||||
return str_replace( 'alt="' . $alt_text . '"', 'alt="' . self::ALT_PLACEHOLDER . '"', $caption_shortcode );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Attachment_Image_Update_Factory
|
||||
*/
|
||||
class WPML_Media_Attachment_Image_Update_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $wpdb;
|
||||
|
||||
return new WPML_Media_Attachment_Image_Update( $wpdb );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Attachment_Image_Update
|
||||
* Allows adding a custom image to a translated attachment
|
||||
*/
|
||||
class WPML_Media_Attachment_Image_Update implements IWPML_Action {
|
||||
|
||||
const TRANSIENT_FILE_UPLOAD_PREFIX = 'wpml_media_file_update_';
|
||||
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
|
||||
/**
|
||||
* WPML_Media_Attachment_Image_Update constructor.
|
||||
*
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( wpdb $wpdb ) {
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wp_ajax_wpml_media_upload_file', array( $this, 'handle_upload' ) );
|
||||
}
|
||||
|
||||
public function handle_upload() {
|
||||
if ( $this->is_valid_action() ) {
|
||||
|
||||
$original_attachment_id = (int) $_POST['original-attachment-id'];
|
||||
$attachment_id = (int) $_POST['attachment-id'];
|
||||
$file_array = $_FILES['file'];
|
||||
$target_language = $_POST['language'];
|
||||
|
||||
$thumb_path = '';
|
||||
$thumb_url = '';
|
||||
|
||||
$upload_overrides = apply_filters( 'wpml_media_wp_upload_overrides', array( 'test_form' => false ) );
|
||||
$file = wp_handle_upload( $file_array, $upload_overrides );
|
||||
|
||||
if ( ! isset( $file['error'] ) ) {
|
||||
|
||||
if ( wp_image_editor_supports( array( 'mime_type' => $file['type'] ) ) ) {
|
||||
|
||||
$editor = wp_get_image_editor( $file['file'] );
|
||||
|
||||
if ( ! is_wp_error( $editor ) ) {
|
||||
|
||||
$size = $editor->get_size();
|
||||
if ( $size['width'] > 150 || $size['height'] > 150 ) {
|
||||
$resizing = $editor->resize( 150, 150, true );
|
||||
|
||||
if ( is_wp_error( $resizing ) ) {
|
||||
wp_send_json_error( $resizing->get_error_message() );
|
||||
}
|
||||
}
|
||||
$thumb = $editor->save();
|
||||
|
||||
if ( ! empty( $thumb ) ) {
|
||||
$uploads_dir = wp_get_upload_dir();
|
||||
|
||||
$thumb_url = $uploads_dir['baseurl'] . $uploads_dir['subdir'] . '/' . $thumb['file'];
|
||||
$thumb_path = $thumb['path'];
|
||||
}
|
||||
} else {
|
||||
wp_send_json_error( __( 'Failed to load the image editor', 'wpml-media' ) );
|
||||
}
|
||||
} elseif ( 0 === strpos( $file['type'], 'image/' ) ) {
|
||||
$thumb_url = $file['url'];
|
||||
$thumb_path = $file['file'];
|
||||
} else {
|
||||
$thumb_url = wp_mime_type_icon( $original_attachment_id );
|
||||
}
|
||||
|
||||
set_transient(
|
||||
self::TRANSIENT_FILE_UPLOAD_PREFIX . $original_attachment_id . '_' . $target_language,
|
||||
array(
|
||||
'upload' => $file,
|
||||
'thumb' => $thumb_path,
|
||||
),
|
||||
HOUR_IN_SECONDS
|
||||
);
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'attachment_id' => $attachment_id,
|
||||
'thumb' => $thumb_url,
|
||||
'name' => basename( $file['file'] ),
|
||||
)
|
||||
);
|
||||
|
||||
} else {
|
||||
wp_send_json_error( $file['error'] );
|
||||
}
|
||||
} else {
|
||||
wp_send_json_error( 'invalid action' );
|
||||
}
|
||||
}
|
||||
|
||||
private function is_valid_action() {
|
||||
$is_attachment_id = isset( $_POST['attachment-id'] );
|
||||
$is_post_action = isset( $_POST['action'] ) && 'wpml_media_upload_file' === $_POST['action'];
|
||||
|
||||
return $is_attachment_id && $is_post_action && wp_verify_nonce( $_POST['wpnonce'], 'media-translation' );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Caption_Tags_Parse
|
||||
*/
|
||||
class WPML_Media_Caption_Tags_Parse {
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_captions( $text ) {
|
||||
$captions = array();
|
||||
|
||||
if ( preg_match_all( '/\[caption (.+)\](.+)\[\/caption\]/sU', $text, $matches ) ) {
|
||||
|
||||
for ( $i = 0; $i < count( $matches[0] ); $i++ ) {
|
||||
$captions[] = new WPML_Media_Caption( $matches[0][ $i ], $matches[1][ $i ], $matches[2][ $i ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $captions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Caption
|
||||
*/
|
||||
class WPML_Media_Caption {
|
||||
|
||||
private $shortcode;
|
||||
private $content_string;
|
||||
private $attributes;
|
||||
private $attachment_id;
|
||||
private $link;
|
||||
private $img;
|
||||
private $caption;
|
||||
|
||||
public function __construct( $caption_shortcode, $attributes_data, $content_string ) {
|
||||
$this->shortcode = $caption_shortcode;
|
||||
$this->content_string = $content_string;
|
||||
|
||||
$this->attributes = $this->find_attributes_array( $attributes_data );
|
||||
$this->attachment_id = $this->find_attachment_id( $this->attributes );
|
||||
|
||||
$this->link = $this->find_link( $content_string );
|
||||
|
||||
$img_parser = new WPML_Media_Img_Parse();
|
||||
$this->img = current( $img_parser->get_imgs( $content_string ) );
|
||||
$this->caption = trim( strip_tags( $content_string ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function get_id() {
|
||||
return $this->attachment_id;
|
||||
}
|
||||
|
||||
public function get_caption() {
|
||||
return $this->caption;
|
||||
}
|
||||
|
||||
public function get_shortcode_string() {
|
||||
return $this->shortcode;
|
||||
}
|
||||
|
||||
public function get_content() {
|
||||
return $this->content_string;
|
||||
}
|
||||
|
||||
public function get_image_alt() {
|
||||
if ( isset( $this->img['attributes']['alt'] ) ) {
|
||||
return $this->img['attributes']['alt'];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function get_link() {
|
||||
return $this->link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attributes_list
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function find_attributes_array( $attributes_list ) {
|
||||
$attributes = array();
|
||||
if ( preg_match_all( '/(\S+)=["\']?((?:.(?!["\']?\s+(?:\S+)=|[>"\']))+.)["\']?/', $attributes_list, $attribute_matches ) ) {
|
||||
foreach ( $attribute_matches[1] as $k => $key ) {
|
||||
$attributes[ $key ] = $attribute_matches[2][ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
private function find_attachment_id( $attributes ) {
|
||||
$attachment_id = null;
|
||||
if ( isset( $attributes['id'] ) ) {
|
||||
if ( preg_match( '/attachment_([0-9]+)\b/', $attributes['id'], $id_match ) ) {
|
||||
if ( 'attachment' === get_post_type( (int) $id_match[1] ) ) {
|
||||
$attachment_id = (int) $id_match[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $string
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function find_link( $string ) {
|
||||
$link = array();
|
||||
if ( preg_match( '/<a ([^>]+)>(.+)<\/a>/s', $string, $a_match ) ) {
|
||||
if ( preg_match( '/href=["\']([^"]+)["\']/', $a_match[1], $url_match ) ) {
|
||||
$link['url'] = $url_match[1];
|
||||
}
|
||||
}
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Custom_Field_Images_Translation_Factory
|
||||
*/
|
||||
class WPML_Media_Custom_Field_Images_Translation_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $sitepress, $iclTranslationManagement;
|
||||
|
||||
$media_localization_settings = WPML_Media::get_setting( 'media_files_localization' );
|
||||
|
||||
if ( $media_localization_settings['custom_fields'] || WPML_Media_Custom_Field_Batch_Url_Translation::is_ajax_request() ) {
|
||||
$image_translator = new WPML_Media_Image_Translate( $sitepress, new WPML_Media_Attachment_By_URL_Factory() );
|
||||
$image_updater = new WPML_Media_Translated_Images_Update( new WPML_Media_Img_Parse(), $image_translator, new WPML_Media_Sizes() );
|
||||
|
||||
return new WPML_Media_Custom_Field_Images_Translation( $image_updater, $sitepress, $iclTranslationManagement );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Custom_Field_Images_Translation
|
||||
* Translate images in posts custom fields translations when a custom field is created or updated
|
||||
*/
|
||||
class WPML_Media_Custom_Field_Images_Translation implements IWPML_Action {
|
||||
|
||||
/**
|
||||
* @var WPML_Media_Custom_Field_Images_Translation
|
||||
*/
|
||||
private $images_updater;
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
/**
|
||||
* @var TranslationManagement
|
||||
*/
|
||||
private $iclTranslationManagement;
|
||||
|
||||
/**
|
||||
* WPML_Media_Custom_Field_Images_Translation constructor.
|
||||
*
|
||||
* @param WPML_Media_Translated_Images_Update $images_updater
|
||||
* @param SitePress $sitepress
|
||||
* @param TranslationManagement $iclTranslationManagement
|
||||
*/
|
||||
public function __construct(
|
||||
WPML_Media_Translated_Images_Update $images_updater,
|
||||
SitePress $sitepress,
|
||||
TranslationManagement $iclTranslationManagement
|
||||
|
||||
) {
|
||||
$this->images_updater = $images_updater;
|
||||
$this->sitepress = $sitepress;
|
||||
$this->iclTranslationManagement = $iclTranslationManagement;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'updated_post_meta', array( $this, 'translate_images' ), PHP_INT_MAX, 4 );
|
||||
add_action( 'added_post_meta', array( $this, 'translate_images' ), PHP_INT_MAX, 4 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $meta_id
|
||||
* @param int $object_id
|
||||
* @param string $meta_key
|
||||
* @param string $meta_value
|
||||
*/
|
||||
public function translate_images( $meta_id, $object_id, $meta_key, $meta_value ) {
|
||||
|
||||
$settings_factory = new WPML_Custom_Field_Setting_Factory( $this->iclTranslationManagement );
|
||||
$setting = $settings_factory->post_meta_setting( $meta_key );
|
||||
|
||||
$is_custom_field_translatable = $this->sitepress->get_wp_api()
|
||||
->constant( 'WPML_TRANSLATE_CUSTOM_FIELD' ) === $setting->status();
|
||||
$post_type = get_post_type( $object_id );
|
||||
$is_post_translatable = $this->sitepress->is_translated_post_type( $post_type );
|
||||
|
||||
if ( is_string( $meta_value ) && $is_post_translatable && $is_custom_field_translatable ) {
|
||||
$post_element = new WPML_Post_Element( $object_id, $this->sitepress );
|
||||
$source_language = $post_element->get_source_language_code();
|
||||
if ( null !== $source_language ) {
|
||||
$this->filter_meta_value_and_update(
|
||||
$meta_value,
|
||||
$meta_key,
|
||||
$post_element->get_language_code(),
|
||||
$source_language,
|
||||
$object_id
|
||||
);
|
||||
} else {
|
||||
foreach ( array_keys( $this->sitepress->get_active_languages() ) as $language ) {
|
||||
$translation = $post_element->get_translation( $language );
|
||||
if ( $translation ) {
|
||||
$this->filter_meta_value_and_update(
|
||||
$meta_value,
|
||||
$meta_key,
|
||||
$language,
|
||||
$source_language,
|
||||
$translation->get_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $meta_value
|
||||
* @param string $meta_key
|
||||
* @param string $target_language
|
||||
* @param string $source_language
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function filter_meta_value_and_update( $meta_value, $meta_key, $target_language, $source_language, $post_id ) {
|
||||
$meta_value_filtered = $this->images_updater->replace_images_with_translations(
|
||||
$meta_value,
|
||||
$target_language,
|
||||
$source_language
|
||||
);
|
||||
|
||||
if ( $meta_value_filtered !== $meta_value ) {
|
||||
remove_action( 'updated_post_meta', array( $this, 'translate_images' ), PHP_INT_MAX );
|
||||
update_post_meta( $post_id, $meta_key, wp_slash( $meta_value_filtered ), $meta_value );
|
||||
add_action( 'updated_post_meta', array( $this, 'translate_images' ), PHP_INT_MAX, 4 );
|
||||
}
|
||||
|
||||
return $meta_value_filtered;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Image_Translate
|
||||
* Allows getting translated images in a give language from an attachment
|
||||
*/
|
||||
class WPML_Media_Image_Translate {
|
||||
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* @var WPML_Media_Attachment_By_URL_Factory
|
||||
*/
|
||||
private $attachment_by_url_factory;
|
||||
|
||||
/**
|
||||
* WPML_Media_Image_Translate constructor.
|
||||
*
|
||||
* @param SitePress $sitepress
|
||||
* @param WPML_Media_Attachment_By_URL_Factory $attachment_by_url_factory
|
||||
*/
|
||||
public function __construct( SitePress $sitepress, WPML_Media_Attachment_By_URL_Factory $attachment_by_url_factory ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->attachment_by_url_factory = $attachment_by_url_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $attachment_id
|
||||
* @param string $language
|
||||
* @param string $size
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_translated_image( $attachment_id, $language, $size = null ) {
|
||||
$image_url = '';
|
||||
$attachment = new WPML_Post_Element( $attachment_id, $this->sitepress );
|
||||
$attachment_translation = $attachment->get_translation( $language );
|
||||
|
||||
if ( $attachment_translation ) {
|
||||
$uploads_dir = wp_get_upload_dir();
|
||||
$attachment_id = $attachment_translation->get_id();
|
||||
if ( null === $size ) {
|
||||
$image_url = $uploads_dir['baseurl'] . '/' . get_post_meta( $attachment_id, '_wp_attached_file', true );
|
||||
} else {
|
||||
$image_url = $this->get_sized_image_url( $attachment_id, $size, $uploads_dir );
|
||||
}
|
||||
}
|
||||
|
||||
return $image_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $img_src
|
||||
* @param string $source_language
|
||||
* @param string $target_language
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_translated_image_by_url( $img_src, $source_language, $target_language ) {
|
||||
|
||||
$attachment_id = $this->get_attachment_id_by_url( $img_src, $source_language );
|
||||
|
||||
if ( $attachment_id ) {
|
||||
$size = $this->get_image_size_from_url( $img_src, $attachment_id );
|
||||
try {
|
||||
$img_src = $this->get_translated_image( $attachment_id, $target_language, $size );
|
||||
} catch ( Exception $e ) {
|
||||
$img_src = false;
|
||||
}
|
||||
} else {
|
||||
$img_src = false;
|
||||
}
|
||||
|
||||
return $img_src;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $img_src
|
||||
* @param string $source_language
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_attachment_id_by_url( $img_src, $source_language ) {
|
||||
$attachment_by_url = $this->attachment_by_url_factory->create( $img_src, $source_language );
|
||||
return (int) $attachment_by_url->get_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param int $attachment_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_image_size_from_url( $url, $attachment_id ) {
|
||||
$media_sizes = new WPML_Media_Sizes();
|
||||
return $media_sizes->get_image_size_from_url( $url, $attachment_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $attachment_id
|
||||
* @param $size
|
||||
* @param $uploads_dir
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_sized_image_url( $attachment_id, $size, $uploads_dir ) {
|
||||
$image_url = '';
|
||||
$meta_data = wp_get_attachment_metadata( $attachment_id );
|
||||
|
||||
if ( array_key_exists( $size, $meta_data['sizes'] ) ) {
|
||||
$image_url_parts = array( $uploads_dir['baseurl'] );
|
||||
|
||||
if ( array_key_exists( 'file', $meta_data ) ) {
|
||||
$file_subdirectory = $meta_data['file'];
|
||||
$file_subdirectory_parts = explode( '/', $file_subdirectory );
|
||||
|
||||
array_pop( $file_subdirectory_parts );
|
||||
$image_url_parts[] = implode( '/', $file_subdirectory_parts );
|
||||
}
|
||||
$image_url_parts[] = $meta_data['sizes'][ $size ]['file'];
|
||||
|
||||
$image_url = implode( '/', $image_url_parts );
|
||||
}
|
||||
|
||||
return $image_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Img_Parse
|
||||
*/
|
||||
class WPML_Media_Img_Parse {
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_imgs( $text ) {
|
||||
$images = $this->get_from_img_tags( $text );
|
||||
|
||||
if ( $this->can_parse_blocks( $text ) ) {
|
||||
$blocks = parse_blocks( $text );
|
||||
$images = array_merge( $images, $this->get_from_css_background_images_in_blocks( $blocks ) );
|
||||
} else {
|
||||
$images = array_merge( $images, $this->get_from_css_background_images( $text ) );
|
||||
}
|
||||
|
||||
return $images;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_from_img_tags( $text ) {
|
||||
$images = array();
|
||||
|
||||
if ( preg_match_all( '/<img ([^>]+)>/s', $text, $matches ) ) {
|
||||
foreach ( $matches[1] as $i => $match ) {
|
||||
if ( preg_match_all( '/(\S+)\\s*=\\s*["\']?((?:.(?!["\']?\s+(?:\S+)=|[>"\']))+.)["\']?/', $match, $attribute_matches ) ) {
|
||||
$attributes = array();
|
||||
foreach ( $attribute_matches[1] as $k => $key ) {
|
||||
$attributes[ $key ] = $attribute_matches[2][ $k ];
|
||||
}
|
||||
if ( isset( $attributes['src'] ) ) {
|
||||
$images[ $i ]['attributes'] = $attributes;
|
||||
$images[ $i ]['attachment_id'] = $this->get_attachment_id_from_attributes( $images[ $i ]['attributes'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $images;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_from_css_background_images( $text ) {
|
||||
$images = array();
|
||||
|
||||
if ( preg_match_all( '/<\w+[^>]+style\s?=\s?"[^"]*?background-image:url\(\s?([^\s\)]+)\s?\)/', $text, $matches ) ) {
|
||||
foreach ( $matches[1] as $src ) {
|
||||
$images[] = array(
|
||||
'attributes' => array( 'src' => $src ),
|
||||
'attachment_id' => null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $images;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $blocks
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_from_css_background_images_in_blocks( $blocks ) {
|
||||
$images = array();
|
||||
|
||||
foreach ( $blocks as $block ) {
|
||||
$block = $this->sanitize_block( $block );
|
||||
|
||||
if ( ! empty( $block->innerBlocks ) ) {
|
||||
$inner_images = $this->get_from_css_background_images_in_blocks( $block->innerBlocks );
|
||||
$images = array_merge( $images, $inner_images );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! isset( $block->innerHTML, $block->attrs->id ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$background_images = $this->get_from_css_background_images( $block->innerHTML );
|
||||
$image = reset( $background_images );
|
||||
|
||||
if ( $image ) {
|
||||
$image['attachment_id'] = $block->attrs->id;
|
||||
$images[] = $image;
|
||||
}
|
||||
}
|
||||
|
||||
return $images;
|
||||
}
|
||||
|
||||
/**
|
||||
* `parse_blocks` does not specify which kind of collection it should return
|
||||
* (not always an array of `WP_Block_Parser_Block`) and the block parser can be filtered,
|
||||
* so we'll cast it to a standard object for now.
|
||||
*
|
||||
* @param mixed $block
|
||||
*
|
||||
* @return stdClass|WP_Block_Parser_Block
|
||||
*/
|
||||
private function sanitize_block( $block ) {
|
||||
$block = (object) $block;
|
||||
|
||||
if ( isset( $block->attrs ) ) {
|
||||
/** Sometimes `$block->attrs` is an object or an array, so we'll use an object */
|
||||
$block->attrs = (object) $block->attrs;
|
||||
}
|
||||
|
||||
return $block;
|
||||
}
|
||||
|
||||
function can_parse_blocks( $string ) {
|
||||
return false !== strpos( $string, '<!-- wp:' ) && function_exists( 'parse_blocks' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $attributes
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
private function get_attachment_id_from_attributes( $attributes ) {
|
||||
$attachment_id = null;
|
||||
if ( isset( $attributes['class'] ) ) {
|
||||
if ( preg_match( '/wp-image-([0-9]+)\b/', $attributes['class'], $id_match ) ) {
|
||||
if ( 'attachment' === get_post_type( (int) $id_match[1] ) ) {
|
||||
$attachment_id = (int) $id_match[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Post_Images_Translation_Factory
|
||||
*/
|
||||
class WPML_Media_Post_Images_Translation_Factory implements IWPML_REST_Action_Loader, IWPML_Backend_Action_Loader {
|
||||
|
||||
/**
|
||||
* @return IWPML_Action|null|WPML_Media_Post_Images_Translation
|
||||
*/
|
||||
public function create() {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$media_localization_settings = WPML_Media::get_setting( 'media_files_localization' );
|
||||
if ( $media_localization_settings['posts'] ) {
|
||||
$image_translator = new WPML_Media_Image_Translate( $sitepress, new WPML_Media_Attachment_By_URL_Factory() );
|
||||
$image_updater = new WPML_Media_Translated_Images_Update( new WPML_Media_Img_Parse(), $image_translator, new WPML_Media_Sizes() );
|
||||
|
||||
return new WPML_Media_Post_Images_Translation(
|
||||
$image_updater,
|
||||
$sitepress,
|
||||
$wpdb,
|
||||
new WPML_Translation_Element_Factory( $sitepress ),
|
||||
new WPML_Media_Custom_Field_Images_Translation_Factory(),
|
||||
new WPML_Media_Usage_Factory()
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Post_Images_Translation
|
||||
* Translate images in posts translations when a post is created or updated
|
||||
*/
|
||||
class WPML_Media_Post_Images_Translation implements IWPML_Action {
|
||||
|
||||
/**
|
||||
* @var WPML_Media_Translated_Images_Update
|
||||
*/
|
||||
private $images_updater;
|
||||
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
/**
|
||||
* @var WPML_Translation_Element_Factory
|
||||
*/
|
||||
private $translation_element_factory;
|
||||
/**
|
||||
* @var WPML_Media_Custom_Field_Images_Translation_Factory
|
||||
*/
|
||||
private $custom_field_images_translation_factory;
|
||||
/**
|
||||
* @var WPML_Media_Usage_Factory
|
||||
*/
|
||||
private $media_usage_factory;
|
||||
|
||||
private $captions_map = array();
|
||||
|
||||
private $translate_locks = array();
|
||||
|
||||
public function __construct(
|
||||
WPML_Media_Translated_Images_Update $images_updater,
|
||||
SitePress $sitepress,
|
||||
wpdb $wpdb,
|
||||
WPML_Translation_Element_Factory $translation_element_factory,
|
||||
WPML_Media_Custom_Field_Images_Translation_Factory $custom_field_images_translation_factory,
|
||||
WPML_Media_Usage_Factory $media_usage_factory
|
||||
) {
|
||||
$this->images_updater = $images_updater;
|
||||
$this->sitepress = $sitepress;
|
||||
$this->wpdb = $wpdb;
|
||||
$this->translation_element_factory = $translation_element_factory;
|
||||
$this->custom_field_images_translation_factory = $custom_field_images_translation_factory;
|
||||
$this->media_usage_factory = $media_usage_factory;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'save_post', array( $this, 'translate_images' ), PHP_INT_MAX, 1 );
|
||||
add_filter( 'wpml_pre_save_pro_translation', array( $this, 'translate_images_in_content' ), PHP_INT_MAX, 2 );
|
||||
add_filter( 'wpml_pre_save_pro_translation', array(
|
||||
$this,
|
||||
'replace_placeholders_and_id_in_caption_shortcode'
|
||||
), PHP_INT_MAX, 2 );
|
||||
add_action( 'wpml_tm_job_fields',
|
||||
array( $this, 'replace_caption_placeholders_in_fields' ), 10, 2 );
|
||||
add_filter( 'wpml_tm_job_data_post_content', array(
|
||||
$this,
|
||||
'restore_placeholders_in_translated_job_body'
|
||||
), 10, 1 );
|
||||
|
||||
add_action( 'icl_make_duplicate', array( $this, 'translate_images_in_duplicate' ), PHP_INT_MAX, 4 );
|
||||
|
||||
add_action( 'wpml_added_media_file_translation', array( $this, 'translate_url_in_post' ), PHP_INT_MAX, 1 );
|
||||
add_action( 'wpml_pro_translation_completed', array( $this, 'translate_images' ), PHP_INT_MAX, 1 );
|
||||
add_action( 'wpml_restored_media_file_translation', array( $this, 'translate_url_in_post' ), PHP_INT_MAX, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*/
|
||||
public function translate_images( $post_id ) {
|
||||
if ( isset( $this->translate_locks[ $post_id ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->translate_locks[ $post_id ] = true;
|
||||
|
||||
$post = get_post( $post_id );
|
||||
|
||||
if ( ! $post ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var WPML_Post_Element $post_element */
|
||||
$post_element = $this->translation_element_factory->create( $post_id, 'post' );
|
||||
$source_language = $post_element->get_source_language_code();
|
||||
|
||||
if ( null !== $source_language ) {
|
||||
|
||||
$this->translate_images_in_post_content( $post, $post_element );
|
||||
$this->translate_images_in_custom_fields( $post_id );
|
||||
|
||||
} else { // is original
|
||||
foreach ( array_keys( $this->sitepress->get_active_languages() ) as $target_language ) {
|
||||
/** @var WPML_Post_Element $translation */
|
||||
$translation = $post_element->get_translation( $target_language );
|
||||
if ( null !== $translation && $post_id !== $translation->get_id() ) {
|
||||
$this->translate_images_in_post_content( get_post( $translation->get_id() ), $translation );
|
||||
$this->translate_images_in_custom_fields( $translation->get_id() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unset( $this->translate_locks[ $post_id ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $master_post_id
|
||||
* @param string $language
|
||||
* @param array $post_array
|
||||
* @param int $post_id
|
||||
*/
|
||||
public function translate_images_in_duplicate( $master_post_id, $language, $post_array, $post_id ) {
|
||||
$this->translate_images( $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Post $post
|
||||
* @param WPML_Post_Element $post_element
|
||||
*/
|
||||
private function translate_images_in_post_content( WP_Post $post, WPML_Post_Element $post_element ) {
|
||||
|
||||
if ( (bool) apply_filters( 'wpml_pb_should_body_be_translated', true, $post, 'translate_images_in_post_content' ) ) {
|
||||
$post_content_filtered = $this->images_updater->replace_images_with_translations(
|
||||
$post->post_content,
|
||||
$post_element->get_language_code(),
|
||||
$post_element->get_source_language_code()
|
||||
);
|
||||
|
||||
if ( $post_content_filtered !== $post->post_content ) {
|
||||
$this->wpdb->update(
|
||||
$this->wpdb->posts,
|
||||
array( 'post_content' => $post_content_filtered ),
|
||||
array( 'ID' => $post->ID ),
|
||||
array( '%s' ),
|
||||
array( '%d' )
|
||||
);
|
||||
}
|
||||
} elseif ( $this->is_updated_from_media_translation_menu() ) {
|
||||
do_action( 'wpml_pb_resave_post_translation', $post_element );
|
||||
}
|
||||
}
|
||||
|
||||
private function is_updated_from_media_translation_menu() {
|
||||
$allowed_actions = array(
|
||||
'wpml_media_save_translation',
|
||||
'wpml_media_translate_media_url_in_posts',
|
||||
);
|
||||
|
||||
return isset( $_POST['action'] ) && in_array( $_POST['action'], $allowed_actions, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*/
|
||||
private function translate_images_in_custom_fields( $post_id ) {
|
||||
|
||||
$custom_fields_image_translation = $this->custom_field_images_translation_factory->create();
|
||||
if ( $custom_fields_image_translation ) {
|
||||
$post_meta = get_metadata( 'post', $post_id );
|
||||
foreach ( $post_meta as $meta_key => $meta_value ) {
|
||||
$custom_fields_image_translation->translate_images( null, $post_id, $meta_key, $meta_value[0] );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $postarr
|
||||
* @param stdClass $job
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function translate_images_in_content( array $postarr, stdclass $job ) {
|
||||
|
||||
$postarr['post_content'] = $this->images_updater->replace_images_with_translations(
|
||||
$postarr['post_content'],
|
||||
$job->language_code,
|
||||
$job->source_language_code
|
||||
);
|
||||
|
||||
return $postarr;
|
||||
}
|
||||
|
||||
public function translate_url_in_post( $attachment_id, $posts = array() ) {
|
||||
if ( ! $posts ) {
|
||||
$media_usage = $this->media_usage_factory->create( $attachment_id );
|
||||
$posts = $media_usage->get_posts();
|
||||
}
|
||||
|
||||
foreach ( $posts as $post_id ) {
|
||||
$this->translate_images( $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
public function replace_placeholders_and_id_in_caption_shortcode( array $postarr, stdClass $job ) {
|
||||
|
||||
$media = $this->find_media_in_job( $job );
|
||||
|
||||
$postarr['post_content'] = $this->replace_caption_placeholders_in_string(
|
||||
$postarr['post_content'],
|
||||
$media,
|
||||
$job->language_code
|
||||
);
|
||||
|
||||
return $postarr;
|
||||
}
|
||||
|
||||
public function replace_caption_placeholders_in_string( $text, $media, $language ) {
|
||||
|
||||
$caption_parser = new WPML_Media_Caption_Tags_Parse();
|
||||
$captions = $caption_parser->get_captions( $text );
|
||||
|
||||
foreach ( $captions as $caption ) {
|
||||
$attachment_id = $caption->get_id();
|
||||
$caption_shortcode = $new_caption_shortcode = $caption->get_shortcode_string();
|
||||
|
||||
if ( isset( $media[ $attachment_id ] ) ) {
|
||||
|
||||
if ( isset( $media[ $attachment_id ]['caption'] ) ) {
|
||||
$new_caption_shortcode = $this->replace_placeholder_with_caption( $new_caption_shortcode, $caption, $media[ $attachment_id ]['caption'] );
|
||||
}
|
||||
|
||||
if ( isset( $media[ $attachment_id ]['alt'] ) ) {
|
||||
$new_caption_shortcode = $this->replace_placeholder_with_alt_text( $new_caption_shortcode, $caption, $media[ $attachment_id ]['alt'] );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( $attachment_id ) {
|
||||
$new_caption_shortcode = $this->replace_caption_id_with_translated_id(
|
||||
$new_caption_shortcode,
|
||||
$attachment_id,
|
||||
$language
|
||||
);
|
||||
}
|
||||
|
||||
if ( $new_caption_shortcode !== $caption_shortcode ) {
|
||||
$text = str_replace( $caption_shortcode, $new_caption_shortcode, $text );
|
||||
$this->captions_map[ $caption_shortcode ] = $new_caption_shortcode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $new_post_id
|
||||
* @param array $fields
|
||||
* @param stdClass $job
|
||||
*/
|
||||
public function replace_caption_placeholders_in_fields( array $fields, stdClass $job ) {
|
||||
|
||||
$media = $this->find_media_in_job( $job );
|
||||
|
||||
foreach ( $fields as $field_id => $field ) {
|
||||
$fields[ $field_id ]['data'] = $this->replace_caption_placeholders_in_string(
|
||||
$field['data'],
|
||||
$media,
|
||||
$job->language_code
|
||||
);
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
private function replace_placeholder_with_caption( $caption_shortcode, WPML_Media_Caption $caption, $new_caption ) {
|
||||
$caption_content = $caption->get_content();
|
||||
$new_caption_content = str_replace( WPML_Media_Add_To_Translation_Package::CAPTION_PLACEHOLDER, $new_caption, $caption_content );
|
||||
|
||||
return str_replace( $caption_content, $new_caption_content, $caption_shortcode );
|
||||
}
|
||||
|
||||
private function replace_placeholder_with_alt_text( $caption_shortcode, WPML_Media_Caption $caption, $new_alt_text ) {
|
||||
return str_replace( 'alt="' . WPML_Media_Add_To_Translation_Package::ALT_PLACEHOLDER . '"', 'alt="' . $new_alt_text . '"', $caption_shortcode );
|
||||
}
|
||||
|
||||
private function replace_caption_id_with_translated_id( $caption_shortcode, $attachment_id, $language ) {
|
||||
$post_element = $this->translation_element_factory->create( $attachment_id, 'post' );
|
||||
$translation = $post_element->get_translation( $language );
|
||||
if ( $translation ) {
|
||||
|
||||
$translated_id = $translation->get_id();
|
||||
|
||||
$caption_shortcode = str_replace(
|
||||
'id="attachment_' . $attachment_id . '"',
|
||||
'id="attachment_' . $translated_id . '"',
|
||||
$caption_shortcode
|
||||
);
|
||||
}
|
||||
|
||||
return $caption_shortcode;
|
||||
}
|
||||
private function find_media_in_job( stdClass $job ) {
|
||||
$media = array();
|
||||
|
||||
foreach ( $job->elements as $element ) {
|
||||
$field_type = explode( '_', $element->field_type );
|
||||
if ( 'media' === $field_type[0] ) {
|
||||
if ( ! isset( $media[ $field_type[1] ] ) ) {
|
||||
$media[ $field_type[1] ] = array();
|
||||
}
|
||||
$media[ $field_type[1] ][ $field_type[2] ] = base64_decode( $element->field_data_translated );
|
||||
}
|
||||
}
|
||||
|
||||
return $media;
|
||||
}
|
||||
|
||||
public function restore_placeholders_in_translated_job_body( $new_body ) {
|
||||
/**
|
||||
* Translation management is updating the translated job data with the post_content
|
||||
* from the translated post.
|
||||
* We want the translated job data to contain the placeholders so we need to
|
||||
* find the captions we replaced and restore it with the version with the placeholders
|
||||
*/
|
||||
|
||||
foreach ( $this->captions_map as $caption_with_placeholder => $caption_in_post ) {
|
||||
$new_body = str_replace( $caption_in_post, $caption_with_placeholder, $new_body );
|
||||
}
|
||||
$this->captions_map = array();
|
||||
|
||||
return $new_body;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Post_With_Media_Files_Factory {
|
||||
/**
|
||||
* @param $post_id
|
||||
*
|
||||
* @return WPML_Media_Post_With_Media_Files
|
||||
*/
|
||||
public function create( $post_id ) {
|
||||
global $sitepress, $iclTranslationManagement;
|
||||
|
||||
return new WPML_Media_Post_With_Media_Files(
|
||||
$post_id,
|
||||
new WPML_Media_Img_Parse(),
|
||||
new WPML_Media_Attachment_By_URL_Factory(),
|
||||
$sitepress,
|
||||
new WPML_Custom_Field_Setting_Factory( $iclTranslationManagement )
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Post_With_Media_Files {
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $post_id;
|
||||
/**
|
||||
* @var WPML_Media_Img_Parse
|
||||
*/
|
||||
private $media_parser;
|
||||
/**
|
||||
* @var WPML_Media_Attachment_By_URL_Factory
|
||||
*/
|
||||
private $attachment_by_url_factory;
|
||||
/**
|
||||
* @var SitePress $sitepress
|
||||
*/
|
||||
private $sitepress;
|
||||
/**
|
||||
* @var WPML_Custom_Field_Setting_Factory
|
||||
*/
|
||||
private $cf_settings_factory;
|
||||
|
||||
/**
|
||||
* WPML_Media_Post_With_Media_Files constructor.
|
||||
*
|
||||
* @param $post_id
|
||||
* @param WPML_Media_Img_Parse $media_parser
|
||||
* @param WPML_Media_Attachment_By_URL_Factory $attachment_by_url_factory
|
||||
* @param SitePress $sitepress
|
||||
* @param WPML_Custom_Field_Setting_Factory $cf_settings_factory
|
||||
*/
|
||||
public function __construct(
|
||||
$post_id,
|
||||
WPML_Media_Img_Parse $media_parser,
|
||||
WPML_Media_Attachment_By_URL_Factory $attachment_by_url_factory,
|
||||
SitePress $sitepress,
|
||||
WPML_Custom_Field_Setting_Factory $cf_settings_factory
|
||||
) {
|
||||
$this->post_id = $post_id;
|
||||
$this->media_parser = $media_parser;
|
||||
$this->attachment_by_url_factory = $attachment_by_url_factory;
|
||||
$this->sitepress = $sitepress;
|
||||
$this->cf_settings_factory = $cf_settings_factory;
|
||||
}
|
||||
|
||||
public function get_media_ids() {
|
||||
$media_ids = array();
|
||||
|
||||
if ( $post = get_post( $this->post_id ) ) {
|
||||
|
||||
$content_to_parse = apply_filters( 'wpml_media_content_for_media_usage', $post->post_content, $post );
|
||||
$post_content_media = $this->media_parser->get_imgs( $content_to_parse );
|
||||
$media_ids = $this->_get_ids_from_media_array( $post_content_media );
|
||||
|
||||
if ( $featured_image = get_post_meta( $this->post_id, '_thumbnail_id', true ) ) {
|
||||
$media_ids[] = $featured_image;
|
||||
}
|
||||
|
||||
$media_localization_settings = WPML_Media::get_setting( 'media_files_localization' );
|
||||
if ( $media_localization_settings['custom_fields'] ) {
|
||||
$custom_fields_content = $this->get_content_in_translatable_custom_fields();
|
||||
$custom_fields_media = $this->media_parser->get_imgs( $custom_fields_content );
|
||||
$media_ids = array_merge( $media_ids, $this->_get_ids_from_media_array( $custom_fields_media ) );
|
||||
}
|
||||
|
||||
if ( $gallery_media_ids = $this->get_gallery_media_ids( $content_to_parse ) ) {
|
||||
$media_ids = array_unique( array_values( array_merge( $media_ids, $gallery_media_ids ) ) );
|
||||
}
|
||||
|
||||
if ( $attached_media_ids = $this->get_attached_media_ids( $this->post_id ) ) {
|
||||
$media_ids = array_unique( array_values( array_merge( $media_ids, $attached_media_ids ) ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return apply_filters( 'wpml_ids_of_media_used_in_post', $media_ids, $this->post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $media_array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _get_ids_from_media_array( $media_array ) {
|
||||
$media_ids = array();
|
||||
foreach ( $media_array as $media ) {
|
||||
if ( isset( $media['attachment_id'] ) ) {
|
||||
$media_ids[] = $media['attachment_id'];
|
||||
} else {
|
||||
$attachment_by_url = $this->attachment_by_url_factory->create( $media['attributes']['src'], wpml_get_current_language() );
|
||||
if ( $attachment_id = $attachment_by_url->get_id() ) {
|
||||
$media_ids[] = $attachment_id;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $media_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $post_content
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_gallery_media_ids( $post_content ) {
|
||||
|
||||
$galleries_media_ids = array();
|
||||
$gallery_shortcode_regex = '/\[gallery [^[]*ids=["\']([0-9,\s]+)["\'][^[]*\]/m';
|
||||
if ( preg_match_all( $gallery_shortcode_regex, $post_content, $matches ) ) {
|
||||
foreach ( $matches[1] as $gallery_ids_string ) {
|
||||
$media_ids_array = explode( ',', $gallery_ids_string );
|
||||
foreach ( $media_ids_array as $media_id ) {
|
||||
if ( 'attachment' === get_post_type ( $media_id ) ) {
|
||||
$galleries_media_ids[] = (int) $media_id;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $galleries_media_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $languages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_untranslated_media( $languages ) {
|
||||
|
||||
$untranslated_media = array();
|
||||
|
||||
$post_media = $this->get_media_ids();
|
||||
|
||||
foreach ( $post_media as $attachment_id ) {
|
||||
|
||||
$post_element = new WPML_Post_Element( $attachment_id, $this->sitepress );
|
||||
foreach ( $languages as $language ) {
|
||||
$translation = $post_element->get_translation( $language );
|
||||
if ( null === $translation || ! $this->media_file_is_translated( $attachment_id, $translation->get_id() ) ) {
|
||||
$untranslated_media[] = $attachment_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $untranslated_media;
|
||||
}
|
||||
|
||||
private function media_file_is_translated( $attachment_id, $translated_attachment_id ) {
|
||||
return get_post_meta( $attachment_id, '_wp_attached_file', true )
|
||||
!== get_post_meta( $translated_attachment_id, '_wp_attached_file', true );
|
||||
}
|
||||
|
||||
private function get_content_in_translatable_custom_fields() {
|
||||
$content = '';
|
||||
|
||||
$post_meta = get_metadata( 'post', $this->post_id );
|
||||
|
||||
foreach ( $post_meta as $meta_key => $meta_value ) {
|
||||
$setting = $this->cf_settings_factory->post_meta_setting( $meta_key );
|
||||
$is_translatable = $this->sitepress->get_wp_api()
|
||||
->constant( 'WPML_TRANSLATE_CUSTOM_FIELD' ) === $setting->status();
|
||||
if ( is_string( $meta_value[0] ) && $is_translatable ) {
|
||||
$content .= $meta_value[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
private function get_attached_media_ids( $post_id ) {
|
||||
$attachments = get_children(
|
||||
array(
|
||||
'post_parent' => $post_id,
|
||||
'post_status' => 'inherit',
|
||||
'post_type' => 'attachment',
|
||||
)
|
||||
);
|
||||
return array_keys( $attachments );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Save_Translation_Factory
|
||||
*/
|
||||
class WPML_Media_Save_Translation_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $sitepress, $wpdb;
|
||||
|
||||
return new WPML_Media_Save_Translation( $sitepress, $wpdb, new WPML_Media_File_Factory(), new WPML_Translation_Element_Factory( $sitepress ) );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Save_Translation implements IWPML_Action {
|
||||
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
/**
|
||||
* @var WPML_Media_File_Factory
|
||||
*/
|
||||
private $media_file_factory;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $post_data;
|
||||
/**
|
||||
* @var WPML_Translation_Element_Factory
|
||||
*/
|
||||
private $translation_element_factory;
|
||||
|
||||
|
||||
/**
|
||||
* WPML_Media_Save_Translation constructor.
|
||||
*
|
||||
* @param SitePress $sitepress
|
||||
* @param wpdb $wpdb
|
||||
* @param WPML_Media_File_Factory $media_file_factory
|
||||
* @param WPML_Translation_Element_Factory $translation_element_factory
|
||||
*/
|
||||
public function __construct( SitePress $sitepress, wpdb $wpdb, WPML_Media_File_Factory $media_file_factory, WPML_Translation_Element_Factory $translation_element_factory ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->wpdb = $wpdb;
|
||||
$this->media_file_factory = $media_file_factory;
|
||||
$this->translation_element_factory = $translation_element_factory;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wp_ajax_wpml_media_save_translation', array( $this, 'save_media_translation' ) );
|
||||
}
|
||||
|
||||
public function save_media_translation() {
|
||||
|
||||
if ( wp_verify_nonce( $_POST['wpnonce'], 'media-translation' ) ) {
|
||||
$post_array['ID'] = (int) $_POST['translated-attachment-id'];
|
||||
$original_attachment_id = (int) $_POST['original-attachment-id'];
|
||||
$translated_language = sanitize_text_field( $_POST['translated-language'] );
|
||||
|
||||
if ( isset( $_POST['translation']['title'] ) ) {
|
||||
$post_array['post_title'] = sanitize_text_field( $_POST['translation']['title'] );
|
||||
}
|
||||
if ( isset( $_POST['translation']['caption'] ) ) {
|
||||
$post_array['post_excerpt'] = sanitize_text_field( $_POST['translation']['caption'] );
|
||||
}
|
||||
if ( isset( $_POST['translation']['description'] ) ) {
|
||||
$post_array['post_content'] = sanitize_text_field( $_POST['translation']['description'] );
|
||||
}
|
||||
|
||||
if ( $post_array['ID'] ) {
|
||||
$attachment_id = wp_update_post( $post_array );
|
||||
|
||||
if ( $this->should_restore_media() ) {
|
||||
$this->restore_media_file( $attachment_id, $original_attachment_id, $translated_language );
|
||||
}
|
||||
} else {
|
||||
|
||||
$post_array['post_type'] = 'attachment';
|
||||
$post_array['post_status'] = 'inherit';
|
||||
$post_array['guid'] = get_post_field( 'guid', $original_attachment_id );
|
||||
$post_array['post_mime_type'] = get_post_field( 'post_mime_type', $original_attachment_id );
|
||||
|
||||
$attachment_id = $this->create_attachment_translation( $original_attachment_id, $post_array );
|
||||
|
||||
$this->sitepress->set_element_language_details(
|
||||
$attachment_id,
|
||||
'post_attachment',
|
||||
$this->get_post_trid_value(),
|
||||
$this->get_post_lang_value()
|
||||
);
|
||||
|
||||
if ( ! $this->has_media_upload() ) {
|
||||
$this->copy_attached_file_info_from_original( $attachment_id, $original_attachment_id );
|
||||
}
|
||||
|
||||
$this->mark_media_as_not_translated( $attachment_id, $translated_language );
|
||||
|
||||
}
|
||||
$translation_status = WPML_Media_Translation_Status::NEEDS_MEDIA_TRANSLATION;
|
||||
|
||||
if ( $this->has_media_upload() ) {
|
||||
$this->update_media_file( $attachment_id, $original_attachment_id, $translated_language );
|
||||
$translation_status = WPML_Media_Translation_Status::TRANSLATED;
|
||||
}
|
||||
|
||||
if ( isset( $_POST['translation']['alt-text'] ) ) {
|
||||
update_post_meta(
|
||||
$attachment_id,
|
||||
'_wp_attachment_image_alt',
|
||||
sanitize_text_field( $_POST['translation']['alt-text'] )
|
||||
);
|
||||
}
|
||||
|
||||
if ( 0 === strpos( get_post_field( 'post_mime_type', $original_attachment_id ), 'image/' ) ) {
|
||||
$translated_thumb = wp_get_attachment_thumb_url( $attachment_id );
|
||||
$original_thumb = wp_get_attachment_thumb_url( $original_attachment_id );
|
||||
$media_file_is_translated = $translated_thumb !== $original_thumb;
|
||||
} else {
|
||||
$media_file_is_translated = get_attached_file( $attachment_id ) !== get_attached_file( $original_attachment_id );
|
||||
$translated_thumb = wp_mime_type_icon( $original_attachment_id );
|
||||
}
|
||||
|
||||
$media_usage = get_post_meta( $original_attachment_id, WPML_Media_Usage::FIELD_NAME, true );
|
||||
$posts_list = array();
|
||||
if ( isset( $media_usage['posts'] ) ) {
|
||||
foreach ( $media_usage['posts'] as $post_id ) {
|
||||
$post_element = $this->translation_element_factory->create( $post_id, 'post' );
|
||||
$post_translation = $post_element->get_translation( $translated_language );
|
||||
if ( $post_translation ) {
|
||||
$posts_list[] = array(
|
||||
'url' => get_edit_post_link( $post_translation->get_id() ),
|
||||
'title' => get_post_field( 'post_title', $post_translation->get_id() ),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $media_usage['posts'] ) && $this->should_restore_media() ) {
|
||||
do_action( 'wpml_restored_media_file_translation', $attachment_id, $media_usage['posts'] );
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'attachment_id' => $attachment_id,
|
||||
'thumb' => $media_file_is_translated ? $translated_thumb : false,
|
||||
'status' => $translation_status,
|
||||
'usage' => $posts_list,
|
||||
);
|
||||
|
||||
wp_send_json_success( $response );
|
||||
} else {
|
||||
wp_send_json_error( array( 'error' => __( 'Invalid nonce', 'wpml-media' ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
private function has_media_upload() {
|
||||
return ! empty( $_POST['update-media-file'] );
|
||||
}
|
||||
|
||||
private function should_restore_media() {
|
||||
return ! empty( $_POST['restore-media'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $original_attachment_id
|
||||
* @param array $post_array
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function create_attachment_translation( $original_attachment_id, $post_array ) {
|
||||
|
||||
$post_element = $this->translation_element_factory->create( $original_attachment_id, 'post' );
|
||||
$this->set_post_trid_value( $post_element->get_trid() );
|
||||
$this->set_post_lang_value( $_POST['translated-language'] );
|
||||
|
||||
add_filter( 'wpml_tm_save_post_trid_value', array( $this, 'get_post_trid_value' ) );
|
||||
add_filter( 'wpml_tm_save_post_lang_value', array( $this, 'get_post_lang_value' ) );
|
||||
|
||||
$attachment_id = wp_insert_post( $post_array );
|
||||
|
||||
remove_filter( 'wpml_tm_save_post_trid_value', array( $this, 'get_post_trid_value' ) );
|
||||
remove_filter( 'wpml_tm_save_post_lang_value', array( $this, 'get_post_lang_value' ) );
|
||||
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
private function set_post_trid_value( $value ) {
|
||||
$this->post_data['post_icl_trid'] = $value;
|
||||
}
|
||||
|
||||
public function get_post_trid_value() {
|
||||
return $this->post_data['post_icl_trid'];
|
||||
}
|
||||
|
||||
private function set_post_lang_value( $value ) {
|
||||
$this->post_data['post_icl_language'] = $value;
|
||||
}
|
||||
|
||||
public function get_post_lang_value() {
|
||||
return $this->post_data['post_icl_language'];
|
||||
}
|
||||
|
||||
private function restore_media_file( $attachment_id, $original_attachment_id, $language ) {
|
||||
|
||||
$media_file = $this->media_file_factory->create( $attachment_id );
|
||||
$media_file->delete();
|
||||
|
||||
$this->copy_attached_file_info_from_original( $attachment_id, $original_attachment_id );
|
||||
$this->mark_media_as_not_translated( $original_attachment_id, $language );
|
||||
}
|
||||
|
||||
private function copy_attached_file_info_from_original( $attachment_id, $original_attachment_id ) {
|
||||
$meta_keys = array(
|
||||
'_wp_attachment_metadata',
|
||||
'_wp_attached_file',
|
||||
'_wp_attachment_backup_sizes',
|
||||
);
|
||||
foreach ( $meta_keys as $meta_key ) {
|
||||
update_post_meta(
|
||||
$attachment_id,
|
||||
$meta_key,
|
||||
get_post_meta( $original_attachment_id, $meta_key, true )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires after attachment post meta is copied
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @param int $original_attachment_id The ID of the source/original attachment.
|
||||
* @param int $attachment_id The ID of the duplicated attachment.
|
||||
*/
|
||||
do_action( 'wpml_after_copy_attached_file_postmeta', $original_attachment_id, $attachment_id );
|
||||
}
|
||||
|
||||
private function mark_media_as_not_translated( $attachment_id, $language ) {
|
||||
update_post_meta( $attachment_id, WPML_Media_Translation_Status::STATUS_PREFIX . $language, WPML_Media_Translation_Status::NEEDS_MEDIA_TRANSLATION );
|
||||
}
|
||||
|
||||
private function mark_media_as_translated( $attachment_id, $language ) {
|
||||
update_post_meta( $attachment_id, WPML_Media_Translation_Status::STATUS_PREFIX . $language, WPML_Media_Translation_Status::TRANSLATED );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $file
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_attachment_post_data( $file ) {
|
||||
$postarr = array(
|
||||
'post_mime_type' => $file['type'],
|
||||
'guid' => $file['url'],
|
||||
'post_modified' => current_time( 'mysql' ),
|
||||
'post_modified_gmt' => current_time( 'mysql', 1 ),
|
||||
);
|
||||
|
||||
return $postarr;
|
||||
}
|
||||
|
||||
private function update_media_file( $attachment_id, $original_attachment_id, $translated_language_code ) {
|
||||
$transient_key = WPML_Media_Attachment_Image_Update::TRANSIENT_FILE_UPLOAD_PREFIX . $original_attachment_id . '_' . $translated_language_code;
|
||||
|
||||
$media_file_upload = get_transient( $transient_key );
|
||||
if ( $media_file_upload ) {
|
||||
|
||||
$file = $media_file_upload['upload'];
|
||||
|
||||
// delete previous media file + sizes
|
||||
$media_file = $this->media_file_factory->create( $attachment_id );
|
||||
$media_file->delete();
|
||||
|
||||
$post_data = $this->get_attachment_post_data( $file );
|
||||
$this->wpdb->update( $this->wpdb->posts, $post_data, array( 'ID' => $attachment_id ) );
|
||||
update_attached_file( $attachment_id, $file['file'] );
|
||||
|
||||
/**
|
||||
* Fires after attached file is updated
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @param int $attachment_id The ID of uploaded attachment.
|
||||
* @param array $file {
|
||||
* Uploaded file data.
|
||||
*
|
||||
* @type string file Absolute path to file.
|
||||
*
|
||||
* @type string url File URL.
|
||||
*
|
||||
* @type string type File type.
|
||||
* }
|
||||
* @param string $translated_language_code Attachment language code.
|
||||
*/
|
||||
do_action( 'wpml_updated_attached_file', $attachment_id, $file, $translated_language_code );
|
||||
|
||||
wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file['file'] ) );
|
||||
|
||||
$this->mark_media_as_translated( $original_attachment_id, $translated_language_code );
|
||||
do_action( 'wpml_added_media_file_translation', $original_attachment_id, $file, $translated_language_code );
|
||||
|
||||
delete_transient( $transient_key );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Set_Posts_Media_Flag_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $wpdb;
|
||||
|
||||
$post_media_usage_factory = new WPML_Media_Post_Media_Usage_Factory();
|
||||
|
||||
return new WPML_Media_Set_Posts_Media_Flag(
|
||||
$wpdb,
|
||||
wpml_get_admin_notices(),
|
||||
$post_media_usage_factory->create(),
|
||||
new WPML_Media_Post_With_Media_Files_Factory()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Set_Posts_Media_Flag implements IWPML_Action {
|
||||
const HAS_MEDIA_POST_FLAG = '_wpml_media_has_media';
|
||||
|
||||
const BATCH_SIZE = 100;
|
||||
/**
|
||||
* @var wpdb $wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
/**
|
||||
* @var WPML_Notices
|
||||
*/
|
||||
private $wpml_notices;
|
||||
/**
|
||||
* @var WPML_Media_Post_Media_Usage
|
||||
*/
|
||||
private $post_media_usage;
|
||||
/**
|
||||
* @var WPML_Media_Post_With_Media_Files_Factory
|
||||
*/
|
||||
private $post_with_media_files_factory;
|
||||
|
||||
public function __construct(
|
||||
wpdb $wpdb,
|
||||
WPML_Notices $wpml_notices,
|
||||
WPML_Media_Post_Media_Usage $post_media_usage,
|
||||
WPML_Media_Post_With_Media_Files_Factory $post_with_media_files_factory
|
||||
) {
|
||||
$this->wpdb = $wpdb;
|
||||
$this->wpml_notices = $wpml_notices;
|
||||
$this->post_media_usage = $post_media_usage;
|
||||
$this->post_with_media_files_factory = $post_with_media_files_factory;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wp_ajax_' . WPML_Media_Posts_Media_Flag_Notice::PREPARE_ACTION, array( $this, 'clear_flags' ) );
|
||||
add_action( 'wp_ajax_' . WPML_Media_Posts_Media_Flag_Notice::PROCESS_ACTION, array( $this, 'process_batch' ) );
|
||||
|
||||
add_action( 'save_post', array( $this, 'update_post_flag' ) );
|
||||
}
|
||||
|
||||
public function clear_flags() {
|
||||
if ( $this->verify_nonce( WPML_Media_Posts_Media_Flag_Notice::PREPARE_ACTION ) ) {
|
||||
|
||||
if ( ! WPML_Media::has_setup_started() ) {
|
||||
$this->wpdb->delete( $this->wpdb->postmeta, array( 'meta_key' => self::HAS_MEDIA_POST_FLAG ), array( '%s' ) );
|
||||
}
|
||||
wp_send_json_success( array( 'status' => __( 'Running setup...', 'wpml-media' ) ) );
|
||||
|
||||
} else {
|
||||
wp_send_json_error( array( 'status' => 'Invalid nonce' ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function process_batch() {
|
||||
if ( $this->verify_nonce( WPML_Media_Posts_Media_Flag_Notice::PROCESS_ACTION ) ) {
|
||||
$this->mark_started();
|
||||
|
||||
$continue = false;
|
||||
$status = __( 'Setup complete!', 'wpml-media' );
|
||||
$offset = isset( $_POST['offset'] ) ? (int) $_POST['offset'] : 0;
|
||||
|
||||
if ( ! WPML_Media::has_setup_run() ) {
|
||||
|
||||
$sql = $this->wpdb->prepare( "
|
||||
SELECT SQL_CALC_FOUND_ROWS ID, post_content FROM {$this->wpdb->posts} p
|
||||
JOIN {$this->wpdb->prefix}icl_translations t
|
||||
ON t.element_id = p.ID AND t.element_type LIKE 'post_%'
|
||||
LEFT JOIN {$this->wpdb->prefix}postmeta m ON p.ID = m.post_id AND m.meta_key='%s'
|
||||
WHERE p.post_type NOT IN ( 'auto-draft', 'attachment', 'revision' )
|
||||
AND t.source_language_code IS NULL AND m.meta_id IS NULL
|
||||
ORDER BY ID ASC
|
||||
LIMIT %d, %d
|
||||
", self::HAS_MEDIA_POST_FLAG, $offset, self::BATCH_SIZE );
|
||||
|
||||
$posts = $this->wpdb->get_results( $sql );
|
||||
|
||||
$total_posts_found = $this->wpdb->get_var( 'SELECT FOUND_ROWS()' );
|
||||
|
||||
if ( $continue = ( count( $posts ) > 0 ) ) {
|
||||
$this->flag_posts( $posts );
|
||||
$this->record_media_usage( $posts );
|
||||
$progress = round( 100*min( $offset, $total_posts_found )/$total_posts_found );
|
||||
$status = sprintf( __( 'Setup in progress: %d%% complete...', 'wpml-media' ), $progress );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $continue ) {
|
||||
$this->mark_complete();
|
||||
}
|
||||
|
||||
wp_send_json_success( array(
|
||||
'status' => $status,
|
||||
'offset' => $offset + self::BATCH_SIZE,
|
||||
'continue' => $continue
|
||||
) );
|
||||
|
||||
} else {
|
||||
wp_send_json_error( array( 'status' => 'Invalid nonce' ) );
|
||||
}
|
||||
}
|
||||
|
||||
private function verify_nonce( $action ) {
|
||||
return isset( $_POST['nonce'] ) && wp_verify_nonce( $_POST['nonce'], $action );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $posts
|
||||
*/
|
||||
private function flag_posts( $posts ) {
|
||||
foreach ( $posts as $post ) {
|
||||
$this->update_post_flag( $post->ID );
|
||||
}
|
||||
}
|
||||
|
||||
public function update_post_flag( $post_id ) {
|
||||
|
||||
$post_with_media_files = $this->post_with_media_files_factory->create( $post_id );
|
||||
|
||||
if ( $post_with_media_files->get_media_ids() ) {
|
||||
update_post_meta( $post_id, self::HAS_MEDIA_POST_FLAG, 1 );
|
||||
} else {
|
||||
delete_post_meta( $post_id, self::HAS_MEDIA_POST_FLAG );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $posts
|
||||
*/
|
||||
private function record_media_usage( $posts ) {
|
||||
foreach ( $posts as $post ) {
|
||||
$this->post_media_usage->update_media_usage( $post->ID );
|
||||
}
|
||||
}
|
||||
|
||||
private function mark_complete() {
|
||||
WPML_Media::set_setup_run();
|
||||
$this->wpml_notices->remove_notice(
|
||||
WPML_Media_Posts_Media_Flag_Notice::NOTICE_GROUP,
|
||||
WPML_Media_Posts_Media_Flag_Notice::NOTICE_ID
|
||||
);
|
||||
}
|
||||
|
||||
private function mark_started() {
|
||||
WPML_Media::set_setup_started();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_Media_Sizes {
|
||||
/**
|
||||
* @param array $img
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_size_from_class( array $img ) {
|
||||
if ( array_key_exists( 'attributes', $img ) && array_key_exists( 'class', $img['attributes'] ) ) {
|
||||
|
||||
$classes = explode( ' ', $img['attributes']['class'] );
|
||||
foreach ( $classes as $class ) {
|
||||
if ( strpos( $class, 'size-' ) === 0 ) {
|
||||
$class_parts = explode( '-', $class );
|
||||
if ( count( $class_parts ) >= 2 ) {
|
||||
unset( $class_parts[0] );
|
||||
|
||||
return implode( '-', $class_parts );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $img
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_size_from_attributes( array $img ) {
|
||||
if (
|
||||
array_key_exists( 'attributes', $img )
|
||||
&& array_key_exists( 'width', $img['attributes'] )
|
||||
&& array_key_exists( 'height', $img['attributes'] )
|
||||
) {
|
||||
|
||||
$width = $img['attributes']['width'];
|
||||
$height = $img['attributes']['height'];
|
||||
|
||||
$size_name = $this->get_image_size_name( $width, $height );
|
||||
|
||||
if ( $size_name ) {
|
||||
return $size_name;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $img
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_attachment_size( array $img ) {
|
||||
$size = null;
|
||||
if ( array_key_exists( 'size', $img ) ) {
|
||||
$size = $img['size'];
|
||||
}
|
||||
if ( ! $size ) {
|
||||
$size = $this->get_size_from_class( $img );
|
||||
}
|
||||
if ( ! $size ) {
|
||||
$size = $this->get_size_from_attributes( $img );
|
||||
}
|
||||
if ( ! $size ) {
|
||||
$size = $this->get_size_from_url( $img );
|
||||
}
|
||||
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $width
|
||||
* @param string $height
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
private function get_image_size_name( $width, $height ) {
|
||||
global $_wp_additional_image_sizes;
|
||||
|
||||
foreach ( get_intermediate_image_sizes() as $size ) {
|
||||
if ( isset( $_wp_additional_image_sizes[ $size ] ) ) {
|
||||
if ( $width == $_wp_additional_image_sizes[ $size ]['width'] && $height == $_wp_additional_image_sizes[ $size ]['height'] ) {
|
||||
return $size;
|
||||
}
|
||||
} elseif ( in_array( $size, array( 'thumbnail', 'medium', 'medium_large', 'large' ) ) ) {
|
||||
if ( $width == get_option( "{$size}_size_w" ) && $height == get_option( "{$size}_size_h" ) ) {
|
||||
return $size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $img
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
private function get_size_from_url( array $img ) {
|
||||
$size = null;
|
||||
|
||||
if ( isset( $img['attributes']['src'], $img['attachment_id'] ) ) {
|
||||
$size = $this->get_image_size_from_url( $img['attributes']['src'], $img['attachment_id'] );
|
||||
}
|
||||
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $url
|
||||
* @param $attachment_id
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_image_size_from_url( $url, $attachment_id ) {
|
||||
$size = null;
|
||||
|
||||
$thumb_file_name = basename( $url );
|
||||
$attachment_meta_data = wp_get_attachment_metadata( $attachment_id );
|
||||
foreach ( $attachment_meta_data['sizes'] as $key => $size_array ) {
|
||||
if ( $thumb_file_name === $size_array['file'] ) {
|
||||
$size = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_String_Images_Translation_Factory
|
||||
*/
|
||||
class WPML_Media_String_Images_Translation_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$media_localization_settings = WPML_Media::get_setting( 'media_files_localization' );
|
||||
|
||||
if ( $media_localization_settings['strings'] ) {
|
||||
$image_translator = new WPML_Media_Image_Translate( $sitepress, new WPML_Media_Attachment_By_URL_Factory() );
|
||||
$image_updater = new WPML_Media_Translated_Images_Update( new WPML_Media_Img_Parse(), $image_translator, new WPML_Media_Sizes() );
|
||||
$string_factory = new WPML_ST_String_Factory( $wpdb );
|
||||
|
||||
return new WPML_Media_String_Images_Translation( $image_updater, $string_factory );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_String_Images_Translation
|
||||
* Translate images in posts strings translations when a string translation is created or updated
|
||||
*/
|
||||
class WPML_Media_String_Images_Translation implements IWPML_Action {
|
||||
|
||||
/**
|
||||
* @var WPML_Media_String_Images_Translation
|
||||
*/
|
||||
private $images_updater;
|
||||
/**
|
||||
* @var WPML_ST_String_Factory
|
||||
*/
|
||||
private $string_factory;
|
||||
|
||||
/**
|
||||
* WPML_Media_String_Images_Translation constructor.
|
||||
*
|
||||
* @param WPML_Media_Translated_Images_Update $images_updater
|
||||
* @param WPML_ST_String_Factory $string_factory
|
||||
*/
|
||||
public function __construct( WPML_Media_Translated_Images_Update $images_updater, WPML_ST_String_Factory $string_factory ) {
|
||||
$this->images_updater = $images_updater;
|
||||
$this->string_factory = $string_factory;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'wpml_st_string_translation_before_save', array( $this, 'translate_images' ), PHP_INT_MAX, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $translation_data
|
||||
* @param string $target_language
|
||||
* @param int $string_id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function translate_images( $translation_data, $target_language, $string_id ) {
|
||||
if ( ! empty( $translation_data['value'] ) ) {
|
||||
$original_string = $this->string_factory->find_by_id( $string_id );
|
||||
|
||||
$translation_data['value'] = $this->images_updater->replace_images_with_translations(
|
||||
$translation_data['value'],
|
||||
$target_language,
|
||||
$original_string->get_language()
|
||||
);
|
||||
}
|
||||
|
||||
return $translation_data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Translated_Images_Update
|
||||
* Translates images in a given text
|
||||
*/
|
||||
class WPML_Media_Translated_Images_Update {
|
||||
|
||||
/**
|
||||
* @var WPML_Media_Img_Parse
|
||||
*/
|
||||
private $img_parser;
|
||||
|
||||
/**
|
||||
* @var WPML_Media_Image_Translate
|
||||
*/
|
||||
private $image_translator;
|
||||
/**
|
||||
* @var WPML_Media_Sizes
|
||||
*/
|
||||
private $media_sizes;
|
||||
|
||||
/**
|
||||
* WPML_Media_Translated_Images_Update constructor.
|
||||
*
|
||||
* @param WPML_Media_Img_Parse $img_parser
|
||||
* @param WPML_Media_Image_Translate $image_translator
|
||||
* @param WPML_Media_Sizes $media_sizes
|
||||
*/
|
||||
public function __construct( WPML_Media_Img_Parse $img_parser, WPML_Media_Image_Translate $image_translator, WPML_Media_Sizes $media_sizes ) {
|
||||
$this->img_parser = $img_parser;
|
||||
$this->image_translator = $image_translator;
|
||||
$this->media_sizes = $media_sizes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param string $source_language
|
||||
* @param string $target_language
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function replace_images_with_translations( $text, $target_language, $source_language = null ) {
|
||||
|
||||
$imgs = $this->img_parser->get_imgs( $text );
|
||||
|
||||
foreach ( $imgs as $img ) {
|
||||
$attachment_id = $translated_id = false;
|
||||
if ( isset( $img['attachment_id'] ) && $img['attachment_id'] ) {
|
||||
$attachment_id = $img['attachment_id'];
|
||||
$translated_id = apply_filters(
|
||||
'wpml_object_id',
|
||||
$attachment_id,
|
||||
'attachment',
|
||||
true,
|
||||
$target_language
|
||||
);
|
||||
$size = $this->media_sizes->get_attachment_size( $img );
|
||||
$translated_src = $this->image_translator->get_translated_image( $attachment_id, $target_language, $size );
|
||||
} else {
|
||||
$translated_src = $this->get_translated_image_by_url( $target_language, $source_language, $img );
|
||||
}
|
||||
if ( $translated_src && $translated_src !== $img['attributes']['src'] ) {
|
||||
$text = $this->replace_image_src( $text, $img['attributes']['src'], $translated_src );
|
||||
}
|
||||
if ( $attachment_id && $attachment_id !== $translated_id ) {
|
||||
$text = $this->replace_att_class( $text, $attachment_id, $translated_id );
|
||||
$text = $this->replace_att_in_block( $text, $attachment_id, $translated_id );
|
||||
}
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function replace_image_src( $text, $from, $to ) {
|
||||
return str_replace( $from, $to, $text );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function replace_att_class( $text, $from, $to ) {
|
||||
$pattern = '/\bwp-image-' . $from . '\b/u';
|
||||
$replacement = 'wp-image-' . $to;
|
||||
return preg_replace( $pattern, $replacement, $text );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function replace_att_in_block( $text, $from, $to ) {
|
||||
$pattern = '/<!-- wp:image {.*?"id":(' . $from . '),.*?-->/u';
|
||||
$replacement = function ( $matches ) use ( $to ) {
|
||||
return str_replace( '"id":' . $matches[1], '"id":' . $to, $matches[0] );
|
||||
};
|
||||
|
||||
return preg_replace_callback( $pattern, $replacement, $text );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $target_language
|
||||
* @param $source_language
|
||||
* @param $img
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
private function get_translated_image_by_url( $target_language, $source_language, $img ) {
|
||||
if ( null === $source_language ) {
|
||||
$source_language = wpml_get_current_language();
|
||||
}
|
||||
$translated_src = $this->image_translator->get_translated_image_by_url(
|
||||
$img['attributes']['src'],
|
||||
$source_language,
|
||||
$target_language
|
||||
);
|
||||
|
||||
return $translated_src;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Translation_Status_Factory implements IWPML_Backend_Action_Loader, IWPML_REST_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $sitepress;
|
||||
|
||||
return new WPML_Media_Translation_Status( $sitepress );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Translation_Status implements IWPML_Action {
|
||||
|
||||
const NOT_TRANSLATED = 'media-not-translated';
|
||||
const IN_PROGRESS = 'in-progress';
|
||||
const TRANSLATED = 'media-translated';
|
||||
const NEEDS_MEDIA_TRANSLATION = 'needs-media-translation';
|
||||
|
||||
const STATUS_PREFIX = '_translation_status_';
|
||||
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
|
||||
public function __construct( SitePress $sitepress ) {
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wpml_tm_send_post_jobs', array( $this, 'set_translation_status_in_progress' ) );
|
||||
add_action( 'wpml_pro_translation_completed', array( $this, 'save_bundled_media_translation' ), 10, 3 );
|
||||
}
|
||||
|
||||
public function set_translation_status_in_progress( WPML_TM_Translation_Batch $batch ) {
|
||||
foreach ( $batch->get_elements() as $item ) {
|
||||
foreach ( $item->get_media_to_translations() as $attachment_id ) {
|
||||
foreach ( array_keys( $item->get_target_langs() ) as $lang ) {
|
||||
$this->set_status( $attachment_id, $lang, self::IN_PROGRESS );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function set_status( $attachment_id, $language, $status ) {
|
||||
update_post_meta( $attachment_id, self::STATUS_PREFIX . $language, $status );
|
||||
}
|
||||
|
||||
public function save_bundled_media_translation( $new_post_id, $fields, $job ) {
|
||||
|
||||
$media_translations = $this->get_media_translations( $job );
|
||||
$translation_package = new WPML_Element_Translation_Package();
|
||||
|
||||
foreach ( $media_translations as $attachment_id => $translation_data ) {
|
||||
$attachment_translation_id = $this->save_attachment_translation(
|
||||
$attachment_id,
|
||||
$translation_data,
|
||||
$translation_package,
|
||||
$job->language_code
|
||||
);
|
||||
if ( $this->should_translate_media_image( $job, $attachment_id ) ) {
|
||||
$this->set_status( $attachment_id, $job->language_code, self::NEEDS_MEDIA_TRANSLATION );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function should_translate_media_image( $job, $attachment_id ) {
|
||||
foreach ( $job->elements as $element ) {
|
||||
if ( 'should_translate_media_image_' . $attachment_id === $element->field_type && $element->field_data ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function get_media_translations( $job ) {
|
||||
|
||||
$media = array();
|
||||
|
||||
$media_field_regexp = '#^media_([0-9]+)_([a-z_]+)$#';
|
||||
foreach ( $job->elements as $element ) {
|
||||
if ( preg_match( $media_field_regexp, $element->field_type, $matches ) ) {
|
||||
list( , $attachment_id, $media_field ) = $matches;
|
||||
$media[ $attachment_id ][ $media_field ] = $element;
|
||||
}
|
||||
}
|
||||
|
||||
return $media;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $attachment_id
|
||||
* @param array $translation_data
|
||||
* @param WPML_Element_Translation_Package $translation_package
|
||||
* @param string $language
|
||||
* @return bool|int|WP_Error
|
||||
*/
|
||||
private function save_attachment_translation( $attachment_id, $translation_data, $translation_package, $language ) {
|
||||
|
||||
$postarr = array();
|
||||
$alt_text = null;
|
||||
|
||||
foreach ( $translation_data as $field => $data ) {
|
||||
|
||||
$translated_value = $translation_package->decode_field_data(
|
||||
$data->field_data_translated,
|
||||
$data->field_format
|
||||
);
|
||||
|
||||
if ( 'alt_text' === $field ) {
|
||||
$alt_text = $translated_value;
|
||||
} else {
|
||||
|
||||
switch ( $field ) {
|
||||
case 'title':
|
||||
$wp_post_field = 'post_title';
|
||||
break;
|
||||
case 'caption':
|
||||
$wp_post_field = 'post_excerpt';
|
||||
break;
|
||||
case 'description':
|
||||
$wp_post_field = 'post_content';
|
||||
break;
|
||||
default:
|
||||
$wp_post_field = '';
|
||||
|
||||
}
|
||||
|
||||
if ( $wp_post_field ) {
|
||||
$postarr[ $wp_post_field ] = $translated_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$post_element = new WPML_Post_Element( $attachment_id, $this->sitepress );
|
||||
$attachment_translation = $post_element->get_translation( $language );
|
||||
$attachment_translation_id = null !== $attachment_translation ? $attachment_translation->get_id() : false;
|
||||
|
||||
if ( $attachment_translation_id ) {
|
||||
$postarr['ID'] = $attachment_translation_id;
|
||||
wp_update_post( $postarr );
|
||||
} else {
|
||||
$postarr['post_type'] = 'attachment';
|
||||
$postarr['post_status'] = 'inherit';
|
||||
$postarr['guid'] = get_post_field( 'guid', $attachment_id );
|
||||
$postarr['post_mime_type'] = get_post_field( 'post_mime_type', $attachment_id );
|
||||
|
||||
$attachment_translation_id = wp_insert_post( $postarr );
|
||||
|
||||
$this->sitepress->set_element_language_details( $attachment_translation_id, 'post_attachment', $post_element->get_trid(), $language );
|
||||
|
||||
$this->copy_attached_file_info_from_original( $attachment_translation_id, $attachment_id );
|
||||
|
||||
}
|
||||
|
||||
if ( null !== $alt_text ) {
|
||||
update_post_meta( $attachment_translation_id, '_wp_attachment_image_alt', $alt_text );
|
||||
}
|
||||
|
||||
return $attachment_translation_id;
|
||||
}
|
||||
|
||||
private function copy_attached_file_info_from_original( $attachment_id, $original_attachment_id ) {
|
||||
$meta_keys = array(
|
||||
'_wp_attachment_metadata',
|
||||
'_wp_attached_file',
|
||||
'_wp_attachment_backup_sizes',
|
||||
);
|
||||
foreach ( $meta_keys as $meta_key ) {
|
||||
update_post_meta(
|
||||
$attachment_id,
|
||||
$meta_key,
|
||||
get_post_meta( $original_attachment_id, $meta_key, true )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Populate_Media_Strings_Translations_Factory implements IWPML_Backend_Action_Loader {
|
||||
public function create() {
|
||||
global $sitepress;
|
||||
|
||||
if ( class_exists( 'WPML_Element_Translation_Package' ) ) {
|
||||
return new WPML_Media_Populate_Media_Strings_Translations(
|
||||
new WPML_Translation_Element_Factory( $sitepress ),
|
||||
new WPML_Element_Translation_Package()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Populate_Media_Strings_Translations implements IWPML_Action {
|
||||
|
||||
/**
|
||||
* @var WPML_Translation_Element_Factory
|
||||
*/
|
||||
private $translation_element_factory;
|
||||
|
||||
/**
|
||||
* @var WPML_Element_Translation_Package
|
||||
*/
|
||||
private $translation_package;
|
||||
|
||||
public function __construct(
|
||||
WPML_Translation_Element_Factory $translation_element_factory,
|
||||
WPML_Element_Translation_Package $translation_package
|
||||
) {
|
||||
$this->translation_element_factory = $translation_element_factory;
|
||||
$this->translation_package = $translation_package;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'wpml_tm_populate_prev_translation', array( $this, 'populate' ), 10, 3 );
|
||||
}
|
||||
|
||||
public function populate( $prev_translation, $package, $lang ) {
|
||||
|
||||
if ( ! $prev_translation ) {
|
||||
foreach ( $package['contents'] as $field => $data ) {
|
||||
if ( $media_field = $this->is_media_field( $field ) ) {
|
||||
|
||||
$attachment = $this->translation_element_factory->create( $media_field['id'], 'post' );
|
||||
$attachment_translation = $attachment->get_translation( $lang );
|
||||
|
||||
if ( $attachment_translation ) {
|
||||
$original_id = (int) $media_field['id'];
|
||||
$translation_id = $attachment_translation->get_id();
|
||||
|
||||
switch ( $media_field['field'] ) {
|
||||
case 'title':
|
||||
$translated_value = $this->get_post_field( 'post_title', $original_id, $translation_id );
|
||||
break;
|
||||
case 'caption':
|
||||
$translated_value = $this->get_post_field( 'post_excerpt', $original_id, $translation_id );
|
||||
break;
|
||||
case 'description':
|
||||
$translated_value = $this->get_post_field( 'post_content', $original_id, $translation_id );
|
||||
break;
|
||||
case 'alt_text':
|
||||
$translated_value = get_post_meta( $translation_id, '_wp_attachment_image_alt', true );
|
||||
if ( ! $translated_value ) {
|
||||
$translated_value = get_post_meta( $original_id, '_wp_attachment_image_alt', true );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$translated_value = false;
|
||||
|
||||
}
|
||||
|
||||
if ( $translated_value ) {
|
||||
$prev_translation[ $field ] = wpml_tm_create_translated_field(
|
||||
'', $this->translation_package->encode_field_data( $translated_value ), true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return $prev_translation;
|
||||
}
|
||||
|
||||
private function is_media_field( $field ) {
|
||||
$media_field = array();
|
||||
|
||||
if ( preg_match( '#^media_([0-9]+)_([a-z_]+)$#', $field, $matches ) ) {
|
||||
$media_field['id'] = $matches[1];
|
||||
$media_field['field'] = $matches[2];
|
||||
}
|
||||
|
||||
return $media_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @param int $original_id
|
||||
* @param int $translation_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_post_field( $field, $original_id, $translation_id ) {
|
||||
$value = get_post_field( $field, $translation_id );
|
||||
|
||||
if ( ! $value ) {
|
||||
$value = get_post_field( $field, $original_id );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Post_Media_Usage_Factory implements IWPML_Backend_Action_Loader, IWPML_Frontend_Action_Loader {
|
||||
|
||||
public function create(){
|
||||
global $sitepress;
|
||||
return new WPML_Media_Post_Media_Usage(
|
||||
$sitepress,
|
||||
new WPML_Media_Post_With_Media_Files_Factory(),
|
||||
new WPML_Media_Usage_Factory()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Post_Media_Usage implements IWPML_Action {
|
||||
|
||||
/** @see WPML_Post_Translation::save_post_actions() */
|
||||
const PRIORITY_AFTER_CORE_SAVE_POST_ACTIONS = 200;
|
||||
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
/**
|
||||
* @var WPML_Media_Post_With_Media_Files_Factory
|
||||
*/
|
||||
private $post_with_media_files_factory;
|
||||
/**
|
||||
* @var WPML_Media_Usage_Factory
|
||||
*/
|
||||
private $media_usage_factory;
|
||||
|
||||
|
||||
public function __construct(
|
||||
SitePress $sitepress,
|
||||
WPML_Media_Post_With_Media_Files_Factory $post_with_media_files_factory,
|
||||
WPML_Media_Usage_Factory $media_usage_factory
|
||||
) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->post_with_media_files_factory = $post_with_media_files_factory;
|
||||
$this->media_usage_factory = $media_usage_factory;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'save_post', array( $this, 'update_media_usage' ), self::PRIORITY_AFTER_CORE_SAVE_POST_ACTIONS, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param WP_Post|null $post
|
||||
*/
|
||||
public function update_media_usage( $post_id, $post = null ) {
|
||||
|
||||
if ( null === $post ) {
|
||||
$post = get_post( $post_id );
|
||||
}
|
||||
|
||||
if ( $this->sitepress->get_wp_api()->constant( 'DOING_AUTOSAVE' )
|
||||
|| ! $this->sitepress->is_translated_post_type( $post->post_type )
|
||||
|| $post_id !== (int) $this->sitepress->get_original_element_id( $post_id, 'post_' . $post->post_type )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$media_ids = $this->post_with_media_files_factory->create( $post_id )->get_media_ids();
|
||||
foreach ( $media_ids as $media_id ) {
|
||||
$this->media_usage_factory->create( $media_id )->add_post( $post->ID );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Usage_Factory {
|
||||
|
||||
public function create( $attachment_id ) {
|
||||
return new WPML_Media_Usage( $attachment_id );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Usage {
|
||||
|
||||
const FIELD_NAME = '_wpml_media_usage';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $attachment_id;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $usage;
|
||||
|
||||
/**
|
||||
* @param int $attachment_id
|
||||
*/
|
||||
public function __construct( $attachment_id ) {
|
||||
$this->attachment_id = $attachment_id;
|
||||
|
||||
$usage = get_post_meta( $this->attachment_id, self::FIELD_NAME, true );
|
||||
$this->usage = empty( $usage ) ? array() : $usage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_posts() {
|
||||
return empty( $this->usage['posts'] ) ? array() : $this->usage['posts'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*/
|
||||
public function add_post( $post_id ) {
|
||||
$posts = $this->get_posts();
|
||||
$posts[] = $post_id;
|
||||
$this->usage['posts'] = array_unique( $posts );
|
||||
$this->update_usage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*/
|
||||
public function remove_post( $post_id ) {
|
||||
$this->usage['posts'] = array_values( array_diff( (array) $this->usage['posts'], array( $post_id ) ) );
|
||||
$this->update_usage();
|
||||
}
|
||||
|
||||
private function update_usage() {
|
||||
update_post_meta( $this->attachment_id, self::FIELD_NAME, $this->usage );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Help_Tab_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
return new WPML_Media_Help_Tab();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Help_Tab implements IWPML_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
|
||||
add_action( 'admin_head', array( $this, 'add' ) );
|
||||
}
|
||||
|
||||
public function add() {
|
||||
$current_screen = get_current_screen();
|
||||
|
||||
if ( $this->is_media_related_screen( $current_screen ) ) {
|
||||
$media_translation_dashboard = esc_html__( 'WPML » Media Translation', 'wpml-media' );
|
||||
$wpml_translation_dashboard = esc_html__( 'WPML » Translation Management', 'wpml-media' );
|
||||
$current_screen->add_help_tab(
|
||||
array(
|
||||
'id' => 'wpml-media-translation',
|
||||
'title' => esc_html__( 'Translating Media', 'wpml-media' ),
|
||||
'content' =>
|
||||
'<p>' . esc_html__( 'There are two ways for you to translate Media:', 'wpml-media' ) . '</p>' .
|
||||
'<ul>' .
|
||||
'<li>' . sprintf(
|
||||
esc_html__( 'Use the dashboard on the %s page to translate your images and other media files.', 'wpml-media' ),
|
||||
$media_translation_dashboard
|
||||
) . '</li>' .
|
||||
'<li>' . sprintf(
|
||||
esc_html__( 'Use the dashboard on the %s page to send pages that contain media, for translation.', 'wpml-media' ),
|
||||
$wpml_translation_dashboard
|
||||
) . '</li>' .
|
||||
'</ul>' .
|
||||
'</ul>' .
|
||||
'<a href="https://wpml.org/?page_id=113610">' . esc_html__( 'Learn more about WPML Media Translation', 'wpml-media' ) . '</a>',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function is_media_related_screen( $current_screen ) {
|
||||
$accepted_bases = array(
|
||||
'wpml_page_wpml-media',
|
||||
'upload',
|
||||
'media',
|
||||
'wpml_page_wpml-translation-management/menu/main',
|
||||
);
|
||||
|
||||
return $current_screen && in_array( $current_screen->base, $accepted_bases );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Menus_Factory
|
||||
*/
|
||||
class WPML_Media_Menus_Factory {
|
||||
|
||||
public function create() {
|
||||
global $sitepress, $wpdb;
|
||||
|
||||
$wpml_wp_api = $sitepress->get_wp_api();
|
||||
$wpml_media_path = $wpml_wp_api->constant( 'WPML_MEDIA_PATH' );
|
||||
|
||||
$template_service_loader = new WPML_Twig_Template_Loader( array( $wpml_media_path . '/templates/menus/' ) );
|
||||
$pagination = new WPML_Admin_Pagination();
|
||||
|
||||
return new WPML_Media_Menus( $template_service_loader, $sitepress, $wpdb, $pagination );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Menus {
|
||||
|
||||
/**
|
||||
* @var IWPML_Template_Service
|
||||
*/
|
||||
private $template_service;
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
/**
|
||||
* @var WPML_Admin_Pagination
|
||||
*/
|
||||
private $pagination;
|
||||
|
||||
/**
|
||||
* WPML_Media_Menus constructor.
|
||||
*
|
||||
* @param WPML_Twig_Template_Loader $template_service
|
||||
* @param SitePress $sitepress
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( WPML_Twig_Template_Loader $template_service, SitePress $sitepress, wpdb $wpdb, WPML_Admin_Pagination $pagination = null ) {
|
||||
$this->template_service = $template_service;
|
||||
$this->sitepress = $sitepress;
|
||||
$this->wpdb = $wpdb;
|
||||
$this->pagination = $pagination;
|
||||
|
||||
}
|
||||
|
||||
public function display() {
|
||||
global $wp_locale, $wpml_query_filter;
|
||||
|
||||
do_action( 'wpml_media_messages' );
|
||||
do_action( 'wpml_media_menu' );
|
||||
|
||||
$menu_overrides = apply_filters( 'wpml_media_menu_overrides', array() );
|
||||
if ( $menu_overrides ) {
|
||||
foreach ( $menu_overrides as $menu_override ) {
|
||||
call_user_func( $menu_override );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$wpml_media_url = $this->sitepress->get_wp_api()->constant( 'WPML_MEDIA_URL' );
|
||||
$wpml_media_version = $this->sitepress->get_wp_api()->constant( 'WPML_MEDIA_VERSION' );
|
||||
|
||||
wp_enqueue_style( OTGS_Assets_Handles::POPOVER_TOOLTIP );
|
||||
wp_enqueue_script( OTGS_Assets_Handles::POPOVER_TOOLTIP );
|
||||
wp_enqueue_style( 'wpml-media', $wpml_media_url . '/res/css/media-translation.css', array(), $wpml_media_version );
|
||||
wp_enqueue_script(
|
||||
'wpml-media',
|
||||
$wpml_media_url . '/res/js/media-translation-popup.js',
|
||||
array(
|
||||
'jquery',
|
||||
'jquery-ui-dialog',
|
||||
),
|
||||
$wpml_media_version,
|
||||
true
|
||||
);
|
||||
$wpml_media_popup_strings = array(
|
||||
'title' => esc_js( __( 'Media Translation', 'wpml-media' ) ),
|
||||
'cancel' => esc_js( __( 'Cancel', 'wpml-media' ) ),
|
||||
'save' => esc_js( __( 'Save media translation', 'wpml-media' ) ),
|
||||
'status_labels' => WPML_Media_Translations_UI::get_translation_status_labels(),
|
||||
);
|
||||
wp_localize_script( 'wpml-media', 'wpml_media_popup', $wpml_media_popup_strings );
|
||||
wp_enqueue_script( 'wpml-media-batch-url-translation', $wpml_media_url . '/res/js/batch-url-translation.js', array( 'jquery' ), $wpml_media_version, true );
|
||||
$batch_translation_vars = array(
|
||||
'complete' => esc_js( __( 'Scan complete!', 'wpml-media' ) ),
|
||||
'is_st_enabled' => (bool) $this->sitepress->get_wp_api()->constant( 'WPML_ST_VERSION' ),
|
||||
);
|
||||
wp_localize_script( 'wpml-media-batch-url-translation', 'wpml_media_batch_translation', $batch_translation_vars );
|
||||
|
||||
wp_enqueue_script( OTGS_Assets_Handles::TABLE_STICKY_HEADER );
|
||||
|
||||
$media_translations_ui = new WPML_Media_Translations_UI(
|
||||
$this->sitepress,
|
||||
$this->wpdb,
|
||||
$wp_locale,
|
||||
$wpml_query_filter,
|
||||
$this->pagination
|
||||
);
|
||||
|
||||
$media_translations_ui->show();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Posts_Media_Flag_Notice_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $sitepress;
|
||||
|
||||
if ( current_user_can( 'manage_options' ) && ! WPML_Media::has_setup_run() && $sitepress->is_setup_complete() ) {
|
||||
return new WPML_Media_Posts_Media_Flag_Notice( $sitepress );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Posts_Media_Flag_Notice implements IWPML_Action {
|
||||
|
||||
const PREPARE_ACTION = 'wpml-media-has-media-flag-prepare';
|
||||
const PROCESS_ACTION = 'wpml-media-has-media-flag';
|
||||
|
||||
const NOTICE_ID = 'wpml-media-posts-media-flag';
|
||||
const NOTICE_GROUP = 'wpml-media';
|
||||
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* WPML_Media_Has_Media_Notice constructor.
|
||||
*
|
||||
* @param SitePress $sitepress
|
||||
*/
|
||||
public function __construct( SitePress $sitepress ) {
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
|
||||
if ( $this->is_wpml_media_screen() ) {
|
||||
add_filter( 'wpml_media_menu_overrides', array( $this, 'override_default_menu' ) );
|
||||
} else {
|
||||
add_action( 'admin_head', array( $this, 'add_top_notice' ) );
|
||||
}
|
||||
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_js' ) );
|
||||
}
|
||||
|
||||
public function override_default_menu( $menu_elements ) {
|
||||
$menu_elements[] = array( $this, 'render_menu' );
|
||||
|
||||
return $menu_elements;
|
||||
}
|
||||
|
||||
public function enqueue_js() {
|
||||
$wpml_media_url = $this->sitepress->get_wp_api()->constant( 'WPML_MEDIA_URL' );
|
||||
wp_enqueue_script( 'wpml-media-setup', $wpml_media_url . '/res/js/wpml-media-posts-media-flag.js', array( 'jquery' ), false, true );
|
||||
}
|
||||
|
||||
private function is_wpml_media_screen() {
|
||||
return isset( $_GET['page'] ) && 'wpml-media' === $_GET['page'];
|
||||
}
|
||||
|
||||
public function add_top_notice() {
|
||||
|
||||
/* translators: name ot WPML-Media plugin */
|
||||
$wpml_media = '<strong>' . __( 'WPML Media Translation', 'wpml-media' ) . '</strong>';
|
||||
|
||||
/* translators: used to build a link in the "Click here to finish the setup" */
|
||||
$here_text = _x( 'here', 'Used to build a link in the "Click here to finish the setup"', 'wpml-media' );
|
||||
$here_link = '<a href="' . admin_url( 'admin.php?page=wpml-media' ) . '">' . $here_text . '</a>';
|
||||
|
||||
/* translators: %1$s will be replaced with a translation of "WPML Media Translation", while %2$s is a link with the translation of the word "here" */
|
||||
$text = vsprintf(
|
||||
esc_html__( 'The %1$s setup is almost complete. Click %2$s to finish the setup.', 'wpml-media' ),
|
||||
array(
|
||||
$wpml_media,
|
||||
$here_link
|
||||
)
|
||||
);
|
||||
|
||||
$notice = new WPML_Notice( self::NOTICE_ID, $text, self::NOTICE_GROUP );
|
||||
$notice->set_css_class_types( 'notice-warning' );
|
||||
$notice->set_hideable( false );
|
||||
$notice->set_dismissible( false );
|
||||
$notice->set_collapsable( false );
|
||||
$notice->add_exclude_from_page( 'wpml-media' );
|
||||
$notice->add_capability_check( array( 'manage_options' ) );
|
||||
$wpml_admin_notices = wpml_get_admin_notices();
|
||||
$wpml_admin_notices->add_notice( $notice );
|
||||
|
||||
}
|
||||
|
||||
public function render_menu() {
|
||||
?>
|
||||
<div class="wrap wpml-media-setup">
|
||||
<h2><?php esc_html_e( 'Setup required', 'wpml-media' ) ?></h2>
|
||||
<div
|
||||
id="wpml-media-posts-media-flag"
|
||||
class="notice notice-warning"
|
||||
style="padding-bottom:8px"
|
||||
|
||||
data-prepare-action="<?php echo esc_attr( self::PREPARE_ACTION ); ?>"
|
||||
data-prepare-nonce="<?php echo wp_create_nonce( self::PREPARE_ACTION ); ?>"
|
||||
|
||||
data-process-action="<?php echo esc_attr( self::PROCESS_ACTION ); ?>"
|
||||
data-process-nonce="<?php echo wp_create_nonce( self::PROCESS_ACTION ); ?>"
|
||||
|
||||
>
|
||||
<p>
|
||||
<?php esc_html_e( 'In order to get WPML Media Translation fully working, you need to run this set up which takes only a few moments depending on the total number of posts in your WordPress install.', 'wpml-media' ); ?>
|
||||
</p>
|
||||
<input type="button" class="button-primary alignright"
|
||||
value="<?php esc_attr_e( 'Finish setup', 'wpml-media' ) ?>"/>
|
||||
|
||||
<span class="spinner"> </span>
|
||||
<p class="alignleft status description"></p>
|
||||
<br clear="all"/>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Screen_Options_Factory
|
||||
*/
|
||||
class WPML_Media_Screen_Options_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
/**
|
||||
* @return IWPML_Action|WPML_Media_Screen_Options
|
||||
*/
|
||||
public function create() {
|
||||
|
||||
$options = array();
|
||||
|
||||
if ( $this->is_translation_dashboard() ) {
|
||||
|
||||
$option_name = 'wpml_media_translation_dashboard_items_per_page';
|
||||
$options[] = array(
|
||||
'key' => 'per_page',
|
||||
'args' => array(
|
||||
'label' => __( 'Number of items per page:', 'wpml-media' ),
|
||||
'default' => get_option( $option_name, 20 ),
|
||||
'option' => $option_name,
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ( $options ) {
|
||||
return new WPML_Media_Screen_Options( $options );
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is_translation_dashboard() {
|
||||
return ! isset( $_GET['sm'] ) || 'media-translation' === $_GET['sm'];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Screen_Options implements IWPML_Action {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $options = array();
|
||||
|
||||
/**
|
||||
* WPML_Media_Screen_Options constructor.
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct( $options ) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'load-wpml_page_wpml-media', array( $this, 'add_options' ) );
|
||||
add_filter( 'set-screen-option', array( $this, 'set_screen_option' ), 10, 3 );
|
||||
}
|
||||
|
||||
public function add_options() {
|
||||
foreach ( $this->options as $option ) {
|
||||
add_screen_option( $option['key'], $option['args'] );
|
||||
}
|
||||
}
|
||||
|
||||
public function set_screen_option( $status, $option_name, $value ) {
|
||||
if ( $this->is_valid_option( $option_name ) ) {
|
||||
update_option( $option_name, $value );
|
||||
}
|
||||
}
|
||||
|
||||
private function is_valid_option( $option_name ) {
|
||||
$valid = false;
|
||||
foreach ( $this->options as $option ) {
|
||||
if ( $option_name === $option['args']['option'] ) {
|
||||
$valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Editor_Notices_Factory
|
||||
*/
|
||||
class WPML_Media_Editor_Notices_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
return new WPML_Media_Editor_Notices();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Editor_Notices
|
||||
*/
|
||||
class WPML_Media_Editor_Notices implements IWPML_Action {
|
||||
const TEXT_EDIT_NOTICE_DISMISSED = '_wpml_media_editor_text_edit_notice_dismissed';
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wp_ajax_wpml_media_editor_text_edit_notice_dismissed', array( $this, 'dismiss_texts_change_notice' ) );
|
||||
}
|
||||
|
||||
public function dismiss_texts_change_notice() {
|
||||
update_user_meta( get_current_user_id(), self::TEXT_EDIT_NOTICE_DISMISSED, 1 );
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,550 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Media_Translations_UI
|
||||
*/
|
||||
class WPML_Media_Translations_UI extends WPML_Templates_Factory {
|
||||
const PREVIEW_MAX_WIDTH = 800;
|
||||
const PREVIEW_MAX_HEIGHT = 600;
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
/**
|
||||
* @var WP_Locale
|
||||
*/
|
||||
private $wp_locale;
|
||||
/**
|
||||
* @var WPML_Query_Filter
|
||||
*/
|
||||
private $wpml_query_filter;
|
||||
/**
|
||||
* @var WPML_Admin_Pagination
|
||||
*/
|
||||
private $pagination;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $query_args = array();
|
||||
|
||||
/**
|
||||
* WPML_Media_Translations_UI constructor.
|
||||
*
|
||||
* @param SitePress $sitepress
|
||||
* @param wpdb $wpdb
|
||||
* @param WP_Locale $wp_locale
|
||||
* @param WPML_Query_Filter $wpml_query_filter
|
||||
* @param WPML_Admin_Pagination $pagination
|
||||
*/
|
||||
public function __construct(
|
||||
SitePress $sitepress,
|
||||
wpdb $wpdb,
|
||||
WP_Locale $wp_locale,
|
||||
WPML_Query_Filter $wpml_query_filter,
|
||||
WPML_Admin_Pagination $pagination
|
||||
) {
|
||||
parent::__construct();
|
||||
$this->sitepress = $sitepress;
|
||||
$this->wpdb = $wpdb;
|
||||
$this->wp_locale = $wp_locale;
|
||||
$this->wpml_query_filter = $wpml_query_filter;
|
||||
$this->pagination = $pagination;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_model() {
|
||||
|
||||
$this->set_query_args();
|
||||
|
||||
$languages = $this->get_languages();
|
||||
|
||||
$model = array(
|
||||
'strings' => array(
|
||||
'heading' => __( 'Media Translation', 'wpml-media' ),
|
||||
'filter_by_date' => __( 'Filter by date', 'wpml-media' ),
|
||||
'all_dates' => __( 'All dates', 'wpml-media' ),
|
||||
'in' => __( 'in', 'wpml_media' ),
|
||||
'to' => __( 'to', 'wpml_media' ),
|
||||
'filter_by_status' => __( 'Filter by translation status', 'wpml-media' ),
|
||||
'status_all' => __( 'All translation statuses', 'wpml-media' ),
|
||||
'status_not' => __( 'Media file not translated', 'wpml-media' ),
|
||||
'status_translated' => __( 'Translated media uploaded', 'wpml-media' ),
|
||||
'status_in_progress' => __( 'Translation in progress', 'wpml-media' ),
|
||||
'status_needs_translation' => __( 'Needs media file translation', 'wpml-media' ),
|
||||
'filter_by_language' => __( 'Filter by language', 'wpml-media' ),
|
||||
'any_language' => __( 'Any language', 'wpml-media' ),
|
||||
'search_media' => __( 'Search Media:', 'wpml-media' ),
|
||||
'search_placeholder' => __( 'Title, caption or description', 'wpml-media' ),
|
||||
'search_button_label' => __( 'Filter', 'wpml-media' ),
|
||||
'original_language' => __( 'Original language', 'wpml-media' ),
|
||||
'no_attachments' => __( 'No attachments found', 'wpml-media' ),
|
||||
'add_translation' => __( 'Add media file translation', 'wpml-media' ),
|
||||
'edit_translation' => __( 'Edit %s translation', 'wpml-media' ),
|
||||
'original' => __( 'Original:', 'wpml-media' ),
|
||||
'translation' => __( 'Translation:', 'wpml-media' ),
|
||||
'file' => __( 'File', 'wpml-media' ),
|
||||
'name' => __( 'Name', 'wpml-media' ),
|
||||
'caption' => __( 'Caption', 'wpml-media' ),
|
||||
'alt_text' => __( 'Alt text', 'wpml-media' ),
|
||||
'description' => __( 'Description', 'wpml-media' ),
|
||||
'copy_from_original' => __( 'Copy from original', 'wpml-media' ),
|
||||
'upload_translated_media' => __( 'Upload translated media file', 'wpml-media' ),
|
||||
'use_different_file' => __( 'Use a different file', 'wpml-media' ),
|
||||
'revert_to_original' => __( 'Revert to original', 'wpml-media' ),
|
||||
'restore_original_media' => __( 'Restore original media file', 'wpml-media' ),
|
||||
'statuses' => self::get_translation_status_labels(),
|
||||
'texts_change_notice' => __( 'Any changes you make to the text here will not affect any previous publications of this media on your website. This edited version will only appear if you select it from the library to be embedded.', 'wpml-media' ),
|
||||
),
|
||||
'months' => $this->get_months(),
|
||||
'selected_month' => isset( $this->query_args['m'] ) ? (int) $this->query_args['m'] : 0,
|
||||
'selected_status' => isset( $this->query_args['status'] ) ? $this->query_args['status'] : '',
|
||||
'from_language' => isset( $this->query_args['slang'] ) ? $this->query_args['slang'] : '',
|
||||
'to_language' => isset( $this->query_args['tlang'] ) ? $this->query_args['tlang'] : '',
|
||||
'statuses' => array(
|
||||
'not_translated' => WPML_Media_Translation_Status::NOT_TRANSLATED,
|
||||
'in_progress' => WPML_Media_Translation_Status::IN_PROGRESS,
|
||||
'translated' => WPML_Media_Translation_Status::TRANSLATED,
|
||||
'needs_translation' => WPML_Media_Translation_Status::NEEDS_MEDIA_TRANSLATION,
|
||||
),
|
||||
'search' => isset( $this->query_args['s'] ) ? $this->query_args['s'] : '',
|
||||
'languages' => $languages,
|
||||
'attachments' => $this->get_attachments( $languages ),
|
||||
'nonce' => wp_nonce_field( 'media-translation', 'wpnonce', false, false ),
|
||||
'pagination' => $this->get_pagination(),
|
||||
'target_language' => $this->should_filter_by_target_language() ? $this->query_args['tlang'] : '',
|
||||
|
||||
'batch_translation' => $this->get_batch_translation(),
|
||||
|
||||
'show_text_change_notice' => ! get_user_meta( get_current_user_id(), WPML_Media_Editor_Notices::TEXT_EDIT_NOTICE_DISMISSED, true ),
|
||||
);
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
public static function get_translation_status_labels() {
|
||||
return array(
|
||||
WPML_Media_Translation_Status::NOT_TRANSLATED => __( 'Not translated', 'wpml-media' ),
|
||||
WPML_Media_Translation_Status::IN_PROGRESS => __( 'In progress', 'wpml-media' ),
|
||||
WPML_Media_Translation_Status::TRANSLATED => __( 'Translated', 'wpml-media' ),
|
||||
WPML_Media_Translation_Status::NEEDS_MEDIA_TRANSLATION => __( 'Needs translation', 'wpml-media' ),
|
||||
);
|
||||
}
|
||||
|
||||
private function set_query_args() {
|
||||
$arg_keys = array( 'm', 'status', 'slang', 'tlang', 's', 'paged' );
|
||||
foreach ( $arg_keys as $key ) {
|
||||
if ( isset( $_GET[ $key ] ) ) {
|
||||
$this->query_args[ $key ] = sanitize_text_field( $_GET[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function get_months() {
|
||||
$months = array();
|
||||
|
||||
$month_results = $this->wpdb->get_results(
|
||||
"
|
||||
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
|
||||
FROM {$this->wpdb->posts}
|
||||
WHERE post_type = 'attachment'
|
||||
ORDER BY post_date DESC
|
||||
"
|
||||
);
|
||||
|
||||
foreach ( $month_results as $month ) {
|
||||
$months[] = array(
|
||||
'id' => $month->year . zeroise( $month->month, 2 ),
|
||||
'label' => sprintf( __( '%1$s %2$d' ), $this->wp_locale->get_month( $month->month ), $month->year ),
|
||||
);
|
||||
}
|
||||
|
||||
return $months;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function get_languages() {
|
||||
$languages = array();
|
||||
|
||||
$active_languages = $this->sitepress->get_active_languages();
|
||||
foreach ( $active_languages as $language ) {
|
||||
$languages[ $language['code'] ] = array(
|
||||
'name' => $language['display_name'],
|
||||
'flag' => $this->sitepress->get_flag_url( $language['code'] ),
|
||||
);
|
||||
}
|
||||
|
||||
return $languages;
|
||||
}
|
||||
|
||||
private function get_items_per_page() {
|
||||
return get_option( 'wpml_media_translation_dashboard_items_per_page', 20 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $languages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_attachments( $languages ) {
|
||||
$attachments = array();
|
||||
|
||||
$args = array(
|
||||
'post_type' => 'attachment',
|
||||
'orderby' => 'ID',
|
||||
'order' => 'DESC',
|
||||
'posts_per_page' => $this->get_items_per_page(),
|
||||
);
|
||||
$args = array_merge( $args, $this->query_args );
|
||||
|
||||
if ( $this->should_filter_by_status() ) {
|
||||
$args['meta_query'] = array(
|
||||
'key' => '_media_translation_status',
|
||||
'value' => $this->query_args['status'],
|
||||
);
|
||||
}
|
||||
|
||||
$this->add_query_filters();
|
||||
|
||||
$attachment_posts = get_posts( $args );
|
||||
|
||||
$this->remove_query_filters();
|
||||
|
||||
foreach ( $attachment_posts as $attachment ) {
|
||||
$attachment_id = $attachment->ID;
|
||||
$post_element = new WPML_Post_Element( $attachment_id, $this->sitepress );
|
||||
$media_file_original = get_post_meta( $attachment_id, '_wp_attached_file', true );
|
||||
$translations = array();
|
||||
|
||||
$is_image = (int) ( 0 === strpos( $attachment->post_mime_type, 'image/' ) );
|
||||
|
||||
foreach ( $languages as $code => $language ) {
|
||||
$translation = $post_element->get_translation( $code );
|
||||
|
||||
if ( $translation ) {
|
||||
$translation_post = $translation->get_wp_object();
|
||||
$media_file_translated = get_post_meta( $translation->get_id(), '_wp_attached_file', true );
|
||||
|
||||
$translations[ $code ] = array(
|
||||
'id' => $translation->get_id(),
|
||||
'file_name' => basename( $media_file_translated ),
|
||||
'title' => $translation_post->post_title,
|
||||
'caption' => $translation_post->post_excerpt,
|
||||
'description' => $translation_post->post_content,
|
||||
'alt' => get_post_meta( $translation->get_id(), '_wp_attachment_image_alt', true ),
|
||||
'thumb' => $this->get_attachment_thumb( $translation->get_id(), $is_image ),
|
||||
'media_is_translated' => $media_file_translated && $media_file_translated !== $media_file_original,
|
||||
'status' => $this->get_translation_status( $attachment_id, $translation ),
|
||||
);
|
||||
|
||||
} else {
|
||||
$translations[ $code ] = array(
|
||||
'status' => WPML_Media_Translation_Status::NOT_TRANSLATED,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$attachments[] = array(
|
||||
'post' => $attachment,
|
||||
'mime_type' => $is_image ? 'image/*' : $attachment->post_mime_type,
|
||||
'is_image' => $is_image,
|
||||
'file_name' => basename( $media_file_original ),
|
||||
'alt' => get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ),
|
||||
'meta' => get_post_meta( $attachment_id, '_wp_attachment_metadata', true ),
|
||||
'language' => $post_element->get_language_code(),
|
||||
'thumb' => $this->get_attachment_thumb( $attachment_id, $is_image ),
|
||||
'url' => $is_image ? $this->get_attachment_url( $attachment_id ) : '',
|
||||
'translations' => $translations,
|
||||
'preview' => [
|
||||
'width' => self::PREVIEW_MAX_WIDTH,
|
||||
'height' => self::PREVIEW_MAX_HEIGHT,
|
||||
],
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return $attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $attachment_id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_attachment_url( $attachment_id ) {
|
||||
$image = wp_get_attachment_image_src( $attachment_id, [ self::PREVIEW_MAX_WIDTH, self::PREVIEW_MAX_HEIGHT ] );
|
||||
|
||||
return $image[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $attachment_id
|
||||
* @param bool $is_image
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_attachment_thumb( $attachment_id, $is_image = true ) {
|
||||
$image = wp_get_attachment_image_src( $attachment_id, 'thumbnail', true );
|
||||
|
||||
$thumb = array(
|
||||
'src' => $image ? $image[0] : '',
|
||||
'width' => $is_image ? 60 : $image[1],
|
||||
'height' => $is_image ? 60 : $image[2],
|
||||
);
|
||||
|
||||
return $thumb;
|
||||
}
|
||||
|
||||
public function set_total_items_in_pagination( $query ) {
|
||||
|
||||
$query_count = preg_replace(
|
||||
'/^SELECT /',
|
||||
'SELECT SQL_CALC_FOUND_ROWS ',
|
||||
$query
|
||||
);
|
||||
$this->wpdb->get_results( $query_count );
|
||||
|
||||
$this->pagination->set_total_items( $this->wpdb->get_var( 'SELECT FOUND_ROWS()' ) );
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
private function get_pagination() {
|
||||
|
||||
$this->pagination->set_items_per_page( $this->get_items_per_page() );
|
||||
$current_page = isset( $this->query_args['paged'] ) ? $this->query_args['paged'] : 1;
|
||||
$this->pagination->set_current_page( $current_page );
|
||||
|
||||
$model = array(
|
||||
'strings' => array(
|
||||
'list_navigation' => __( 'Navigation', 'wpml-media' ),
|
||||
'of' => __( 'of', 'wpml-media' ),
|
||||
),
|
||||
'pagination' => array(
|
||||
'get_first_page_url' => $this->pagination->get_first_page_url(),
|
||||
'first_page' => __( 'First page', 'wpml-media' ),
|
||||
|
||||
'get_previous_page_url' => $this->pagination->get_previous_page_url(),
|
||||
'previous_page' => __( 'Previous page', 'wpml-media' ),
|
||||
|
||||
'get_current_page' => $this->pagination->get_current_page(),
|
||||
'get_total_pages' => $this->pagination->get_total_pages(),
|
||||
|
||||
'get_next_page_url' => $this->pagination->get_next_page_url(),
|
||||
'next_page' => __( 'Next page', 'wpml-media' ),
|
||||
|
||||
'get_last_page_url' => $this->pagination->get_last_page_url(),
|
||||
'last_page' => __( 'Last page', 'wpml-media' ),
|
||||
),
|
||||
'total_items' => sprintf(
|
||||
_n( '%s item', '%s items', $this->pagination->get_total_items() ),
|
||||
$this->pagination->get_total_items()
|
||||
),
|
||||
);
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
private function get_batch_translation() {
|
||||
$model = array(
|
||||
'strings' => array(
|
||||
'close' => __( 'Close', 'wpml-media' ),
|
||||
'was_replaced' => __( 'The media that you uploaded was replaced in these translated posts:', 'wpml-media' ),
|
||||
'other_posts' => __( 'The same media might be used in other posts too. Do you want to scan and replace it?', 'wpml-media' ),
|
||||
'without_usage' => __( 'The media that you uploaded will be used in future post translations. The same media might be used in already existing posts. Do you want to scan and replace it now?', 'wpml-media' ),
|
||||
'scan_for_this_media' => __( 'Scan for content that has specifically this media (faster)', 'wpml-media' ),
|
||||
'scan_for_all_media' => __( 'Scan for content that has any of the media files that I translated (takes more time)', 'wpml-media' ),
|
||||
'button_label' => _x( 'Scan & Replace', 'Button label (verb)', 'wpml-media' ),
|
||||
),
|
||||
);
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
private function add_query_filters() {
|
||||
remove_filter( 'posts_join', array( $this->wpml_query_filter, 'posts_join_filter' ), 10 );
|
||||
remove_filter( 'posts_where', array( $this->wpml_query_filter, 'posts_where_filter' ), 10 );
|
||||
|
||||
add_filter( 'posts_join', array( $this, 'filter_request_clause_join' ), PHP_INT_MAX );
|
||||
add_filter( 'posts_where', array( $this, 'filter_request_clause_where' ), PHP_INT_MAX );
|
||||
add_filter( 'posts_request', array( $this, 'set_total_items_in_pagination' ), - PHP_INT_MAX );
|
||||
}
|
||||
|
||||
private function remove_query_filters() {
|
||||
add_filter( 'posts_join', array( $this->wpml_query_filter, 'posts_join_filter' ), 10, 2 );
|
||||
add_filter( 'posts_where', array( $this->wpml_query_filter, 'posts_where_filter' ), 10, 2 );
|
||||
|
||||
remove_filter( 'posts_join', array( $this, 'filter_request_clause_join' ), PHP_INT_MAX );
|
||||
remove_filter( 'posts_where', array( $this, 'filter_request_clause_where' ), PHP_INT_MAX );
|
||||
remove_filter( 'posts_request', array( $this, 'set_total_items_in_pagination' ), - PHP_INT_MAX );
|
||||
}
|
||||
|
||||
public function filter_request_clause_join( $join ) {
|
||||
|
||||
$join .= " LEFT JOIN {$this->wpdb->prefix}icl_translations icl_translations_source
|
||||
ON icl_translations_source.element_id = {$this->wpdb->posts}.ID ";
|
||||
|
||||
if ( $this->should_filter_by_status() ) {
|
||||
if ( $this->should_filter_by_target_language() ) {
|
||||
$join .= $this->wpdb->prepare(
|
||||
" LEFT JOIN {$this->wpdb->postmeta} post_meta
|
||||
ON icl_translations_source.element_id = post_meta.post_id
|
||||
AND post_meta.meta_key = %s
|
||||
",
|
||||
WPML_Media_Translation_Status::STATUS_PREFIX . $this->query_args['tlang']
|
||||
);
|
||||
} else {
|
||||
$active_language = $this->sitepress->get_active_languages();
|
||||
$default_lanuage = $this->sitepress->get_default_language();
|
||||
|
||||
foreach ( $active_language as $language ) {
|
||||
if ( $language['code'] !== $default_lanuage ) {
|
||||
$sanitized_code = str_replace( '-', '_', $language['code'] );
|
||||
|
||||
$join .= $this->wpdb->prepare(
|
||||
" LEFT JOIN {$this->wpdb->postmeta} post_meta_{$sanitized_code}
|
||||
ON {$this->wpdb->posts}.ID = post_meta_{$sanitized_code}.post_id
|
||||
AND post_meta_{$sanitized_code}.meta_key=%s",
|
||||
WPML_Media_Translation_Status::STATUS_PREFIX . $language['code']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( $this->should_filter_by_target_language() ) {
|
||||
$join .= " JOIN {$this->wpdb->prefix}icl_translations icl_translations_target
|
||||
ON icl_translations_target.trid = icl_translations_source.trid
|
||||
AND icl_translations_target.language_code='{$this->query_args['tlang']}'";
|
||||
}
|
||||
}
|
||||
|
||||
return $join;
|
||||
}
|
||||
|
||||
public function filter_request_clause_where( $where ) {
|
||||
|
||||
$where .= " AND icl_translations_source.element_type='post_attachment'
|
||||
AND icl_translations_source.source_language_code IS NULL ";
|
||||
|
||||
if ( ! empty( $this->query_args['slang'] ) && $this->query_args['slang'] !== 'all' ) {
|
||||
$where .= $this->wpdb->prepare( ' AND icl_translations_source.language_code = %s ', $this->query_args['slang'] );
|
||||
}
|
||||
|
||||
if ( $this->should_filter_by_status() ) {
|
||||
if ( $this->should_filter_by_target_language() ) {
|
||||
if ( $this->query_args['status'] === WPML_Media_Translation_Status::NOT_TRANSLATED ) {
|
||||
$where .= $this->wpdb->prepare(
|
||||
' AND (
|
||||
post_meta.meta_value IS NULL OR
|
||||
post_meta.meta_value = %s OR
|
||||
post_meta.meta_value = %s OR
|
||||
post_meta.meta_value = %s
|
||||
)',
|
||||
WPML_Media_Translation_Status::NOT_TRANSLATED,
|
||||
WPML_Media_Translation_Status::IN_PROGRESS,
|
||||
WPML_Media_Translation_Status::NEEDS_MEDIA_TRANSLATION
|
||||
);
|
||||
} else {
|
||||
$where .= $this->wpdb->prepare( ' AND post_meta.meta_value = %s', $this->query_args['status'] );
|
||||
}
|
||||
} else {
|
||||
$active_language = $this->sitepress->get_active_languages();
|
||||
$default_language = $this->sitepress->get_default_language();
|
||||
|
||||
if ( $this->query_args['status'] === WPML_Media_Translation_Status::TRANSLATED ) {
|
||||
foreach ( $active_language as $language ) {
|
||||
$sanitized_code = str_replace( '-', '_', $language['code'] );
|
||||
if ( $language['code'] !== $default_language ) {
|
||||
$where .= $this->wpdb->prepare(
|
||||
"AND post_meta_{$sanitized_code}.meta_value = %s",
|
||||
WPML_Media_Translation_Status::TRANSLATED
|
||||
);
|
||||
}
|
||||
}
|
||||
} elseif ( $this->query_args['status'] === WPML_Media_Translation_Status::NOT_TRANSLATED ) {
|
||||
$where .= 'AND ( 0 ';
|
||||
foreach ( $active_language as $language ) {
|
||||
$sanitized_code = str_replace( '-', '_', $language['code'] );
|
||||
if ( $language['code'] !== $default_language ) {
|
||||
$where .= $this->wpdb->prepare(
|
||||
"
|
||||
OR post_meta_{$sanitized_code}.meta_value = %s
|
||||
OR post_meta_{$sanitized_code}.meta_value IS NULL",
|
||||
$this->query_args['status']
|
||||
);
|
||||
}
|
||||
}
|
||||
$where .= ') ';
|
||||
} else {
|
||||
$where .= 'AND ( 0 ';
|
||||
foreach ( $active_language as $language ) {
|
||||
$sanitized_code = str_replace( '-', '_', $language['code'] );
|
||||
if ( $language['code'] !== $default_language ) {
|
||||
$where .= $this->wpdb->prepare(
|
||||
"
|
||||
OR post_meta_{$sanitized_code}.meta_value = %s",
|
||||
$this->query_args['status']
|
||||
);
|
||||
}
|
||||
}
|
||||
$where .= ') ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
private function should_filter_by_status() {
|
||||
return isset( $this->query_args['status'] ) && $this->query_args['status'] !== '';
|
||||
}
|
||||
|
||||
private function should_filter_by_target_language() {
|
||||
return isset( $this->query_args['tlang'] ) && $this->query_args['tlang'] !== '';
|
||||
}
|
||||
|
||||
protected function init_template_base_dir() {
|
||||
$this->template_paths = array(
|
||||
WPML_MEDIA_PATH . '/templates/menus/',
|
||||
WPML_PLUGIN_PATH . '/templates/pagination/',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_template() {
|
||||
return 'media-translation.twig';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $attachment_id
|
||||
* @param $translation
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
private function get_translation_status( $attachment_id, $translation ) {
|
||||
$translation_status = get_post_meta(
|
||||
$attachment_id,
|
||||
WPML_Media_Translation_Status::STATUS_PREFIX . $translation->get_language_code(),
|
||||
true
|
||||
);
|
||||
if ( ! $translation_status ) {
|
||||
$translation_status = WPML_Media_Translation_Status::NOT_TRANSLATED;
|
||||
}
|
||||
|
||||
return $translation_status;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_Media_Privacy_Content_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
/**
|
||||
* @return IWPML_Action
|
||||
*/
|
||||
public function create() {
|
||||
return new WPML_Media_Privacy_Content();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_Media_Privacy_Content extends WPML_Privacy_Content {
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function get_plugin_name() {
|
||||
return 'WPML Media Translation';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|array
|
||||
*/
|
||||
protected function get_privacy_policy() {
|
||||
return __( 'WPML Media Translation will send the email address and name of each manager and assigned translator as well as the content itself to Advanced Translation Editor and to the translation services which are used.', 'wpml-media' );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Set_Initial_Language_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $sitepress, $wpdb;
|
||||
return new WPML_Media_Set_Initial_Language( $wpdb, $sitepress->get_default_language() );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Class WPML_Media_Set_Initial_Language
|
||||
*/
|
||||
class WPML_Media_Set_Initial_Language implements IWPML_Action {
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $language;
|
||||
|
||||
/**
|
||||
* WPML_Media_Set_Initial_Language constructor.
|
||||
*
|
||||
* @param wpdb $wpdb
|
||||
* @param string $language
|
||||
*/
|
||||
public function __construct( wpdb $wpdb, $language ) {
|
||||
$this->wpdb = $wpdb;
|
||||
$this->language = $language;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wp_ajax_wpml_media_set_initial_language', array( $this, 'set' ) );
|
||||
}
|
||||
|
||||
public function set() {
|
||||
|
||||
$this->update_db();
|
||||
|
||||
$message = __( 'Setting language to media: done!', 'wpml-media' );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'message' => $message,
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function update_db() {
|
||||
$maxtrid = $this->wpdb->get_var( "SELECT MAX(trid) FROM {$this->wpdb->prefix}icl_translations" );
|
||||
|
||||
$this->wpdb->query(
|
||||
$this->wpdb->prepare(
|
||||
"
|
||||
INSERT INTO {$this->wpdb->prefix}icl_translations
|
||||
(element_type, element_id, trid, language_code, source_language_code)
|
||||
SELECT 'post_attachment', ID, %d + ID, %s, NULL
|
||||
FROM {$this->wpdb->posts} p
|
||||
LEFT JOIN {$this->wpdb->prefix}icl_translations t
|
||||
ON p.ID = t.element_id AND t.element_type = 'post_attachment'
|
||||
WHERE post_type = 'attachment' AND t.translation_id IS NULL",
|
||||
$maxtrid,
|
||||
$this->language
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Translation_Editor_Layout_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
return new WPML_Media_Translation_Editor_Layout();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Translation_Editor_Layout implements IWPML_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'wpml_tm_job_layout', array( $this, 'group_media_fields' ) );
|
||||
add_filter( 'wpml_tm_adjust_translation_fields', array( $this, 'set_custom_labels' ) );
|
||||
}
|
||||
|
||||
public function group_media_fields( $fields ) {
|
||||
|
||||
$media_fields = array();
|
||||
|
||||
foreach ( $fields as $k => $field ) {
|
||||
$media_field = $this->is_media_field( $field );
|
||||
if ( $media_field ) {
|
||||
unset( $fields[ $k ] );
|
||||
$media_fields[ $media_field['attachment_id'] ][] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $media_fields ) {
|
||||
|
||||
$media_section_field = array(
|
||||
'field_type' => 'tm-section',
|
||||
'title' => __( 'Media', 'wpml-media' ),
|
||||
'fields' => array(),
|
||||
'empty' => false,
|
||||
'empty_message' => '',
|
||||
'sub_title' => '',
|
||||
);
|
||||
|
||||
foreach ( $media_fields as $attachment_id => $media_field ) {
|
||||
|
||||
$media_group_field = array(
|
||||
'title' => '',
|
||||
'divider' => false,
|
||||
'field_type' => 'tm-group',
|
||||
'fields' => $media_field,
|
||||
);
|
||||
|
||||
$image = wp_get_attachment_image_src( $attachment_id, array( 100, 100 ) );
|
||||
$image_field = array(
|
||||
'field_type' => 'wcml-image',
|
||||
'divider' => $media_field !== end( $media_fields ),
|
||||
'image_src' => $image[0],
|
||||
'fields' => array( $media_group_field ),
|
||||
);
|
||||
|
||||
$media_section_field['fields'][] = $image_field;
|
||||
|
||||
}
|
||||
|
||||
$fields[] = $media_section_field;
|
||||
}
|
||||
|
||||
return array_values( $fields );
|
||||
}
|
||||
|
||||
private function is_media_field( $field ) {
|
||||
$media_field = array();
|
||||
if ( is_string( $field ) && preg_match( '/^media_([0-9]+)_([a-z_]+)/', $field, $match ) ) {
|
||||
$media_field = array(
|
||||
'attachment_id' => (int) $match[1],
|
||||
'label' => $match[2],
|
||||
);
|
||||
}
|
||||
|
||||
return $media_field;
|
||||
}
|
||||
|
||||
public function set_custom_labels( $fields ) {
|
||||
|
||||
foreach ( $fields as $k => $field ) {
|
||||
$media_field = $this->is_media_field( $field['field_type'] );
|
||||
if ( $media_field ) {
|
||||
$fields[ $k ]['title'] = $this->get_field_label( $media_field );
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
private function get_field_label( $media_field ) {
|
||||
|
||||
switch ( $media_field['label'] ) {
|
||||
case 'title':
|
||||
$label = __( 'Title', 'wpml-media' );
|
||||
break;
|
||||
case 'caption':
|
||||
$label = __( 'Caption', 'wpml-media' );
|
||||
break;
|
||||
case 'description':
|
||||
$label = __( 'Description', 'wpml-media' );
|
||||
break;
|
||||
case 'alt_text':
|
||||
$label = __( 'Alt Text', 'wpml-media' );
|
||||
break;
|
||||
default:
|
||||
$label = '';
|
||||
}
|
||||
|
||||
return $label;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_2_3_0_Migration {
|
||||
|
||||
const FLAG = 'wpml_media_2_3_migration';
|
||||
const BATCH_SIZE = 200;
|
||||
|
||||
const MAX_BATCH_REQUEST_TIME = 5;
|
||||
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* WPML_Media_2_3_0_Migration constructor.
|
||||
*
|
||||
* @param wpdb $wpdb
|
||||
* @param SitePress $sitepress
|
||||
*/
|
||||
public function __construct( wpdb $wpdb, SitePress $sitepress ) {
|
||||
$this->wpdb = $wpdb;
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
public static function migration_complete() {
|
||||
return WPML_Media::get_setting( self::FLAG );
|
||||
}
|
||||
|
||||
private function mark_migration_complete() {
|
||||
return WPML_Media::update_setting( self::FLAG, 1 );
|
||||
}
|
||||
|
||||
public function is_required() {
|
||||
if ( $this->wpdb->get_var( "SELECT COUNT(ID) FROM {$this->wpdb->posts} WHERE post_type='attachment'" ) ) {
|
||||
return true;
|
||||
}
|
||||
self::mark_migration_complete();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'wpml_media_menu_overrides', array( $this, 'override_default_menu' ) );
|
||||
add_action( 'wp_ajax_wpml_media_2_3_0_upgrade', array( $this, 'run_upgrade' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_js' ) );
|
||||
}
|
||||
|
||||
public function override_default_menu( $menu_elements ) {
|
||||
$menu_elements[] = array( $this, 'render_menu' );
|
||||
return $menu_elements;
|
||||
}
|
||||
|
||||
public function maybe_show_admin_notice() {
|
||||
if ( is_admin() && ! $this->is_wpml_media_screen() ) {
|
||||
add_action( 'admin_notices', array( $this, 'render_menu' ) );
|
||||
}
|
||||
}
|
||||
|
||||
private function is_wpml_media_screen() {
|
||||
return isset( $_GET['page'] ) && $_GET['page'] === 'wpml-media';
|
||||
}
|
||||
|
||||
public function enqueue_js() {
|
||||
$wpml_media_url = $this->sitepress->get_wp_api()->constant( 'WPML_MEDIA_URL' );
|
||||
wp_enqueue_script( 'wpml-media-2-3-0-upgrade', $wpml_media_url . '/res/js/upgrade/upgrade-2-3-0.js', array( 'jquery' ), false, true );
|
||||
}
|
||||
|
||||
public function render_menu() {
|
||||
|
||||
if ( $this->is_wpml_media_screen() ) : ?>
|
||||
<div class="wrap wrap-wpml-media-upgrade">
|
||||
<h2><?php esc_html_e( 'Upgrade required', 'wpml-media' ); ?></h2>
|
||||
<?php endif; ?>
|
||||
<div class="notice notice-warning" id="wpml-media-2-3-0-update" style="padding-bottom:8px">
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
esc_html__( 'The %1$sWPML Media%2$s database needs updating. Please run the updater and leave the tab open until it completes.', 'wpml-media' ),
|
||||
'<strong>',
|
||||
'</strong>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<input type="button" class="button-primary alignright" value="<?php echo esc_attr_x( 'Update', 'Update button label', 'wpml-media' ); ?>" />
|
||||
<input type="hidden" name="nonce" value="<?php echo wp_create_nonce( 'wpml-media-2-3-0-update' ); ?>" />
|
||||
<span class="spinner"></span>
|
||||
<p class="alignleft status description"></p><br clear="all" />
|
||||
</div>
|
||||
<?php if ( $this->is_wpml_media_screen() ) : ?>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
|
||||
}
|
||||
|
||||
private function reset_new_content_settings() {
|
||||
$wpml_media_settings = get_option( '_wpml_media' );
|
||||
// reset (will not remove since it's used by WCML)
|
||||
$wpml_media_settings['new_content_settings']['always_translate_media'] = 0;
|
||||
$wpml_media_settings['new_content_settings']['duplicate_media'] = 0;
|
||||
$wpml_media_settings['new_content_settings']['duplicate_featured'] = 0;
|
||||
update_option( '_wpml_media', $wpml_media_settings );
|
||||
}
|
||||
|
||||
public function run_upgrade() {
|
||||
|
||||
if ( isset( $_POST['nonce'] ) && ( $_POST['nonce'] === wp_create_nonce( 'wpml-media-2-3-0-update' ) ) ) {
|
||||
|
||||
$step = isset( $_POST['step'] ) ? $_POST['step'] : '';
|
||||
|
||||
if ( 'reset-new-content-settings' === $step ) {
|
||||
$this->reset_new_content_settings();
|
||||
wp_send_json_success(
|
||||
array( 'status' => esc_html__( 'Reset new content duplication settings', 'wpml-media' ) )
|
||||
);
|
||||
} elseif ( 'migrate-attachments' === $step ) {
|
||||
$offset = isset( $_POST['offset'] ) ? (int) $_POST['offset'] : 0;
|
||||
|
||||
$batch_size = $this->get_dynamic_batch_size( $_POST );
|
||||
|
||||
$left = $this->migrate_attachments( $offset, $batch_size );
|
||||
|
||||
if ( $left ) {
|
||||
$status = sprintf(
|
||||
esc_html__( 'Updating attachments translation status: %d remaining.', 'wpml-media' ),
|
||||
$left
|
||||
);
|
||||
$continue = 1;
|
||||
$offset += $batch_size;
|
||||
} else {
|
||||
$this->mark_migration_complete();
|
||||
$status = esc_html__( 'Update complete!', 'wpml-media' );
|
||||
$continue = 0;
|
||||
$offset = 0;
|
||||
}
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'status' => $status,
|
||||
'goon' => $continue,
|
||||
'offset' => $offset,
|
||||
'timestamp' => microtime( true ),
|
||||
)
|
||||
);
|
||||
|
||||
} else {
|
||||
wp_send_json_error( array( 'error' => 'Invalid step' ) );
|
||||
}
|
||||
} else {
|
||||
wp_send_json_error( array( 'error' => 'Invalid nonce' ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function migrate_attachments( $offset = 0, $batch_size = self::BATCH_SIZE ) {
|
||||
|
||||
$sql = "SELECT SQL_CALC_FOUND_ROWS p.ID
|
||||
FROM {$this->wpdb->posts} p
|
||||
JOIN {$this->wpdb->prefix}icl_translations t
|
||||
ON t.element_id = p.ID AND p.post_type='attachment'
|
||||
WHERE t.source_language_code IS NULL
|
||||
LIMIT %d, %d";
|
||||
|
||||
$sql_prepared = $this->wpdb->prepare( $sql, $offset, $batch_size );
|
||||
|
||||
$original_attachments = $this->wpdb->get_results( $sql_prepared );
|
||||
|
||||
$total_attachments = $this->wpdb->get_var( 'SELECT FOUND_ROWS() ' );
|
||||
|
||||
if ( $original_attachments ) {
|
||||
foreach ( $original_attachments as $attachment ) {
|
||||
|
||||
$post_element = new WPML_Post_Element( $attachment->ID, $this->sitepress );
|
||||
$translations = $post_element->get_translations();
|
||||
|
||||
$media_file = get_post_meta( $attachment->ID, '_wp_attached_file', true );
|
||||
|
||||
foreach ( $translations as $translation ) {
|
||||
if ( (int) $attachment->ID !== $translation->get_id() ) {
|
||||
$media_translation_status = WPML_Media_Translation_Status::NOT_TRANSLATED;
|
||||
$media_file_translation = get_post_meta( $translation->get_id(), '_wp_attached_file', true );
|
||||
if ( $media_file_translation !== $media_file ) {
|
||||
$media_translation_status = WPML_Media_Translation_Status::TRANSLATED;
|
||||
}
|
||||
update_post_meta(
|
||||
$attachment->ID,
|
||||
WPML_Media_Translation_Status::STATUS_PREFIX . $translation->get_language_code(),
|
||||
$media_translation_status
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$left = max( 0, $total_attachments - $offset );
|
||||
|
||||
return $left;
|
||||
}
|
||||
|
||||
private function get_dynamic_batch_size( $request ) {
|
||||
$batch_size_factor = isset( $request['batch_size_factor'] ) ? (int) $request['batch_size_factor'] : 1;
|
||||
if ( ! empty( $request['timestamp'] ) ) {
|
||||
$elapsed_time = microtime( true ) - (float) $request['timestamp'];
|
||||
|
||||
if ( $elapsed_time < self::MAX_BATCH_REQUEST_TIME ) {
|
||||
$batch_size_factor ++;
|
||||
} else {
|
||||
$batch_size_factor = max( 1, $batch_size_factor - 1 );
|
||||
}
|
||||
}
|
||||
return self::BATCH_SIZE * $batch_size_factor;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user