d8e970ab by Jeff Balicki

stuff

Signed-off-by: Jeff <jeff@gotenzing.com>
1 parent bdf10794
Showing 143 changed files with 4879 additions and 0 deletions
<?php if ( ! defined( 'ABSPATH' ) ) {
exit;
} ?>
<div class="wrap dpp_page_settings">
<h1><?php _e( 'Plugin Settings', 'duplicate-wp-page-post' ) ?></h1>
<?php
$dpp_options = array();
$opt = get_option( 'dpp_wpp_page_options' );
$getinstruct = sanitize_text_field($_GET['instruct']);
$instruct = isset( $getinstruct ) ? $getinstruct : '';
if ( isset( $_POST['submit_dpp_wpp_page'] ) && wp_verify_nonce( $_POST['dpp_nonce_field'], 'dpp_page_action' ) ):
_e( "<strong>changes saving..</strong>", 'duplicate-wp-page-post' );
$dpp_nosave = array( 'submit_dpp_wpp_page' );
foreach ( $dpp_nosave as $noneed ):
unset( $_POST[ $noneed ] );
endforeach;
foreach ( $_POST as $key => $val ):
$dpp_options[ $key ] = sanitize_text_field( $val );
endforeach;
$dpp_settings_save = update_option( 'dpp_wpp_page_options', $dpp_options );
if ( $dpp_settings_save ) {
dpp_wpp_page::dp_redirect( 'options-general.php?page=dpp_page_settings&instruct=1' );
} else {
dpp_wpp_page::dp_redirect( 'options-general.php?page=dpp_page_settings&instruct=2' );
}endif;
if ( ! empty( $instruct ) && $instruct == 1 ):
_e( '<div id="message" class="updated notice notice-success is-dismissible">
<p>Changes Saved!</p>
<button type="button" class="notice-dismiss">
<span class="screen-reader-text">Ignore this notice.</span>
</button>
</div>', 'duplicate-wp-page-post' );
elseif ( ! empty( $instruct ) && $instruct == 2 ):
_e( '<div id="message" class="error notice notice-error is-dismissible">
<p>Changes not saved!</p>
<button type="button" class="notice-dismiss">
<span class="screen-reader-text">Ignore this notice.</span>
</button>
</div>', 'duplicate-wp-page-post' );
endif;
?>
<div id="dpp-stuff">
<div id="dpp-post-body" class="metabox-holder columns-2">
<div id="dpp-post-body-content" style="position: relative;">
<form style="padding: 10px; border: 1px solid #333;" action="" method="post" name="dpp_wpp_page_form">
<?php wp_nonce_field( 'dpp_page_action', 'dpp_nonce_field' ); ?>
<table class="form-table">
<tbody>
<tr>
<th scope="row"><label
for="dpp_posteditor">Select Editor<br><em>Default: Classic Editor</em></label>
</th>
<td>
<select id="dpp_posteditor" name="dpp_posteditor">
<option value="classic" <?php echo ( isset( $opt['dpp_posteditor'] ) && $opt['dpp_posteditor'] == 'classic' ) ? "selected = 'selected'" : ''; ?>><?php _e( 'Classic Editor', 'duplicate-wp-page-post' ); ?></option>
<option value="gutenberg" <?php echo ( isset( $opt['dpp_posteditor'] ) && $opt['dpp_posteditor'] == 'gutenberg' ) ? "selected = 'selected'" : ''; ?>><?php _e( 'Gutenberg Editor', 'duplicate-wp-page-post' ); ?></option>
</select>
<p>Please select which editor you are using.<br> If you are using Gutenberg, select
gutenberg editor otherwise it will not show Duplicate button on edit screen.</p>
</td>
</tr>
<tr>
<th scope="row"><label
for="dpp_post_status">Post Status<br><em>Default: Draft</em></label>
</th>
<td>
<select id="dpp_post_status" name="dpp_post_status">
<option value="draft" <?php echo ( $opt['dpp_post_status'] == 'draft' ) ? "selected = 'selected'" : ''; ?>><?php _e( 'Draft', 'duplicate-wp-page-post' ); ?></option>
<option value="publish" <?php echo ( $opt['dpp_post_status'] == 'publish' ) ? "selected = 'selected'" : ''; ?>><?php _e( 'Publish', 'duplicate-wp-page-post' ); ?></option>
<option value="private" <?php echo ( $opt['dpp_post_status'] == 'private' ) ? "selected = 'selected'" : ''; ?>><?php _e( 'Private', 'duplicate-wp-page-post' ); ?></option>
<option value="pending" <?php echo ( $opt['dpp_post_status'] == 'pending' ) ? "selected = 'selected'" : ''; ?>><?php _e( 'Pending', 'duplicate-wp-page-post' ); ?></option>
</select>
<p>Please select any post status you want to assign for duplicate post.</p>
</td>
</tr>
<tr>
<th scope="row"><label
for="dpp_post_redirect">Redirect<br><em>Default: To current list.</em><br>(After
click on <strong>Duplicate</strong></label>
</th>
<td>
<select id="dpp_post_redirect" name="dpp_post_redirect">
<option value="to_list" <?php echo ( $opt['dpp_post_redirect'] == 'to_list' ) ? "selected = 'selected'" : ''; ?>><?php _e( 'All Post List', 'duplicate-wp-page-post' ); ?></option>
<option value="to_page" <?php echo ( $opt['dpp_post_redirect'] == 'to_page' ) ? "selected = 'selected'" : ''; ?>><?php _e( 'Direct Edit', 'duplicate-wp-page-post' ); ?></option>
</select>
<p>Please select any post redirection, redirect you to selected after click on
duplicate.</p>
</td>
</tr>
<tr>
<th scope="row"><label
for="dpp_post_suffix">Duplicate Post Suffix<br><em>Default: Empty</em></label>
</th>
<td>
<input type="text" class="regular-text"
value="<?php echo ! empty( $opt['dpp_post_suffix'] ) ? esc_attr( $opt['dpp_post_suffix'] ) : '' ?>"
id="dpp_post_suffix" name="dpp_post_suffix">
<p>Add a suffix for duplicate page and post. It will show after title.</p>
</td>
</tr>
<tr>
<th scope="row"><label
for="dpp_post_link_title">Duplicate Link Text<br><em>Default:
Duplicate</em></label>
</th>
<td>
<input type="text" class="regular-text"
value="<?php echo ! empty( $opt['dpp_post_link_title'] ) ? esc_attr( $opt['dpp_post_link_title'] ) : '' ?>"
id="dpp_post_link_title" name="dpp_post_link_title">
<p>It will show above text on duplicate page/post link button instead of default
(Duplicate)</p>
</td>
</tr>
</tbody>
</table>
<p class="submit"><input type="submit" value="Save Settings" class="button button-primary"
id="submit" name="submit_dpp_wpp_page"></p>
</form>
</div>
</div>
<div>
<h3><a href="https://wordpress.org/support/plugin/duplicate-wp-page-post/reviews/?filter=5#new-post">Please
review us</a> if you like the plugin.</h3>
</div>
</div>
</div>
\ No newline at end of file
=== Duplicate Page and Post ===
Contributors: arjunthakur, efficientninja
Tags: duplicate post, duplicate page, clone page, clone post, duplicate custom posts, clone custom post, wordpress page duplicator, wordpress post duplicator, page duplicate, clone page and post, wp post clone.
Requires at least: 3.5
Tested up to: 6.2
Requires PHP: 5.2.4
Stable tag: 2.9.3
Version: 2.9.3
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Duplicate post, Duplicate page and Duplicate custom post or clone page and clone post.
== Description ==
Duplicate page and post plugin provides functionality to create a clone of page or posts. You can duplicate pages, posts and custom post by single click and it will be saved as draft.
Duplicate page and post doesn't have a lot of features that other plugins have, but it also is lightning fast by comparison.
= Major features of this plugin include =
* Create a clone of particular page.
* Create a clone of particular post.
* Create a clone of particular custom post(CPT).
* Option to select editor (Classic and Gutenberg)
* Option to add Post Suffix.
* Option to add custom text for duplicate link button.
* Option to select Duplicate Posts Status.
* Option to Redirect after click on Duplicate.
= Like the plugin? =
<a href="https://wordpress.org/support/plugin/duplicate-wp-page-post/reviews/?rate=5#new-post">Please Vote</a>, Your votes really make a difference! Thanks.
== Installation ==
The plugin is simple to install:
* Download duplicate-wp-page-post.zip
* Unzip
* Upload duplicate-wp-page-post directory to your /wp-content/plugins directory
* Go to the plugin menu page and activate the plugin
== Frequently asked questions ==
= How to create the duplicate of a page or a post? =
1. Activate the plugin through the 'Plugins' menu in WordPress.
2. Then Create New Post/Page Or you can use old one.
3. Now go to all pages or all posts page on your dashboard.
4. Hover your cursor over any page or any post on dashboard section, you'll see a "Click here to clone" Button.
5. After you click on "Duplicate" link, then duplicate post/page will be created and saved as draft, make the changes you wish and hit publish.
= What is the benefit of using this plugin? =
User can easily duplicate the posts, pages or the custom posts with single click. It saves user's time to re-create the same post or page again.
== Screenshots ==
1. screenshot1.png
2. screenshot2.png
3. screenshot3.png
4. screenshot4.png
\ No newline at end of file
<?php
namespace WPML\Media\Widgets\Block;
use WPML\Element\API\Languages;
use WPML\LIB\WP\Hooks;
use function WPML\FP\spreadArgs;
class DisplayTranslation implements \IWPML_Frontend_Action, \IWPML_DIC_Action {
/**
* @var \WPML_Media_Translated_Images_Update $translatedImageUpdate
*/
private $translatedImageUpdate;
public function __construct( \WPML_Media_Translated_Images_Update $translatedImageUpdate ) {
$this->translatedImageUpdate = $translatedImageUpdate;
}
public function add_hooks() {
Hooks::onFilter( 'widget_block_content' )
->then( spreadArgs( function ( $content ) {
return $this->translatedImageUpdate->replace_images_with_translations( $content, Languages::getCurrentCode() );
} ) );
}
}
<?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();
}
<?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;
}
}
<?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;
}
}
<?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;
}
}
\ No newline at end of file
<?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;
}
}
\ No newline at end of file
<?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;
}
}
<?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;
}
}
<?php
class WPML_Media_Attachment_By_URL_Factory {
public function create( $url, $language, \WPML\Media\Classes\WPML_Media_Attachment_By_URL_Query $media_attachment_by_url_query ) {
global $wpdb;
return new WPML_Media_Attachment_By_URL( $wpdb, $url, $language, $media_attachment_by_url_query );
}
}
<?php
namespace WPML\Media\Factories;
class WPML_Media_Attachment_By_URL_Query_Factory {
public function create() {
global $wpdb;
return new \WPML\Media\Classes\WPML_Media_Attachment_By_URL_Query( $wpdb );
}
}
<?php
namespace WPML\Media\Classes;
use WPML\FP\Obj;
class WPML_Media_Attachment_By_URL_Query {
/**
* @var wpdb
*/
private $wpdb;
/**
* @var array
*/
private $id_from_guid_cache = [];
/**
* @var array
*/
private $id_from_meta_cache = [];
/**
* @var boolean Used in tests
*/
private $was_last_fetch_from_cache = false;
/**
* \WPML\Media\Classes\WPML_Media_Attachment_By_URL_Query constructor.
*
* @param \wpdb $wpdb
*/
public function __construct( \wpdb $wpdb ) {
$this->wpdb = $wpdb;
}
/**
* @return boolean
*/
public function getWasLastFetchFromCache() {
return $this->was_last_fetch_from_cache;
}
/**
* Sometimes multiple rows are returned for one language(language_code field)/url(guid field) or language(language_code field)/relativePath(meta_value field) pair.
* We should set only first result in such cases same as with original get_var call, otherwise code with cache will not work in the same way as the original code.
* Example: [[post_id = 1, lang = en, url = otgs.com], [post_id = 2, lang = en, url = otgs.com]] => only first entry should be set to cache, second should be ignored.
*
* @param array $item
* @param string $cache_prop
* @param string $item_index_in_cache
*/
private function setItemToCache( $item, $cache_prop, $item_index_in_cache ) {
if ( array_key_exists( $item_index_in_cache, $this->$cache_prop ) ) {
return;
}
$this->{$cache_prop}[$item_index_in_cache] = $item;
}
/**
* @param array $source_items
*/
private function filterItems( $source_items ) {
return array_values( array_filter( array_unique( $source_items ) ) );
}
/**
* @param string $language
* @param array $urls
*/
public function prefetchAllIdsFromGuids( $language, $urls ) {
$urls = $this->filterItems( $urls );
$urls = array_filter( $urls, function( $url ) use ( $language ) {
$index = md5( $language . $url );
return ! array_key_exists( $index, $this->id_from_guid_cache );
} );
if ( 0 === count( $urls ) ) {
return;
}
$sql = '';
$sql .= "SELECT p.ID AS post_id, p.guid, t.language_code FROM {$this->wpdb->posts} p ";
$sql .= "JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = p.ID ";
$sql .= "WHERE t.element_type='post_attachment' AND t.language_code=%s ";
$sql .= 'AND p.guid IN (' . wpml_prepare_in( $urls ) . ')';
// phpcs:disable WordPress.WP.PreparedSQL.NotPrepared
$results = $this->wpdb->get_results( $this->wpdb->prepare( $sql, $language ), ARRAY_A );
foreach ( $results as $result ) {
$index = md5( $result['language_code'] . $result['guid'] );
$this->setItemToCache( $result, 'id_from_guid_cache', $index );
}
// We should put not found values into the cache too, otherwise they will be still queried later.
$urls_count = count( $urls );
for ( $i = 0; $i < $urls_count; $i++ ) {
$index = md5( $language . $urls[ $i ] );
$this->setItemToCache( null, 'id_from_guid_cache', $index );
}
}
/**
* @param string $language
* @param string $url
*/
public function getIdFromGuid( $language, $url ) {
$this->was_last_fetch_from_cache = false;
$index = md5( $language . $url );
if ( array_key_exists( $index, $this->id_from_guid_cache ) ) {
$this->was_last_fetch_from_cache = true;
return ( $this->id_from_guid_cache[ $index ] ) ? $this->id_from_guid_cache[ $index ]['post_id'] : null;
}
$attachment_id = $this->wpdb->get_var(
// phpcs:disable WordPress.WP.PreparedSQL.NotPrepared
$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
",
$language,
$url
)
);
return $attachment_id;
}
/**
* @param string $language
* @param array $pathes
*/
public function prefetchAllIdsFromMetas( $language, $pathes ) {
$pathes = $this->filterItems( $pathes );
$pathes = array_filter( $pathes, function( $path ) use ( $language ) {
$index = md5( $language . $path );
return ! array_key_exists( $index, $this->id_from_meta_cache );
} );
if ( 0 === count( $pathes ) ) {
return;
}
$sql = '';
$sql .= "SELECT p.post_id, t.language_code, p.meta_value FROM {$this->wpdb->postmeta} p ";
$sql .= "JOIN {$this->wpdb->prefix}icl_translations t ON t.element_id = p.post_id ";
$sql .= "WHERE p.meta_key='_wp_attached_file' AND t.element_type='post_attachment' AND t.language_code=%s ";
$sql .= 'AND p.meta_value IN (' . wpml_prepare_in( $pathes ) . ')';
// phpcs:disable WordPress.WP.PreparedSQL.NotPrepared
$results = $this->wpdb->get_results( $this->wpdb->prepare( $sql, $language ), ARRAY_A );
foreach ( $results as $result ) {
$index = md5( $result['language_code'] . $result['meta_value'] );
$this->setItemToCache( $result, 'id_from_meta_cache', $index );
}
// We should put not found values into the cache too, otherwise they will be still queried later.
$pathes_count = count( $pathes );
for ( $i = 0; $i < $pathes_count; $i++ ) {
$index = md5( $language . $pathes[ $i ] );
$this->setItemToCache( null, 'id_from_meta_cache', $index );
}
}
/**
* @param string $relative_path
* @param string $language
*/
public function getIdFromMeta( $relative_path, $language ) {
$this->was_last_fetch_from_cache = false;
$index = md5( $language . $relative_path );
if ( array_key_exists( $index, $this->id_from_meta_cache ) ) {
$this->was_last_fetch_from_cache = true;
return ( $this->id_from_meta_cache[ $index ] ) ? $this->id_from_meta_cache[ $index ]['post_id'] : null;
}
$attachment_id = $this->wpdb->get_var(
// phpcs:disable WordPress.WP.PreparedSQL.NotPrepared
$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,
$language
)
);
return $attachment_id;
}
}
<?php
class WPML_Media_Attachment_By_URL {
/**
* @var wpdb
*/
private $wpdb;
/**
* @var string
*/
private $url;
/**
* @var string
*/
private $language;
/**
* @var \WPML\Media\Classes\WPML_Media_Attachment_By_URL_Query
*/
private $media_attachment_by_url_query;
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;
/** @var null|boolean */
public $cache_hit_flag = null;
/**
* WPML_Media_Attachment_By_URL constructor.
*
* @param wpdb $wpdb
* @param string $url
* @param string $language
* @param \WPML\Media\Classes\WPML_Media_Attachment_By_URL_Query $media_attachment_by_url_query
*/
public function __construct(
wpdb $wpdb,
$url,
$language,
\WPML\Media\Classes\WPML_Media_Attachment_By_URL_Query $media_attachment_by_url_query
) {
$this->url = $url;
$this->language = $language;
$this->wpdb = $wpdb;
$this->media_attachment_by_url_query = $media_attachment_by_url_query;
}
/**
* @param string $url
*
* @return string
*/
public static function getUrl( $url ) {
$url = preg_replace( self::SIZE_SUFFIX_REGEXP, '.$3', $url );
return $url;
}
/**
* @param string $url
*
* @return string
*/
public static function getUrlNotScaled( $url ) {
$url = preg_replace( self::SIZE_SUFFIX_REGEXP, '.$3', $url );
$url = str_replace( '-scaled', '', $url );
return $url;
}
/**
* @param string $url
*
* @return string
*/
public static function getUrlRelativePath( $url ) {
$uploads_dir = wp_get_upload_dir();
$relative_path = ltrim( preg_replace( '@^' . $uploads_dir['baseurl'] . '@', '', $url ), '/' );
return $relative_path;
}
/**
* @param string $relative_path
*
* @return string
*/
public static function getUrlRelativePathOriginal( $relative_path ) {
return preg_replace( self::SIZE_SUFFIX_REGEXP, '.$3', $relative_path );
}
/**
* @param string $url
*
* @return string
*/
public static function getUrlRelativePathScaled( $url ) {
$relative_path = self::getUrlRelativePath( $url );
$relative_path = str_replace( '-scaled', '', $relative_path );
$relative_path = preg_replace( '/(\.[^.]+)$/', '-scaled$1', $relative_path );
return $relative_path;
}
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->media_attachment_by_url_query->getIdFromGuid( $this->language, $this->url );
if ( ! $attachment_id ) {
$attachment_id = $this->media_attachment_by_url_query->getIdFromGuid( $this->language, self::getUrlNotScaled( $this->url ) );
}
return $attachment_id;
}
private function get_id_from_meta() {
$relative_path = self::getUrlRelativePath( $this->url );
$relative_path_scaled = self::getUrlRelativePathScaled( $this->url );
// Using _wp_attached_file.
$attachment_id = $this->media_attachment_by_url_query->getIdFromMeta( $relative_path, $this->language );
if ( ! $attachment_id ) {
$attachment_id = $this->media_attachment_by_url_query->getIdFromMeta( $relative_path_scaled, $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 = self::getUrlRelativePathOriginal( $relative_path );
$attachment_id_original = $this->media_attachment_by_url_query->getIdFromMeta( $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;
}
}
<?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();
}
}
<?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_action' ), 10 );
}
public function adjust_attachment_query_action( $query ) {
return $this->adjust_attachment_query( $query );
}
/**
* 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;
}
}
<?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 );
}
}
<?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;
}
}
<?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 && isset( $attachment_meta_data['file'] ) ) {
$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 ) );
}
}
<?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;
}
}
<?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();
}
}
<?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 )
);
}
}
<?php
use WPML\UIPage;
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() {
if ( UIPage::isTMDashboard( $_GET ) ) {
$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' );
}
}
<?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;
}
}
<?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 &raquo; %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 = add_query_arg( 'page', \WPML\UIPage::TM_PAGE, 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/documentation/getting-started-guide/media-translation/?utm_source=plugin&utm_medium=gui&utm_campaign=wpmlmedia',
'redirect_url' => $redirect_url,
);
echo $this->template_loader->get_template()->show( $model, 'submitted-basket-notice.twig' );
}
}
<?php
namespace WPML\Media\Classes;
use WPML\FP\Obj;
use WPML\FP\Str;
/**
* Media file block parser
*/
class WPML_Non_Embedded_Pdf_Parser extends WPML_Media_Element_Parser {
/**
* @var string
*/
private static $non_embedded_pdf_expression = '/wp:file.*class="wp-block-file".*(href=".*\.pdf")>.*\/wp:file/s';
public function getMediaElements() {
return $this->getFromTags();
}
public function getMediaSrcFromAttributes( $attrs ) {
return Obj::propOr( '', 'href', $attrs );
}
protected function getFromTags() {
// phpcs:disable WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
return preg_match_all( self::$non_embedded_pdf_expression, $this->blockText, $matches ) ?
$this->getAttachments( $matches ) : [];
}
/**
* Checks if media element is File Block and has pdf.
*
* @return bool
*/
public function validate() {
return Str::includes( '<!-- wp:file', $this->blockText )
|| Str::includes( 'pdf', $this->blockText );
}
}
<?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 );
}
}
<?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 ) ) {
if ( 'application/pdf' === $file['type'] || stripos( $file['type'], 'video' ) !== false ) {
$dirname = dirname( $file['file'] ) . '/';
$ext = pathinfo( $file['file'], PATHINFO_EXTENSION );
$preview_file = $dirname . wp_unique_filename( $dirname, wp_basename( $file['file'], '.' . $ext ) . "-{$ext}.jpg" );
$editor->save( $preview_file, 'image/jpeg' );
$thumb = $this->resize_thumbnail( $editor );
$attachment_metadata = wp_get_attachment_metadata( $attachment_id );
$attachment_size = [
'file' => basename( $preview_file ),
'width' => $thumb['width'],
'height' => $thumb['height'],
'mime-type' => 'image/jpeg',
];
$attachment_metadata['sizes']['thumbnail'] = $attachment_size;
$attachment_metadata['sizes']['full'] = $attachment_size;
wp_update_attachment_metadata( $attachment_id, $attachment_metadata );
} else {
$thumb = $this->resize_thumbnail( $editor );
}
if ( ! is_wp_error( $thumb ) ) {
$uploads_dir = wp_get_upload_dir();
$thumb_url = $uploads_dir['baseurl'] . $uploads_dir['subdir'] . '/' . $thumb['file'];
$thumb_path = $thumb['path'];
}
} else {
$thumb_url = wp_mime_type_icon( $file['type'] );
if ( $thumb_url ) {
$thumb_path = $file['file'];
} 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' );
}
}
/**
* Resize the thumbnail if it is larger than the settings size
*
* @param WP_Image_Editor $editor
* @return array|WP_Error
*/
private function resize_thumbnail( $editor ) {
$size = $editor->get_size();
if ( $size['width'] > get_option( 'thumbnail_size_w' ) || $size['height'] > get_option( 'thumbnail_size_h' ) ) {
$resizing = $editor->resize( get_option( 'thumbnail_size_w' ), get_option( 'thumbnail_size_h' ), true );
if ( is_wp_error( $resizing ) ) {
wp_send_json_error( $resizing->get_error_message() );
}
}
return $editor->save();
}
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' );
}
}
<?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;
}
}
<?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 );
$mediaParsers = ( new \WPML\Media\Factories\WPML_Media_Element_Parser_Factory() )->create( $content_string );
$mediaElements = [];
foreach ( $mediaParsers as $parser ) {
if ( $parser instanceof \WPML\Media\Classes\WPML_Media_Image_Parser
|| $parser instanceof \WPML\Media\Classes\WPML_Media_Classic_Video_Parser
) {
$mediaElements = array_merge( $mediaElements, $parser->getMediaElements() );
}
}
if ( ! empty( $mediaElements ) ) {
$this->img = current( $mediaElements );
$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;
}
}
<?php
namespace WPML\Media\Classes;
use WPML\FP\Str;
/**
* Classic audio parser
*/
class WPML_Media_Classic_Audio_Parser extends WPML_Media_Classic_Element_Parser {
const Media_Element_Expression = '/\[audio ([^]]+)\]/s';
const Media_Extension_Expression = '/\[audio.+?(?=="http)/';
/**
* Extracts the extension of the classic audio media element, defaults to mp3.
*
* @return false|string
*/
protected function extractExtension() {
$matches = $this->getExtensionMatches();
return ! empty( $matches ) ? substr( $matches[0], - 3 ) : 'mp3';
}
protected function getMediaElementRegex() {
return self::Media_Element_Expression;
}
protected function getMediaExtensionExpression() {
return self::Media_Extension_Expression;
}
/**
* Checks if media element is classic audio (audio uploaded in classic editor).
*
* @return bool
*/
public function validate() {
return Str::includes( '[audio', $this->blockText );
}
}
<?php
namespace WPML\Media\Classes;
abstract class WPML_Media_Classic_Element_Parser extends WPML_Media_Element_Parser {
/**
* Gets string out of the video element, this string should be ending with the video extension, then last 3 characters from string are returned.
*
* @return false|string
*/
abstract protected function extractExtension();
/**
* Returns regular expression used to detect matches of the media element in a string.
*
* @return string
*/
abstract protected function getMediaElementRegex();
/**
* Returns regular expression used to detect the extension of media element in a string.
*
* @return string
*/
abstract protected function getMediaExtensionExpression();
public function getMediaElements() {
return preg_match_all( $this->getMediaElementRegex(), $this->blockText, $matches )
? $this->getAttachments( $matches ) : [];
}
/**
* Returns the source of the media element according to its extension in the attrs array (for example : mp3, mp4., ...).
*
* @param array $attrs
*
* @return string
*/
public function getMediaSrcFromAttributes( $attrs ) {
$extension = $this->extractExtension();
return ( $extension && isset( $attrs[ $extension ] ) ) ? $attrs[ $extension ] : '';
}
/**
* Applies regular expression match to get the media element extension and returns the matches.
*
* @return mixed
*/
protected function getExtensionMatches() {
preg_match( $this->getMediaExtensionExpression(), $this->blockText, $matches );
return $matches;
}
}
<?php
namespace WPML\Media\Classes;
use WPML\FP\Str;
/**
* Classic video parser
*/
class WPML_Media_Classic_Video_Parser extends WPML_Media_Classic_Element_Parser {
const Media_Element_Expression = '/\[video ([^]]+)\]/s';
const Media_Extension_Expression = '/\[video.+?(?=="http)/';
/**
* Extracts the extension of the classic video media element, defaults to mp4.
*
* @return false|string
*/
protected function extractExtension() {
$matches = $this->getExtensionMatches();
return ! empty( $matches ) ? substr( $matches[0], - 3 ) : 'mp4';
}
protected function getMediaElementRegex() {
return self::Media_Element_Expression;
}
protected function getMediaExtensionExpression() {
return self::Media_Extension_Expression;
}
/**
* Checks if media element is classic video (video uploaded in classic editor).
*
* @return bool
*/
public function validate() {
return Str::includes( '[video', $this->blockText );
}
}
<?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(),
new \WPML\Media\Factories\WPML_Media_Attachment_By_URL_Query_Factory()
);
$image_updater = new WPML_Media_Translated_Images_Update( new \WPML\Media\Factories\WPML_Media_Element_Parser_Factory(), $image_translator, new WPML_Media_Sizes() );
return new WPML_Media_Custom_Field_Images_Translation( $image_updater, $sitepress, $iclTranslationManagement );
}
return null;
}
}
<?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;
}
}
<?php
namespace WPML\Media\Classes;
use WPML\LIB\WP\Attachment;
abstract class WPML_Media_Element_Parser {
private static $getAttachmentsRegex = '/(\S+)\\s*=\\s*["\']?((?:.(?!["\']?\s+(?:\S+)=|[>"\']))+.)["\']?/';
protected $blockText;
public function __construct( $blockText ) {
$this->blockText = $blockText;
}
abstract public function getMediaElements();
abstract public function getMediaSrcFromAttributes( $attrs );
abstract public function validate();
protected function getAttachments( $matches ) {
$attachments = [];
foreach ( $matches[1] as $i => $match ) {
if ( preg_match_all( self::$getAttachmentsRegex, $match, $attribute_matches ) ) {
$attributes = [];
foreach ( $attribute_matches[1] as $k => $key ) {
$attributes[ $key ] = $attribute_matches[2][ $k ];
}
$attachments[ $i ]['attributes'] = $attributes;
}
}
return $attachments;
}
}
<?php
namespace WPML\Media\Classes;
use WPML\FP\Obj;
use WPML\FP\Str;
/**
* Media file block parser
*/
class WPML_Media_File_Parser extends WPML_Media_Element_Parser {
private static $objectElementExpression = '/<object ([^>]+)>/s';
public function getMediaElements() {
return $this->getFromTags();
}
public function getMediaSrcFromAttributes( $attrs ) {
return Obj::propOr( '', 'data', $attrs );
}
protected function getFromTags() {
return preg_match_all( self::$objectElementExpression, $this->blockText, $matches ) ?
$this->getAttachments( $matches ) : [];
}
/**
* Checks if media element is File Block and 'parse_blocks' function exists.
*
* @return bool
*/
public function validate() {
return Str::includes( '<!-- wp:file', $this->blockText ) && function_exists( 'parse_blocks' );
}
}
<?php
namespace WPML\Media\Classes;
use WPML\FP\Obj;
use WPML\FP\Str;
/**
* Media in href parser (basically for files included in classic editor)
*/
class WPML_Media_Href_Parser extends WPML_Media_Element_Parser {
private static $allAnchorsRegex = '/<a.*?>.*?<\/a>/s'; // gets any anchor tag
private static $hrefElementRegex = '/<a ([^>]+)/s'; // to get matches for anchors after filtering them (filtering means that we get only anchors without nested tags)
public function getMediaElements() {
return $this->getFromTags();
}
public function getMediaSrcFromAttributes( $attrs ) {
return Obj::propOr('', 'href', $attrs);
}
protected function getFromTags() {
$anchorsWithoutTags = $this->getAnchorsWithoutNestedTags();
return preg_match_all( self::$hrefElementRegex, implode( '', $anchorsWithoutTags ), $matches ) ? $this->getAttachments( $matches ) : [];
}
/**
* Checks if media element is only anchor with href (basically for files uploaded in classic editor).
*
* @return bool
*/
public function validate() {
return Str::includes( '<a href=', $this->blockText ) && ! empty( $this->getAnchorsWithoutNestedTags() );
}
/**
* Gets anchor tags from WP editor that contain neither nested tags not 'wp-block' string in it.
*
* @return array
*/
public function getAnchorsWithoutNestedTags() {
$anchorHasNestedTags = function ( $anchorTag ) {
$pattern = '/<a .*?>.*?<.*?<\/a>/s';
preg_match( $pattern, $anchorTag, $matches );
return ! empty( $matches );
};
$isBlockAnchor = Str::includes( 'wp-block' );
preg_match_all( self::$allAnchorsRegex, $this->blockText, $allAnchorTags );
return wpml_collect( current( $allAnchorTags ) )
->reject( $anchorHasNestedTags )
->reject( $isBlockAnchor )
->toArray();
}
}
<?php
namespace WPML\Media\Classes;
use WPML\FP\Obj;
use WPML\FP\Str;
/**
* Image block parser
*/
class WPML_Media_Image_Parser extends WPML_Media_Element_Parser {
protected static $getFromCssBackgroundImagesRegex = '/<\w+[^>]+style\s?=\s?"[^"]*?background-image:url\(\s?([^\s\)]+)\s?\)/';
protected static $mediaElementsRegex = [
'/<img ([^>]+)>/s',
'/<video ([^>]+)>/s',
'/<audio ([^>]+)>/s',
];
public function getMediaElements() {
$mediaElements = $this->getFromTags();
$blocks = parse_blocks( $this->blockText );
return $blocks ? array_merge( $mediaElements, $this->getFromCssBackgroundImagesInBlocks( $blocks ) )
: array_merge( $mediaElements, $this->getFromCssBackgroundImages( $this->blockText ) );
}
public function getMediaSrcFromAttributes( $attrs ) {
return Obj::propOr( '', 'src', $attrs );
}
protected function getFromTags() {
$mediaElements = wpml_collect( [] );
foreach ( self::$mediaElementsRegex as $mediaElementExpression ) {
if ( preg_match_all( $mediaElementExpression, $this->blockText, $matches ) ) {
$mediaElements = $mediaElements->merge( $this->getAttachments( $matches ) );
}
}
return $mediaElements->toArray();
}
/**
* Checks if media element is Image Block and 'parse_blocks' function exists.
*
* @return bool
*/
public function validate() {
return (
( function_exists( 'parse_blocks' ) &&
( Str::includes( '<!-- wp:image', $this->blockText )
|| Str::includes( '<!-- wp:video', $this->blockText )
|| Str::includes( '<!-- wp:audio', $this->blockText )
)
)
||
Str::includes( '<img', $this->blockText )
||
Str::includes( '<video', $this->blockText )
||
Str::includes( '<audio', $this->blockText )
);
}
/**
* `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
*/
protected function sanitizeBlock( $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;
}
/**
* @param string $text
*
* @return array
*/
protected function getFromCssBackgroundImages( $text ) {
$images = [];
if ( preg_match_all( self::$getFromCssBackgroundImagesRegex, $text, $matches ) ) {
foreach ( $matches[1] as $src ) {
$images[] = [
'attributes' => [ 'src' => $src ],
];
}
}
return $images;
}
/**
* @param array $blocks
*
* @return array
*/
protected function getFromCssBackgroundImagesInBlocks( $blocks ) {
$images = [];
foreach ( $blocks as $block ) {
$block = $this->sanitizeBlock( $block );
if ( ! empty( $block->innerBlocks ) ) {
$inner_images = $this->getFromCssBackgroundImagesInBlocks( $block->innerBlocks );
$images = array_merge( $images, $inner_images );
continue;
}
if ( ! isset( $block->innerHTML, $block->attrs->id ) ) {
continue;
}
$background_images = $this->getFromCssBackgroundImages( $block->innerHTML );
$image = reset( $background_images );
if ( $image ) {
$images[] = $image;
}
}
return $images;
}
}
<?php
use WPML\Element\API\PostTranslations;
/**
* 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;
/**
* @var \WPML\Media\Classes\WPML_Media_Attachment_By_URL_Query
*/
private $media_attachment_by_url_query;
/**
* WPML_Media_Image_Translate constructor.
*
* @param SitePress $sitepress
* @param WPML_Media_Attachment_By_URL_Factory $attachment_by_url_factory
* @param \WPML\Media\Factories\WPML_Media_Attachment_By_URL_Query_Factory $media_attachment_by_url_query_factory
*/
public function __construct(
SitePress $sitepress,
WPML_Media_Attachment_By_URL_Factory $attachment_by_url_factory,
\WPML\Media\Factories\WPML_Media_Attachment_By_URL_Query_Factory $media_attachment_by_url_query_factory
) {
$this->sitepress = $sitepress;
$this->attachment_by_url_factory = $attachment_by_url_factory;
$this->media_attachment_by_url_query = $media_attachment_by_url_query_factory->create();
}
/**
* @param string $source_language
* @param array $items_to_translate
*/
public function prefetchDataForFutureGetTranslatedImageCalls( $source_language, $items_to_translate ) {
$this->media_attachment_by_url_query->prefetchAllIdsFromGuids(
$source_language,
array_merge(
array_map(
function( $item ) {
return WPML_Media_Attachment_By_URL::getUrl( $item['url'] );
},
$items_to_translate
),
array_map(
function( $item ) {
return WPML_Media_Attachment_By_URL::getUrlNotScaled( $item['url'] );
},
$items_to_translate
)
)
);
$this->media_attachment_by_url_query->prefetchAllIdsFromMetas(
$source_language,
array_merge(
array_map(
function( $item ) {
return WPML_Media_Attachment_By_URL::getUrlRelativePath( $item['url'] );
},
$items_to_translate
),
array_map(
function( $item ) {
return WPML_Media_Attachment_By_URL::getUrlRelativePathOriginal(
WPML_Media_Attachment_By_URL::getUrlRelativePath( $item['url'] )
);
},
$items_to_translate
),
array_map(
function( $item ) {
return WPML_Media_Attachment_By_URL::getUrlRelativePathScaled( $item['url'] );
},
$items_to_translate
)
)
);
}
/**
* @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, $this->media_attachment_by_url_query );
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 int $attachment_id
* @param string $size
* @param string $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 );
$image_url_parts = array( $uploads_dir['baseurl'] );
if ( is_array( $meta_data ) && array_key_exists( 'file', $meta_data ) ) {
$file_subdirectory = $meta_data['file'];
$file_subdirectory_parts = explode( '/', $file_subdirectory );
$filename = array_pop( $file_subdirectory_parts );
$image_url_parts[] = implode( '/', $file_subdirectory_parts );
if ( array_key_exists( $size, $meta_data['sizes'] ) ) {
$image_url_parts[] = $meta_data['sizes'][ $size ]['file'];
} else {
$image_url_parts[] = $filename;
}
$image_url = implode( '/', $image_url_parts );
}
return $image_url;
}
}
<?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(),
new \WPML\Media\Factories\WPML_Media_Attachment_By_URL_Query_Factory()
);
$image_updater = new WPML_Media_Translated_Images_Update( new \WPML\Media\Factories\WPML_Media_Element_Parser_Factory(), $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;
}
}
<?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\Factories\WPML_Media_Element_Parser_Factory(),
new WPML_Media_Attachment_By_URL_Factory(),
$sitepress,
new WPML_Custom_Field_Setting_Factory( $iclTranslationManagement ),
new \WPML\Media\Factories\WPML_Media_Attachment_By_URL_Query_Factory()
);
}
}
<?php
use WPML\FP\Fns;
use WPML\LIB\WP\Post;
class WPML_Media_Post_With_Media_Files {
/**
* @var int
*/
private $post_id;
/**
* @var WPML_Media_Img_Parse
*/
private $media_parser_factory;
/**
* @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;
/**
* @var \WPML\Media\Classes\WPML_Media_Attachment_By_URL_Query
*/
private $mediaAttachmentByURLQuery;
/**
* WPML_Media_Post_With_Media_Files constructor.
*
* @param $post_id
* @param \WPML\Media\Factories\WPML_Media_Element_Parser_Factory $media_parser_factory
* @param WPML_Media_Attachment_By_URL_Factory $attachment_by_url_factory
* @param SitePress $sitepress
* @param WPML_Custom_Field_Setting_Factory $cf_settings_factory
* @param \WPML\Media\Factories\WPML_Media_Attachment_By_URL_Query_Factory $mediaAttachmentByURLQueryFactory
*/
public function __construct(
$post_id,
\WPML\Media\Factories\WPML_Media_Element_Parser_Factory $media_parser_factory,
WPML_Media_Attachment_By_URL_Factory $attachment_by_url_factory,
SitePress $sitepress,
WPML_Custom_Field_Setting_Factory $cf_settings_factory,
\WPML\Media\Factories\WPML_Media_Attachment_By_URL_Query_Factory $mediaAttachmentByURLQueryFactory
) {
$this->post_id = $post_id;
$this->media_parser_factory = $media_parser_factory;
$this->attachment_by_url_factory = $attachment_by_url_factory;
$this->sitepress = $sitepress;
$this->cf_settings_factory = $cf_settings_factory;
$this->mediaAttachmentByURLQuery = $mediaAttachmentByURLQueryFactory->create();
}
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 );
$media_parsers = $this->media_parser_factory->create( $content_to_parse );
$this->prefetchDataForFutureAttachmentByUrlGetIdCalls( $media_parsers );
foreach ( $media_parsers as $media_parser ) {
$media_ids = $this->unique_array_merge( $media_ids, $this->_get_ids_from_media_array( $media_parser, $media_parser->getMediaElements() ) );
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();
$media_parsers = $this->media_parser_factory->create( $custom_fields_content );
foreach ( $media_parsers as $media_parser ) {
$media_ids = $this->unique_array_merge( $media_ids, $this->_get_ids_from_media_array( $media_parser, $media_parser->getMediaElements() ) );
}
}
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 ) ) );
$media_ids = $this->unique_array_merge( $media_ids, $gallery_media_ids );
}
if ( $attached_media_ids = $this->get_attached_media_ids( $this->post_id ) ) {
$media_ids = $this->unique_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 $first_array
* @param array $second_array
*
* @return array
*/
private function unique_array_merge( $first_array, $second_array) {
return array_unique( array_values( array_merge( $first_array, $second_array ) ) );
}
/**
* @param \WPML\Media\Classes\WPML_Media_Element_Parser $media_parser
* @param array $media_array
*
* @return array
*/
private function _get_ids_from_media_array( $media_parser, $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_parser->getMediaSrcFromAttributes( $media['attributes'] ),
wpml_get_current_language(),
$this->mediaAttachmentByURLQuery
);
if ( $attachment_by_url->get_id() ) {
$media_ids[] = $attachment_by_url->get_id();
}
}
}
return $media_ids;
}
/**
* @param WPML_Media_Element_Parser[] $mediaParsers
*/
private function prefetchDataForFutureAttachmentByUrlGetIdCalls( $mediaParsers ) {
$urls = [];
foreach ( $mediaParsers as $mediaParser ) {
foreach( $mediaParser->getMediaElements() as $media ) {
if ( isset( $media['attachment_id'] ) ) {
continue;
}
$urls[] = $mediaParser->getMediaSrcFromAttributes( $media['attributes'] );
}
}
$this->mediaAttachmentByURLQuery->prefetchAllIdsFromGuids(
wpml_get_current_language(),
array_merge(
array_map(
function( $url ) {
return WPML_Media_Attachment_By_URL::getUrl( $url );
},
$urls
),
array_map(
function( $url ) {
return WPML_Media_Attachment_By_URL::getUrlNotScaled( $url );
},
$urls
)
)
);
$this->mediaAttachmentByURLQuery->prefetchAllIdsFromMetas(
wpml_get_current_language(),
array_merge(
array_map(
function( $url ) {
return WPML_Media_Attachment_By_URL::getUrlRelativePath( $url );
},
$urls
),
array_map(
function( $url ) {
return WPML_Media_Attachment_By_URL::getUrlRelativePathOriginal(
WPML_Media_Attachment_By_URL::getUrlRelativePath( $url )
);
},
$urls
),
array_map(
function( $url ) {
return WPML_Media_Attachment_By_URL::getUrlRelativePathScaled( $url );
},
$urls
)
)
);
}
/**
* @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 );
$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 = 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 );
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(
array(
'post_parent' => $post_id,
'post_status' => 'inherit',
'post_type' => 'attachment',
)
);
return array_keys( $attachments );
}
}
<?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 ) );
}
}
<?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()
);
}
}
\ No newline at end of file
<?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, [ $this, 'clear_flags_action' ] );
add_action( 'wp_ajax_' . WPML_Media_Posts_Media_Flag_Notice::PROCESS_ACTION, [ $this, 'process_batch_action' ] );
add_action( 'save_post', array( $this, 'update_post_flag' ) );
}
public function clear_flags_action() {
if ( $this->verify_nonce( WPML_Media_Posts_Media_Flag_Notice::PREPARE_ACTION ) ) {
$this->clear_flags();
wp_send_json_success( array( 'status' => __( 'Running setup...', 'wpml-media' ) ) );
} else {
wp_send_json_error( array( 'status' => 'Invalid nonce' ) );
}
}
public function clear_flags() {
if ( ! WPML_Media::has_setup_started() ) {
$this->wpdb->delete( $this->wpdb->postmeta, array( 'meta_key' => self::HAS_MEDIA_POST_FLAG ), array( '%s' ) );
}
}
public function process_batch_action() {
if ( $this->verify_nonce( WPML_Media_Posts_Media_Flag_Notice::PROCESS_ACTION ) ) {
$offset = isset( $_POST['offset'] ) ? (int) $_POST['offset'] : 0;
list( $status, $offset, $continue ) = $this->process_batch( $offset );
wp_send_json_success( array(
'status' => $status,
'offset' => $offset,
'continue' => $continue
) );
} else {
wp_send_json_error( array( 'status' => 'Invalid nonce' ) );
}
}
public function process_batch( $offset ) {
$this->mark_started();
$continue = false;
$status = __( 'Setup complete!', 'wpml-media' );
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();
}
return [ $status, $offset + self::BATCH_SIZE, $continue ];
}
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();
}
}
<?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 );
if ( isset( $attachment_meta_data['sizes'] ) ) {
foreach ( $attachment_meta_data['sizes'] as $key => $size_array ) {
if ( $thumb_file_name === $size_array['file'] ) {
$size = $key;
break;
}
}
}
return $size;
}
}
<?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(),
new \WPML\Media\Factories\WPML_Media_Attachment_By_URL_Query_Factory()
);
$image_updater = new WPML_Media_Translated_Images_Update( new \WPML\Media\Factories\WPML_Media_Element_Parser_Factory(), $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;
}
}
<?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;
}
}
<?php
class WPML_Media_Translation_Status {
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_';
}
<?php
namespace WPML\Media\Factories;
use WPML\Media\Classes\WPML_Media_Classic_Audio_Parser;
use WPML\Media\Classes\WPML_Media_Classic_Video_Parser;
use WPML\Media\Classes\WPML_Media_File_Parser;
use WPML\Media\Classes\WPML_Media_Href_Parser;
use WPML\Media\Classes\WPML_Media_Image_Parser;
use WPML\Media\Classes\WPML_Non_Embedded_Pdf_Parser;
class WPML_Media_Element_Parser_Factory {
/**
* @var array[]
*/
private $availableMediaParsers = [
'img-block' => [ 'class-name' => WPML_Media_Image_Parser::class ],
'audio-block' => [ 'class-name' => WPML_Media_Image_Parser::class ],
'video-block' => [ 'class-name' => WPML_Media_Image_Parser::class ],
'file-block' => [ 'class-name' => WPML_Media_File_Parser::class ],
'non-embedded-pdf' => [ 'class-name' => WPML_Non_Embedded_Pdf_Parser::class ],
'classic-audio' => [ 'class-name' => WPML_Media_Classic_Audio_Parser::class ],
'classic-Video' => [ 'class-name' => WPML_Media_Classic_Video_Parser::class ],
'href' => [ 'class-name' => WPML_Media_Href_Parser::class ],
];
/**
* Returns array of media parsers according to post content.
*
* @param string $post_content
*
* @return array
*/
public function create( $post_content ) {
$parsers = [];
foreach ( $this->availableMediaParsers as $mediaParser ) {
$parserInstance = new $mediaParser['class-name']( $post_content );
if ( $parserInstance->validate() ) {
$parsers [ $mediaParser['class-name'] ] = $parserInstance;
}
}
return $parsers;
}
}
<?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()
);
}
}
}
\ No newline at end of file
<?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;
}
}
\ No newline at end of file
<?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()
);
}
}
\ No newline at end of file
<?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 );
}
}
}
\ No newline at end of file
<?php
class WPML_Media_Usage_Factory {
public function create( $attachment_id ) {
return new WPML_Media_Usage( $attachment_id );
}
}
<?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 );
}
}
<?php
class WPML_Media_Help_Tab_Factory implements IWPML_Backend_Action_Loader {
public function create() {
return new WPML_Media_Help_Tab();
}
}
<?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 &raquo; Media Translation', 'wpml-media' );
$wpml_translation_dashboard = esc_html__( 'WPML &raquo; 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/documentation/getting-started-guide/media-translation/?utm_source=plugin&utm_medium=gui&utm_campaign=wpmlmedia">' . 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 );
}
}
<?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 );
}
}
<?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();
}
}
<?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;
}
}
<?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
}
}
<?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'];
}
}
<?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;
}
}
<?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();
}
}
<?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();
}
}
<?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();
}
}
<?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' );
}
}
<?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() );
}
}
<?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
)
);
}
}
<?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;
}
}
<?php
define( 'WPML_MEDIA_FOLDER', basename( WPML_MEDIA_PATH ) );
define( 'WPML_MEDIA_URL', plugins_url( '', dirname( __FILE__ ) ) );
<?php
class WPML_Media_Dependencies {
function check() {
$all_ok = true;
// Check if WPML is active. If not display warning message and don't load WPML-media
if ( ! defined( 'ICL_SITEPRESS_VERSION' ) || ICL_PLUGIN_INACTIVE ) {
add_action( 'admin_notices', array( $this, '_no_wpml_warning' ) );
$all_ok = false;
}
if ( ! WPML_Core_Version_Check::is_ok( WPML_MEDIA_PATH . '/wpml-dependencies.json' ) ) {
$all_ok = false;
}
if ( ! $all_ok ) {
return false;
}
return true;
}
function _no_wpml_warning() { ?>
<div class="message error wpml-media-inactive"><p>
<?php
printf(
__( 'WPML Media is enabled but not effective. It requires <a href="%s">WPML</a> in order to work.', 'wpml-media' ),
'https://wpml.org/'
);
?>
</p></div>
<?php
}
}
<?php
class WPML_Media_Upgrade {
private static $versions = array(
'2.0',
'2.0.1',
);
static function run() {
global $wpdb;
// Workaround, as for some reasons, get_option() doesn't work only in this case
$wpml_media_settings_prepared = $wpdb->prepare( "select option_value from {$wpdb->prefix}options where option_name = %s", '_wpml_media' );
$wpml_media_settings = $wpdb->get_col( $wpml_media_settings_prepared );
$needs_version_update = true;
// Do not run upgrades if this is a new install (i.e.: plugin has no settings)
if ( $wpml_media_settings || get_option( '_wpml_media_starting_help' ) ) {
$current_version = WPML_Media::get_setting( 'version', null );
if ( $current_version ) {
$needs_version_update = version_compare( $current_version, WPML_MEDIA_VERSION, '<' );
self::run_upgrades_before_2_3_0( $current_version );
} elseif ( self::is_media_version_older_than_2_0() ) {
$needs_version_update = true;
self::run_upgrades_before_2_3_0( '1.6' );
}
}
if ( $needs_version_update ) {
WPML_Media::update_setting( 'version', WPML_MEDIA_VERSION );
}
// Blocking database migration
self::upgrade_2_3_0();
}
/** @param int $current_version */
private static function run_upgrades_before_2_3_0( $current_version ) {
if ( version_compare( $current_version, '2.3.0', '<' ) ) {
foreach ( self::$versions as $version ) {
if ( version_compare( $version, WPML_MEDIA_VERSION, '<=' ) && version_compare( $version, $current_version, '>' ) ) {
$upgrade_method = 'upgrade_' . str_replace( '.', '_', $version );
if ( method_exists( __CLASS__, $upgrade_method ) ) {
self::$upgrade_method();
}
}
}
update_option( 'wpml_media_upgraded_from_prior_2_3_0', 1 );
}
}
/** @return bool */
private static function is_media_version_older_than_2_0() {
global $wpdb;
return (bool) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->postmeta} WHERE meta_key = 'wpml_media_duplicate_of'" );
}
private static function upgrade_2_0() {
global $wpdb;
global $sitepress;
// Check if the old options are set and in case move them to the new plugin settings, then delete the old ones
$old_starting_help = get_option( '_wpml_media_starting_help' );
if ( $old_starting_help ) {
WPML_Media::update_setting( 'starting_help', $old_starting_help );
delete_option( '_wpml_media_starting_help' );
}
// Create translated media
$target_language = $sitepress->get_default_language();
$attachment_ids_prepared = $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s", 'attachment' );
$attachment_ids = $wpdb->get_col( $attachment_ids_prepared );
// Let's first set the language of all images in default languages
foreach ( $attachment_ids as $attachment_id ) {
$wpml_media_lang = get_post_meta( $attachment_id, 'wpml_media_lang', true );
$wpml_media_duplicate_of = get_post_meta( $attachment_id, 'wpml_media_duplicate_of', true );
if ( ! $wpml_media_duplicate_of && ( ! $wpml_media_lang || $wpml_media_lang == $target_language ) ) {
$trid = $sitepress->get_element_trid( $attachment_id, 'post_attachment' );
if ( $trid ) {
// Since trid exists, get the language from there
$target_language = $sitepress->get_language_for_element( $attachment_id, 'post_attachment' );
}
$sitepress->set_element_language_details( $attachment_id, 'post_attachment', $trid, $target_language );
}
}
// Then all the translations
foreach ( $attachment_ids as $attachment_id ) {
$wpml_media_lang = get_post_meta( $attachment_id, 'wpml_media_lang', true );
$wpml_media_duplicate_of = get_post_meta( $attachment_id, 'wpml_media_duplicate_of', true );
if ( $wpml_media_duplicate_of ) {
$source_language = null;
$trid = $sitepress->get_element_trid( $wpml_media_duplicate_of, 'post_attachment' );
$source_language = false;
if ( $trid ) {
// Get the source language of the attachment, just in case is from a language different than the default
$source_language = $sitepress->get_language_for_element( $wpml_media_duplicate_of, 'post_attachment' );
// Fix bug on 1.6, where duplicated images are set to the default language
if ( $wpml_media_lang == $source_language ) {
$wpml_media_lang = false;
$attachment = get_post( $attachment_id );
if ( $attachment->post_parent ) {
$parent_post = get_post( $attachment->post_parent );
$post_parent_language = $sitepress->get_language_for_element( $parent_post->ID, 'post_' . $parent_post->post_type );
if ( $post_parent_language ) {
$wpml_media_lang = $post_parent_language;
}
}
if ( ! $wpml_media_lang ) {
// Trash orphan image
wp_delete_attachment( $attachment_id );
}
}
}
if ( $wpml_media_lang ) {
$sitepress->set_element_language_details( $attachment_id, 'post_attachment', $trid, $wpml_media_lang, $target_language, $source_language );
}
}
}
// Remove old media translation meta
// Remove both meta just in case
$attachment_ids = $wpdb->get_col( $attachment_ids_prepared );
foreach ( $attachment_ids as $attachment_id ) {
delete_post_meta( $attachment_id, 'wpml_media_duplicate_of' );
delete_post_meta( $attachment_id, 'wpml_media_lang' );
}
}
private static function upgrade_2_0_1() {
global $wpdb;
global $sitepress;
// Fixes attachments metadata among translations
$sql = "
SELECT t.element_id, t.trid, t.language_code
FROM {$wpdb->prefix}icl_translations t
LEFT JOIN {$wpdb->postmeta} pm
ON t.element_id = pm.post_id AND pm.meta_key=%s
WHERE t.element_type = %s AND pm.meta_id IS NULL AND element_id IS NOT NULL
";
$sql_prepared = $wpdb->prepare( $sql, array( '_wp_attachment_metadata', 'post_attachment' ) );
$original_attachments = $wpdb->get_results( $sql_prepared );
foreach ( $original_attachments as $original_attachment ) {
$attachment_metadata = get_post_meta( $original_attachment->element_id, '_wp_attachment_metadata', true );
if ( ! $attachment_metadata ) {
$attachment_translations = $sitepress->get_element_translations( $original_attachment->trid, 'post_attachment', true, true );
// Get _wp_attachment_metadata first translation available
foreach ( $attachment_translations as $attachment_translation ) {
if ( $attachment_translation->language_code != $original_attachment->language_code ) {
$attachment_metadata = get_post_meta( $attachment_translation->element_id, '_wp_attachment_metadata', true );
// _wp_attachment_metadata found: save it in the original and go to the next attachment
if ( $attachment_metadata ) {
update_post_meta( $original_attachment->element_id, '_wp_attachment_metadata', $attachment_metadata );
break;
}
}
}
}
}
return true;
}
private static function upgrade_2_3_0() {
global $wpdb, $sitepress;
if ( ! WPML_Media_2_3_0_Migration::migration_complete() ) {
$migration = new WPML_Media_2_3_0_Migration( $wpdb, $sitepress );
if ( $migration->is_required() ) {
$migration->maybe_show_admin_notice();
$migration->add_hooks();
}
}
}
}