first commit
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
class AddMediaDataToTranslationPackage implements \IWPML_Backend_Action {
|
||||
|
||||
const ALT_PLACEHOLDER = '{%ALT_TEXT%}';
|
||||
const CAPTION_PLACEHOLDER = '{%CAPTION%}';
|
||||
|
||||
/** @var PostWithMediaFilesFactory $post_media_factory */
|
||||
private $post_media_factory;
|
||||
|
||||
public function __construct( PostWithMediaFilesFactory $post_media_factory ) {
|
||||
$this->post_media_factory = $post_media_factory;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
if ( \WPML_Media_Duplication_Setup::isTranslateMediaLibraryTextsEnabled() ) {
|
||||
add_action( 'wpml_tm_translation_job_data', [ $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 = [
|
||||
'translate' => 0,
|
||||
'data' => true,
|
||||
'format' => '',
|
||||
];
|
||||
} else {
|
||||
$options = [
|
||||
'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 ] = [
|
||||
'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 = [];
|
||||
|
||||
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 MediaCaptionTagsParse();
|
||||
|
||||
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, MediaCaption $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, MediaCaption $caption ) {
|
||||
|
||||
$alt_text = $caption->get_image_alt();
|
||||
|
||||
return str_replace( 'alt="' . $alt_text . '"', 'alt="' . self::ALT_PLACEHOLDER . '"', $caption_shortcode );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
class AddMediaDataToTranslationPackageFactory implements \IWPML_Backend_Action_Loader {
|
||||
public function create() {
|
||||
return new AddMediaDataToTranslationPackage( new PostWithMediaFilesFactory() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
class MediaAttachmentByUrl {
|
||||
/**
|
||||
* @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,11 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
class MediaAttachmentByUrlFactory {
|
||||
public function create( $url, $language ) {
|
||||
global $wpdb;
|
||||
|
||||
return new MediaAttachmentByUrl( $wpdb, $url, $language );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
class MediaCaption {
|
||||
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 MediaImgParse();
|
||||
$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
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
class MediaCaptionTagsParse {
|
||||
/**
|
||||
* @param string $text
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_captions( $text ) {
|
||||
$captions = [];
|
||||
|
||||
if ( preg_match_all( '/\[caption (.+)\](.+)\[\/caption\]/sU', $text, $matches ) ) {
|
||||
|
||||
for ( $i = 0; $i < count( $matches[0] ); $i ++ ) {
|
||||
$captions[] = new MediaCaption( $matches[0][ $i ], $matches[1][ $i ], $matches[2][ $i ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $captions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
use WPML\LIB\WP\Attachment;
|
||||
|
||||
class MediaImgParse {
|
||||
/**
|
||||
* @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 ) {
|
||||
$media = wpml_collect( [] );
|
||||
|
||||
$media_elements = [
|
||||
'/<img ([^>]+)>/s',
|
||||
'/<video ([^>]+)>/s',
|
||||
'/<audio ([^>]+)>/s',
|
||||
];
|
||||
|
||||
foreach ( $media_elements as $element_expression ) {
|
||||
if ( preg_match_all( $element_expression, $text, $matches ) ) {
|
||||
$media = $media->merge( $this->getAttachments( $matches ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $media->toArray();
|
||||
}
|
||||
|
||||
private function getAttachments( $matches ) {
|
||||
$attachments = [];
|
||||
|
||||
foreach ( $matches[1] as $i => $match ) {
|
||||
if ( preg_match_all( '/(\S+)\\s*=\\s*["\']?((?:.(?!["\']?\s+(?:\S+)=|[>"\']))+.)["\']?/', $match, $attribute_matches ) ) {
|
||||
$attributes = [];
|
||||
foreach ( $attribute_matches[1] as $k => $key ) {
|
||||
$attributes[ $key ] = $attribute_matches[2][ $k ];
|
||||
}
|
||||
if ( isset( $attributes['src'] ) ) {
|
||||
$attachments[ $i ]['attributes'] = $attributes;
|
||||
$attachments[ $i ]['attachment_id'] = Attachment::idFromUrl( $attributes['src'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_from_css_background_images( $text ) {
|
||||
$images = [];
|
||||
|
||||
if ( preg_match_all( '/<\w+[^>]+style\s?=\s?"[^"]*?background-image:url\(\s?([^\s\)]+)\s?\)/', $text, $matches ) ) {
|
||||
foreach ( $matches[1] as $src ) {
|
||||
$images[] = [
|
||||
'attributes' => [ 'src' => $src ],
|
||||
'attachment_id' => null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $images;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $blocks
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_from_css_background_images_in_blocks( $blocks ) {
|
||||
$images = [];
|
||||
|
||||
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' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
class MediaSettings {
|
||||
private static $settings;
|
||||
private static $settings_option_key = '_wpml_media';
|
||||
private static $default_settings = [
|
||||
'version' => false,
|
||||
'media_files_localization' => [
|
||||
'posts' => true,
|
||||
'custom_fields' => true,
|
||||
'strings' => true,
|
||||
],
|
||||
'wpml_media_2_3_migration' => true,
|
||||
'setup_run' => false,
|
||||
];
|
||||
|
||||
public static function init_settings() {
|
||||
if ( ! self::$settings ) {
|
||||
self::$settings = get_option( self::$settings_option_key, [] );
|
||||
}
|
||||
|
||||
self::$settings = array_merge( self::$default_settings, self::$settings );
|
||||
}
|
||||
|
||||
|
||||
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 ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
class MediaTranslationEditorLayout implements \IWPML_Action {
|
||||
public function add_hooks() {
|
||||
if ( \WPML_Media_Duplication_Setup::isTranslateMediaLibraryTextsEnabled() ) {
|
||||
add_filter( 'wpml_tm_job_layout', [ $this, 'group_media_fields' ] );
|
||||
add_filter( 'wpml_tm_adjust_translation_fields', [ $this, 'set_custom_labels' ] );
|
||||
}
|
||||
}
|
||||
|
||||
public function group_media_fields( $fields ) {
|
||||
|
||||
$media_fields = [];
|
||||
|
||||
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 = [
|
||||
'field_type' => 'tm-section',
|
||||
'title' => __( 'Media', 'wpml-media' ),
|
||||
'fields' => [],
|
||||
'empty' => false,
|
||||
'empty_message' => '',
|
||||
'sub_title' => '',
|
||||
];
|
||||
|
||||
foreach ( $media_fields as $attachment_id => $media_field ) {
|
||||
|
||||
$media_group_field = [
|
||||
'title' => '',
|
||||
'divider' => false,
|
||||
'field_type' => 'tm-group',
|
||||
'fields' => $media_field,
|
||||
];
|
||||
|
||||
$image = wp_get_attachment_image_src( $attachment_id, [ 100, 100 ] );
|
||||
$image_field = [
|
||||
'field_type' => 'wcml-image',
|
||||
'divider' => $media_field !== end( $media_fields ),
|
||||
'image_src' => $image[0],
|
||||
'fields' => [ $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 = [];
|
||||
if ( is_string( $field ) && preg_match( '/^media_([0-9]+)_([a-z_]+)/', $field, $match ) ) {
|
||||
$media_field = [
|
||||
'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,9 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
class MediaTranslationEditorLayoutFactory implements \IWPML_Backend_Action_Loader {
|
||||
public function create() {
|
||||
return new MediaTranslationEditorLayout();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
use WPML\FP\Fns;
|
||||
use WPML\LIB\WP\Post;
|
||||
use WPML_Post_Element;
|
||||
|
||||
class PostWithMediaFiles {
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $post_id;
|
||||
/**
|
||||
* @var MediaImgParse
|
||||
*/
|
||||
private $media_parser;
|
||||
/**
|
||||
* @var MediaAttachmentByUrlFactory
|
||||
*/
|
||||
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 MediaImgParse $media_parser
|
||||
* @param MediaAttachmentByUrlFactory $attachment_by_url_factory
|
||||
* @param \SitePress $sitepress
|
||||
* @param \WPML_Custom_Field_Setting_Factory $cf_settings_factory
|
||||
*/
|
||||
public function __construct(
|
||||
$post_id,
|
||||
MediaImgParse $media_parser,
|
||||
MediaAttachmentByUrlFactory $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 = [];
|
||||
|
||||
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 = MediaSettings::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 Fns::filter( Post::get(), 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 = [];
|
||||
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 = [];
|
||||
$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 );
|
||||
$media_ids_array = Fns::map( Fns::unary( 'intval' ), $media_ids_array );
|
||||
|
||||
foreach ( $media_ids_array as $media_id ) {
|
||||
if ( 'attachment' === get_post_type( $media_id ) ) {
|
||||
$galleries_media_ids[] = $media_id;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $galleries_media_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $languages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_untranslated_media( $languages ) {
|
||||
|
||||
$untranslated_media = [];
|
||||
|
||||
$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 );
|
||||
|
||||
if ( is_array( $post_meta ) ) {
|
||||
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(
|
||||
[
|
||||
'post_parent' => $post_id,
|
||||
'post_status' => 'inherit',
|
||||
'post_type' => 'attachment',
|
||||
]
|
||||
);
|
||||
|
||||
return array_keys( $attachments );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\MediaTranslation;
|
||||
|
||||
class PostWithMediaFilesFactory {
|
||||
public function create( $post_id ) {
|
||||
global $sitepress, $iclTranslationManagement;
|
||||
|
||||
return new PostWithMediaFiles(
|
||||
$post_id,
|
||||
new MediaImgParse(),
|
||||
new MediaAttachmentByUrlFactory(),
|
||||
$sitepress,
|
||||
new \WPML_Custom_Field_Setting_Factory( $iclTranslationManagement )
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user