first commit
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Media;
|
||||
|
||||
use WPML\Element\API\PostTranslations;
|
||||
use WPML\FP\Cast;
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Maybe;
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Relation;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\pipe;
|
||||
use function WPML\FP\spreadArgs;
|
||||
|
||||
class FrontendHooks implements \IWPML_Frontend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onFilter( 'wp_get_attachment_caption', 10, 2 )
|
||||
->then( spreadArgs( Fns::withoutRecursion( Fns::identity(), [ __CLASS__, 'translateCaption' ] ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $caption
|
||||
* @param int $postId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function translateCaption( $caption, $postId ) {
|
||||
// $convertId :: int -> string|int|null
|
||||
$convertId = pipe( PostTranslations::getInCurrentLanguage(), Obj::prop( 'element_id' ) );
|
||||
|
||||
return Maybe::of( $postId )
|
||||
->map( $convertId )
|
||||
->map( Cast::toInt() )
|
||||
->reject( Relation::equals( $postId ) )
|
||||
->map( 'wp_get_attachment_caption' )
|
||||
->getOrElse( $caption );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Media;
|
||||
|
||||
use WPML\Core\WP\App\Resources;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use WPML\Media\Option;
|
||||
use WPML\Media\Setup\Endpoint\PerformSetup;
|
||||
use WPML\Media\Setup\Endpoint\PrepareSetup;
|
||||
use WPML\Media\Translate\Endpoint\DuplicateFeaturedImages;
|
||||
use WPML\Media\Translate\Endpoint\FinishMediaTranslation;
|
||||
use WPML\Media\Translate\Endpoint\PrepareForTranslation;
|
||||
use WPML\Media\Translate\Endpoint\TranslateExistingMedia;
|
||||
|
||||
class Loader implements \IWPML_Backend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
if ( ! Option::isSetupFinished() ) {
|
||||
Hooks::onAction( 'wp_loaded' )
|
||||
->then( [ self::class, 'getData' ] )
|
||||
->then( Resources::enqueueApp( 'media-setup' ) );
|
||||
}
|
||||
}
|
||||
|
||||
public static function getData() {
|
||||
return [
|
||||
'name' => 'media_setup',
|
||||
'data' => [
|
||||
'endpoints' => [
|
||||
'prepareForTranslation' => PrepareForTranslation::class,
|
||||
'translateExistingMedia' => TranslateExistingMedia::class,
|
||||
'duplicateFeaturedImages' => DuplicateFeaturedImages::class,
|
||||
'finishMediaTranslation' => FinishMediaTranslation::class,
|
||||
'prepareForSetup' => PrepareSetup::class,
|
||||
'performSetup' => PerformSetup::class,
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* WPML_Attachment_Action_Factory
|
||||
*
|
||||
* @package WPML
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WPML_Attachment_Action_Factory
|
||||
*/
|
||||
class WPML_Attachment_Action_Factory implements
|
||||
IWPML_Backend_Action_Loader, IWPML_Frontend_Action_Loader, IWPML_AJAX_Action_Loader, IWPML_Deferred_Action_Loader {
|
||||
|
||||
/**
|
||||
* Get load action.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_load_action() {
|
||||
return 'wpml_loaded';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create attachment action.
|
||||
*
|
||||
* @return WPML_Attachment_Action
|
||||
*/
|
||||
public function create() {
|
||||
global $sitepress, $wpdb;
|
||||
|
||||
return new WPML_Attachment_Action( $sitepress, $wpdb );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
use WPML\FP\Str;
|
||||
|
||||
/**
|
||||
* WPML_Attachment_Action class file.
|
||||
*
|
||||
* @package WPML
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WPML_Attachment_Action
|
||||
*/
|
||||
class WPML_Attachment_Action implements IWPML_Action {
|
||||
|
||||
/**
|
||||
* SitePress instance.
|
||||
*
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* Wpdb instance.
|
||||
*
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
|
||||
/**
|
||||
* WPML_Attachment_Action constructor.
|
||||
*
|
||||
* @param SitePress $sitepress SitePress instance.
|
||||
* @param wpdb $wpdb wpdb instance.
|
||||
*/
|
||||
public function __construct( SitePress $sitepress, wpdb $wpdb ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add hooks.
|
||||
*/
|
||||
public function add_hooks() {
|
||||
if ( $this->is_admin_or_xmlrpc() && ! $this->is_uploading_plugin_or_theme() ) {
|
||||
|
||||
$active_languages = $this->sitepress->get_active_languages();
|
||||
|
||||
if ( count( $active_languages ) > 1 ) {
|
||||
add_filter( 'views_upload', array( $this, 'views_upload_actions' ) );
|
||||
}
|
||||
}
|
||||
|
||||
add_filter( 'attachment_link', array( $this->sitepress, 'convert_url' ), 10, 1 );
|
||||
add_filter( 'wp_delete_file', array( $this, 'delete_file_filter' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are in site console or xmlrpc request is active.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_admin_or_xmlrpc() {
|
||||
$is_admin = is_admin();
|
||||
$is_xmlrpc = ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST );
|
||||
|
||||
return $is_admin || $is_xmlrpc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are uploading plugin or theme.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_uploading_plugin_or_theme() {
|
||||
global $action;
|
||||
|
||||
return ( isset( $action ) && ( 'upload-plugin' === $action || 'upload-theme' === $action ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter views.
|
||||
*
|
||||
* @param array $views Views.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function views_upload_actions( $views ) {
|
||||
global $pagenow;
|
||||
|
||||
if ( 'upload.php' === $pagenow ) {
|
||||
// Get current language.
|
||||
$lang = $this->sitepress->get_current_language();
|
||||
|
||||
foreach ( $views as $key => $view ) {
|
||||
// Extract the base URL and query parameters.
|
||||
$href_count = preg_match( '/(href=["\'])([\s\S]+?)\?([\s\S]+?)(["\'])/', $view, $href_matches );
|
||||
if ( $href_count && isset( $href_args ) ) {
|
||||
$href_base = $href_matches[2];
|
||||
wp_parse_str( $href_matches[3], $href_args );
|
||||
} else {
|
||||
$href_base = 'upload.php';
|
||||
$href_args = array();
|
||||
}
|
||||
|
||||
if ( 'all' !== $lang ) {
|
||||
$sql = $this->wpdb->prepare(
|
||||
"
|
||||
SELECT COUNT(p.id)
|
||||
FROM {$this->wpdb->posts} AS p
|
||||
INNER JOIN {$this->wpdb->prefix}icl_translations AS t
|
||||
ON p.id = t.element_id
|
||||
WHERE p.post_type = 'attachment'
|
||||
AND t.element_type='post_attachment'
|
||||
AND t.language_code = %s ",
|
||||
$lang
|
||||
);
|
||||
|
||||
switch ( $key ) {
|
||||
case 'all':
|
||||
$and = " AND p.post_status != 'trash' ";
|
||||
break;
|
||||
case 'detached':
|
||||
$and = " AND p.post_status != 'trash' AND p.post_parent = 0 ";
|
||||
break;
|
||||
case 'trash':
|
||||
$and = " AND p.post_status = 'trash' ";
|
||||
break;
|
||||
default:
|
||||
if ( isset( $href_args['post_mime_type'] ) ) {
|
||||
$and = " AND p.post_status != 'trash' " . wp_post_mime_type_where( $href_args['post_mime_type'], 'p' );
|
||||
} else {
|
||||
$and = $this->wpdb->prepare( " AND p.post_status != 'trash' AND p.post_mime_type LIKE %s", $key . '%' );
|
||||
}
|
||||
}
|
||||
|
||||
// phpcs:disable WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
$and = apply_filters( 'wpml-media_view-upload-sql_and', $and, $key, $view, $lang );
|
||||
|
||||
$sql_and = $sql . $and;
|
||||
$sql = apply_filters( 'wpml-media_view-upload-sql', $sql_and, $key, $view, $lang );
|
||||
|
||||
$res = apply_filters( 'wpml-media_view-upload-count', null, $key, $view, $lang );
|
||||
// phpcs:enable
|
||||
|
||||
if ( null === $res ) {
|
||||
$res = $this->wpdb->get_col( $sql );
|
||||
}
|
||||
// Replace count.
|
||||
$view = preg_replace( '/\((\d+)\)/', '(' . $res[0] . ')', $view );
|
||||
}
|
||||
|
||||
// Replace href link, adding the 'lang' argument and the revised count.
|
||||
$href_args['lang'] = $lang;
|
||||
$href_args = array_map( 'urlencode', $href_args );
|
||||
$new_href = add_query_arg( $href_args, $href_base );
|
||||
$views[ $key ] = preg_replace( '/(href=["\'])([\s\S]+?)(["\'])/', '$1' . $new_href . '$3', $view );
|
||||
}
|
||||
}
|
||||
|
||||
return $views;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the image is not duplicated to another post before deleting it physically.
|
||||
*
|
||||
* @param string $file Full file name.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function delete_file_filter( $file ) {
|
||||
if ( $file ) {
|
||||
$file_name = $this->get_file_name( $file );
|
||||
$sql = "SELECT pm.meta_id, pm.post_id FROM {$this->wpdb->postmeta} AS pm
|
||||
WHERE pm.meta_value = %s AND pm.meta_key='_wp_attached_file'";
|
||||
$attachment_prepared = $this->wpdb->prepare( $sql, [ $file_name ] );
|
||||
$attachment = $this->wpdb->get_row( $attachment_prepared );
|
||||
|
||||
if ( ! empty( $attachment ) ) {
|
||||
$file = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
private function get_file_name( $file ) {
|
||||
$file_name = $this->get_file_name_without_size_from_full_name( $file );
|
||||
$upload_dir = wp_upload_dir();
|
||||
$path_parts = explode( "/", Str::replace( $upload_dir['basedir'], '', $file ) );
|
||||
|
||||
if ( $path_parts ) {
|
||||
$path_parts[ count( $path_parts ) - 1 ] = $file_name;
|
||||
}
|
||||
|
||||
return ltrim( implode( '/', $path_parts ), '/' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file name without a size, i.e. 'a-600x400.png' -> 'a.png'.
|
||||
*
|
||||
* @param string $file Full file name.
|
||||
*
|
||||
* @return mixed|string|string[]|null
|
||||
*/
|
||||
private function get_file_name_without_size_from_full_name( $file ) {
|
||||
$file_name = preg_replace( '/^(.+)\-\d+x\d+(\.\w+)$/', '$1$2', $file );
|
||||
$file_name = preg_replace( '/^[\s\S]+(\/.+)$/', '$1', $file_name );
|
||||
$file_name = str_replace( '/', '', $file_name );
|
||||
|
||||
return $file_name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Exception extends Exception {
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
class WPML_Model_Attachments {
|
||||
const ATTACHMENT_TYPE = 'post_attachment';
|
||||
|
||||
/** @var SitePress */
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* @var WPML_Post_Status
|
||||
*/
|
||||
private $status_helper;
|
||||
|
||||
/**
|
||||
* @param SitePress $sitepress
|
||||
* @param WPML_Post_Status $status_helper
|
||||
*/
|
||||
public function __construct( SitePress $sitepress, WPML_Post_Status $status_helper ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->status_helper = $status_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $attachment_id
|
||||
* @param int $duplicated_attachment_id
|
||||
*/
|
||||
public function duplicate_post_meta_data( $attachment_id, $duplicated_attachment_id ) {
|
||||
foreach ( array( '_wp_attachment_metadata', '_wp_attached_file' ) as $meta_key ) {
|
||||
$duplicated_meta_value = get_post_meta( $duplicated_attachment_id, $meta_key, true );
|
||||
|
||||
if ( ! $duplicated_meta_value ) {
|
||||
$source_meta_value = get_post_meta( $attachment_id, $meta_key, true );
|
||||
update_post_meta( $duplicated_attachment_id, $meta_key, $source_meta_value );
|
||||
}
|
||||
}
|
||||
|
||||
update_post_meta( $duplicated_attachment_id, 'wpml_media_processed', 1 );
|
||||
|
||||
do_action( 'wpml_media_create_duplicate_attachment', $attachment_id, $duplicated_attachment_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $trid
|
||||
* @param string $target_language
|
||||
*
|
||||
* @return null|WP_Post
|
||||
*/
|
||||
public function find_duplicated_attachment( $trid, $target_language ) {
|
||||
$attachment_translations = $this->sitepress->get_element_translations( $trid, self::ATTACHMENT_TYPE, true, true );
|
||||
if ( is_array( $attachment_translations ) ) {
|
||||
foreach ( $attachment_translations as $attachment_translation ) {
|
||||
if ( $attachment_translation->language_code === $target_language ) {
|
||||
return get_post( $attachment_translation->element_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Post|null $attachment
|
||||
* @param int $parent_id_of_attachement
|
||||
* @param string $target_language
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function fetch_translated_parent_id( $attachment, $parent_id_of_attachement, $target_language ) {
|
||||
$translated_parent_id = null;
|
||||
|
||||
if ( null !== $attachment && $attachment->post_parent ) {
|
||||
$translated_parent_id = $attachment->post_parent;
|
||||
}
|
||||
|
||||
if ( $parent_id_of_attachement ) {
|
||||
$parent_post = get_post( $parent_id_of_attachement );
|
||||
if ( $parent_post ) {
|
||||
$translated_parent_id = $parent_id_of_attachement;
|
||||
$parent_id_language_code = $this->sitepress->get_language_for_element( $parent_post->ID, 'post_' . $parent_post->post_type );
|
||||
if ( $parent_id_language_code !== $target_language ) {
|
||||
$translated_parent_id = $this->sitepress->get_object_id( $parent_post->ID, $parent_post->post_type, false, $target_language );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $translated_parent_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $new_parent_id
|
||||
* @param WP_Post $attachment
|
||||
*/
|
||||
public function update_parent_id_in_existing_attachment( $new_parent_id, $attachment ) {
|
||||
if ( $this->is_valid_post_type( $attachment->post_type ) ) {
|
||||
wp_update_post( array( 'ID' => $attachment->ID, 'post_parent' => $new_parent_id ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $post_type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_valid_post_type( $post_type ) {
|
||||
$post_types = array_keys( get_post_types( ) );
|
||||
|
||||
return in_array( $post_type, $post_types, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $attachment_id
|
||||
* @param string $target_language
|
||||
* @param int $parent_id_in_target_language
|
||||
* @param int $trid
|
||||
*
|
||||
* @return int
|
||||
* @throws WPML_Media_Exception
|
||||
*/
|
||||
public function duplicate_attachment( $attachment_id, $target_language, $parent_id_in_target_language, $trid ) {
|
||||
$post = get_post( $attachment_id );
|
||||
$post->post_parent = $parent_id_in_target_language;
|
||||
$post->ID = null;
|
||||
|
||||
update_post_meta( $parent_id_in_target_language, '_wpml_media_duplicate', true ); // add the post meta if missing
|
||||
|
||||
$duplicated_attachment_id = $this->insert_attachment( $post );
|
||||
if ( ! $duplicated_attachment_id ) {
|
||||
throw new WPML_Media_Exception( 'Error occured during inserting duplicated attachment to db' );
|
||||
}
|
||||
|
||||
$this->add_language_information_to_attachment( $attachment_id, $duplicated_attachment_id, $target_language, $trid );
|
||||
|
||||
return $duplicated_attachment_id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function insert_attachment( $post ) {
|
||||
$add_attachment_filters_temp = null;
|
||||
if ( array_key_exists( 'add_attachment', $GLOBALS['wp_filter'] ) ) {
|
||||
$add_attachment_filters_temp = $GLOBALS['wp_filter']['add_attachment'];
|
||||
unset( $GLOBALS['wp_filter']['add_attachment'] );
|
||||
}
|
||||
|
||||
$duplicated_attachment_id = wp_insert_post( $post );
|
||||
if ( ! is_int( $duplicated_attachment_id ) ) {
|
||||
$duplicated_attachment_id = 0;
|
||||
}
|
||||
|
||||
if ( null !== $add_attachment_filters_temp ) {
|
||||
$GLOBALS['wp_filter']['add_attachment'] = $add_attachment_filters_temp;
|
||||
unset( $add_attachment_filters_temp );
|
||||
}
|
||||
|
||||
return $duplicated_attachment_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $attachment_id
|
||||
* @param int $duplicated_attachment_id
|
||||
* @param string $target_language
|
||||
* @param int $trid
|
||||
*/
|
||||
private function add_language_information_to_attachment( $attachment_id, $duplicated_attachment_id, $target_language, $trid ) {
|
||||
$source_language = $this->sitepress->get_language_for_element( $attachment_id, self::ATTACHMENT_TYPE );
|
||||
$this->sitepress->set_element_language_details( $duplicated_attachment_id, self::ATTACHMENT_TYPE, $trid, $target_language, $source_language );
|
||||
$this->status_helper->set_status( $duplicated_attachment_id, ICL_TM_DUPLICATE );
|
||||
$this->status_helper->set_update_status( $duplicated_attachment_id, false );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Media\Duplication;
|
||||
|
||||
abstract class AbstractFactory implements \IWPML_Backend_Action_Loader, \IWPML_Frontend_Action_Loader {
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected static function shouldActivateHooks() {
|
||||
return \WPML_Element_Sync_Settings_Factory::createPost()->is_sync( 'attachment' );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Media\Duplication;
|
||||
|
||||
use WPML\Element\API\IfOriginalPost;
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Relation;
|
||||
use WPML\LIB\WP\Post;
|
||||
use WPML\LIB\WP\Hooks as WPHooks;
|
||||
use function WPML\FP\pipe;
|
||||
use function WPML\FP\spreadArgs;
|
||||
|
||||
class Hooks {
|
||||
|
||||
public static function add() {
|
||||
WPHooks::onAction( 'update_postmeta', 10, 4 )
|
||||
->then( spreadArgs( Fns::withoutRecursion( Fns::noop(), [ self::class, 'syncAttachedFile' ] ) ) );
|
||||
}
|
||||
|
||||
public static function syncAttachedFile( $meta_id, $object_id, $meta_key, $meta_value ) {
|
||||
if ( $meta_key === '_wp_attached_file' ) {
|
||||
|
||||
$prevValue = Post::getMetaSingle( $object_id, $meta_key );
|
||||
|
||||
// $isMetaSameAsPrevious :: id → bool
|
||||
$isMetaSameAsPrevious = pipe( Post::getMetaSingle( Fns::__, $meta_key ), Relation::equals( $prevValue ) );
|
||||
|
||||
IfOriginalPost::getTranslationIds( $object_id )
|
||||
->filter( Fns::unary( $isMetaSameAsPrevious ) )
|
||||
->each( Fns::unary( Post::updateMeta( Fns::__, $meta_key, $meta_value ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Media\Duplication;
|
||||
|
||||
class HooksFactory extends AbstractFactory {
|
||||
public function create() {
|
||||
if ( self::shouldActivateHooks() ) {
|
||||
return [ Hooks::class, 'add' ];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Attachments_Duplication_Factory extends \WPML\Media\Duplication\AbstractFactory {
|
||||
|
||||
public function create() {
|
||||
if ( self::shouldActivateHooks() ) {
|
||||
return \WPML\Container\make( WPML_Media_Attachments_Duplication::class );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Settings_Factory extends WPML_Current_Screen_Loader_Factory {
|
||||
|
||||
public function create_hooks() {
|
||||
global $wpdb;
|
||||
|
||||
return new WPML_Media_Settings( $wpdb );
|
||||
}
|
||||
|
||||
public function get_screen_regex() {
|
||||
return defined( 'WPML_TM_FOLDER' )
|
||||
? '/(' . WPML_PLUGIN_FOLDER . '\/menu\/translation-options|wpml_page_' . WPML_TM_FOLDER . '\/menu\/settings)/'
|
||||
: '/' . WPML_PLUGIN_FOLDER . '\/menu\/translation-options/';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Settings {
|
||||
const ID = 'ml-content-setup-sec-media';
|
||||
|
||||
private $wpdb;
|
||||
|
||||
public function __construct( $wpdb ) {
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_script' ) );
|
||||
add_action( 'icl_tm_menu_mcsetup', array( $this, 'render' ) );
|
||||
add_filter( 'wpml_mcsetup_navigation_links', array( $this, 'mcsetup_navigation_links' ) );
|
||||
}
|
||||
|
||||
public function enqueue_script() {
|
||||
wp_enqueue_script( 'wpml-media-settings', ICL_PLUGIN_URL . '/res/js/media/settings.js', array(), ICL_SITEPRESS_VERSION, true );
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$orphan_attachments_sql = "
|
||||
SELECT COUNT(*)
|
||||
FROM {$this->wpdb->posts}
|
||||
WHERE post_type = 'attachment'
|
||||
AND ID NOT IN (
|
||||
SELECT element_id
|
||||
FROM {$this->wpdb->prefix}icl_translations
|
||||
WHERE element_type='post_attachment'
|
||||
)
|
||||
";
|
||||
|
||||
$orphan_attachments = $this->wpdb->get_var( $orphan_attachments_sql );
|
||||
|
||||
?>
|
||||
<div class="wpml-section" id="<?php echo esc_attr( self::ID ); ?>">
|
||||
|
||||
<div class="wpml-section-header">
|
||||
<h3><?php esc_html_e( 'Media Translation', 'sitepress' ); ?></h3>
|
||||
</div>
|
||||
|
||||
<div class="wpml-section-content">
|
||||
<?php if ( $orphan_attachments ) : ?>
|
||||
|
||||
<p><?php esc_html_e( "The Media Translation plugin needs to add languages to your site's media. Without this language information, existing media files will not be displayed in the WordPress admin.", 'sitepress' ); ?></p>
|
||||
|
||||
<?php else : ?>
|
||||
|
||||
<p><?php esc_html_e( 'You can check if some attachments can be duplicated to translated content:', 'sitepress' ); ?></p>
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
<form id="wpml_media_options_form">
|
||||
<input type="hidden" name="no_lang_attachments" value="<?php echo $orphan_attachments; ?>"/>
|
||||
<input type="hidden" id="wpml_media_options_action"/>
|
||||
<table class="wpml-media-existing-content">
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<ul class="wpml_media_options_language">
|
||||
<li><label><input type="checkbox" id="set_language_info" name="set_language_info" value="1"
|
||||
<?php
|
||||
if ( ! empty( $orphan_attachments ) ) :
|
||||
?>
|
||||
checked="checked"<?php endif; ?>
|
||||
<?php
|
||||
if ( empty( $orphan_attachments ) ) :
|
||||
?>
|
||||
disabled="disabled"<?php endif ?> /> <?php esc_html_e( 'Set language information for existing media', 'sitepress' ); ?></label></li>
|
||||
<li><label><input type="checkbox" id="translate_media" name="translate_media" value="1" checked="checked"/> <?php esc_html_e( 'Translate existing media in all languages', 'sitepress' ); ?></label></li>
|
||||
<li><label><input type="checkbox" id="duplicate_media" name="duplicate_media" value="1" checked="checked"/> <?php esc_html_e( 'Duplicate existing media for translated content', 'sitepress' ); ?></label></li>
|
||||
<li><label><input type="checkbox" id="duplicate_featured" name="duplicate_featured" value="1" checked="checked"/> <?php esc_html_e( 'Duplicate the featured images for translated content', 'sitepress' ); ?></label></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="https://wpml.org/documentation/getting-started-guide/media-translation/?utm_source=plugin&utm_medium=gui&utm_campaign=wpmlcore" target="_blank"><?php esc_html_e( 'Media Translation Documentation', 'sitepress' ); ?></a></td>
|
||||
<td align="right">
|
||||
<?php wp_nonce_field( 'wpml_media_settings_actions', 'wpml_media_settings_nonce' ); ?>
|
||||
<input class="button-primary" name="start" type="submit" value="<?php esc_attr_e( 'Start', 'sitepress' ); ?> »"/>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<img class="progress" src="<?php echo ICL_PLUGIN_URL; ?>/res/img/ajax-loader.gif" width="16" height="16" alt="loading" style="display: none;"/>
|
||||
<span class="status"> </span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<table class="wpml-media-new-content-settings">
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<h4><?php esc_html_e( 'How to handle media for new content:', 'sitepress' ); ?></h4>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<ul class="wpml_media_options_language">
|
||||
<?php
|
||||
$settings = get_option( '_wpml_media' );
|
||||
$content_defaults = $settings['new_content_settings'];
|
||||
|
||||
$always_translate_media_html_checked = $content_defaults['always_translate_media'] ? 'checked="checked"' : '';
|
||||
$duplicate_media_html_checked = $content_defaults['duplicate_media'] ? 'checked="checked"' : '';
|
||||
$duplicate_featured_html_checked = $content_defaults['duplicate_featured'] ? 'checked="checked"' : '';
|
||||
?>
|
||||
<li>
|
||||
<label><input type="checkbox" name="content_default_always_translate_media"
|
||||
value="1" <?php echo $always_translate_media_html_checked; ?> /> <?php esc_html_e( 'When uploading media to the Media library, make it available in all languages', 'sitepress' ); ?></label>
|
||||
</li>
|
||||
<li>
|
||||
<label><input type="checkbox" name="content_default_duplicate_media"
|
||||
value="1" <?php echo $duplicate_media_html_checked; ?> /> <?php esc_html_e( 'Duplicate media attachments for translations', 'sitepress' ); ?></label>
|
||||
</li>
|
||||
<li>
|
||||
<label><input type="checkbox" name="content_default_duplicate_featured"
|
||||
value="1" <?php echo $duplicate_featured_html_checked; ?> /> <?php esc_html_e( 'Duplicate featured images for translations', 'sitepress' ); ?></label>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<h4><?php esc_html_e( 'How to handle media library texts:', 'sitepress' ); ?></h4>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<ul class="wpml_media_options_media_library_texts">
|
||||
<?php
|
||||
$settings = get_option( '_wpml_media' );
|
||||
$translateMediaLibraryTexts = \WPML\FP\Obj::propOr(false, 'translate_media_library_texts', $settings) ? 'checked="checked"' : '';
|
||||
?>
|
||||
<li>
|
||||
<label><input type="checkbox" name="translate_media_library_texts"
|
||||
value="1" <?php echo $translateMediaLibraryTexts; ?> /> <?php esc_html_e( 'Translate media library texts with posts', 'sitepress' ); ?></label>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
<td colspan="2" align="right">
|
||||
<input class="button-secondary" name="set_defaults" type="submit" value="<?php esc_attr_e( 'Apply', 'sitepress' ); ?>"/>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<img class="content_default_progress" src="<?php echo ICL_PLUGIN_URL; ?>/res/img/ajax-loader.gif" width="16" height="16" alt="loading" style="display: none;"/>
|
||||
<span class="content_default_status"> </span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
|
||||
</table>
|
||||
|
||||
<div id="wpml_media_all_done" class="hidden updated">
|
||||
<p><?php esc_html_e( "You're all done. From now on, all new media files that you upload to content will receive a language. You can automatically duplicate them to translations from the post-edit screen.", 'sitepress' ); ?></p>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function mcsetup_navigation_links( array $mcsetup_sections ) {
|
||||
$mcsetup_sections[ self::ID ] = esc_html__( 'Media Translation', 'sitepress' );
|
||||
|
||||
return $mcsetup_sections;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace WPML\Media\Setup\Endpoint;
|
||||
|
||||
use WPML\Ajax\IHandler;
|
||||
use WPML\Collect\Support\Collection;
|
||||
|
||||
use WPML\FP\Right;
|
||||
use WPML\FP\Left;
|
||||
|
||||
use function WPML\Container\make;
|
||||
|
||||
class PerformSetup implements IHandler {
|
||||
public function run( Collection $data ) {
|
||||
if ( ! defined( 'WPML_MEDIA_VERSION' ) || ! class_exists( 'WPML_Media_Set_Posts_Media_Flag_Factory' ) ) {
|
||||
return Left::of( [ 'key' => false ] );
|
||||
}
|
||||
|
||||
$offset = $data->get( 'offset' );
|
||||
$mediaFlag = make( \WPML_Media_Set_Posts_Media_Flag_Factory::class )->create();
|
||||
list ( , $newOffset, $continue ) = $mediaFlag->process_batch( $offset );
|
||||
|
||||
return Right::of( [ 'continue' => $continue, 'offset' => $newOffset, ] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace WPML\Media\Setup\Endpoint;
|
||||
|
||||
use WPML\Ajax\IHandler;
|
||||
use WPML\Collect\Support\Collection;
|
||||
|
||||
use WPML\Utilities\KeyedLock;
|
||||
|
||||
use WPML\FP\Left;
|
||||
use WPML\FP\Right;
|
||||
|
||||
use function WPML\Container\make;
|
||||
|
||||
class PrepareSetup implements IHandler {
|
||||
const LOCK_RELEASE_TIMEOUT = 2 * MINUTE_IN_SECONDS;
|
||||
|
||||
public function run( Collection $data ) {
|
||||
if ( !defined( 'WPML_MEDIA_VERSION' ) || !class_exists( 'WPML_Media_Set_Posts_Media_Flag_Factory' ) ) {
|
||||
return Left::of( [ 'key' => false ] );
|
||||
}
|
||||
|
||||
$lock = make( KeyedLock::class, [ ':name' => self::class ] );
|
||||
$key = $lock->create( $data->get( 'key' ), self::LOCK_RELEASE_TIMEOUT );
|
||||
|
||||
if ( $key ) {
|
||||
$mediaFlag = make( \WPML_Media_Set_Posts_Media_Flag_Factory::class)->create();
|
||||
$mediaFlag->clear_flags();
|
||||
|
||||
return Right::of( [ 'key' => $key, ] );
|
||||
} else {
|
||||
return Left::of( [ 'key' => 'in-use', ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Media\Translate;
|
||||
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use WPML\Media\Option;
|
||||
|
||||
class LanguagesUpdated implements \IWPML_AJAX_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onAction( 'wpml_update_active_languages' )
|
||||
->then( function () {
|
||||
Option::setSetupFinished( false );
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Media\Translate\Endpoint;
|
||||
|
||||
use WPML\Ajax\IHandler;
|
||||
use WPML\Collect\Support\Collection;
|
||||
use WPML\FP\Obj;
|
||||
use WPML\LIB\WP\Option;
|
||||
use function WPML\Container\make;
|
||||
use WPML\FP\Right;
|
||||
|
||||
class DuplicateFeaturedImages implements IHandler {
|
||||
public function run( Collection $data ) {
|
||||
if ( ! $this->shouldDuplicateFeaturedImages() ) {
|
||||
return Right::of( 0 );
|
||||
}
|
||||
|
||||
$numberLeft = $data->get( 'remaining', null );
|
||||
|
||||
return Right::of(
|
||||
make( \WPML_Media_Attachments_Duplication::class )->batch_duplicate_featured_images( false, $numberLeft )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function shouldDuplicateFeaturedImages() {
|
||||
return (bool) Obj::pathOr( false, [ 'new_content_settings', 'duplicate_featured' ], Option::getOr( '_wpml_media', [] ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Media\Translate\Endpoint;
|
||||
|
||||
use WPML\Ajax\IHandler;
|
||||
use WPML\Collect\Support\Collection;
|
||||
use function WPML\Container\make;
|
||||
use WPML\FP\Right;
|
||||
|
||||
class FinishMediaTranslation implements IHandler {
|
||||
public function run( Collection $data ) {
|
||||
make( \WPML_Media_Attachments_Duplication::class )->batch_mark_processed( false );
|
||||
return Right::of( true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Media\Translate\Endpoint;
|
||||
|
||||
use WPML\Ajax\IHandler;
|
||||
use WPML\Collect\Support\Collection;
|
||||
use function WPML\Container\make;
|
||||
use WPML\FP\Left;
|
||||
use WPML\FP\Right;
|
||||
use WPML\Media\Option;
|
||||
use WPML\Utilities\KeyedLock;
|
||||
|
||||
class PrepareForTranslation implements IHandler {
|
||||
const LOCK_RELEASE_TIMEOUT = 2 * MINUTE_IN_SECONDS;
|
||||
|
||||
public function run( Collection $data ) {
|
||||
if ( Option::isSetupFinished() ) {
|
||||
return Left::of( [ 'key' => false ] );
|
||||
}
|
||||
|
||||
$lock = make( KeyedLock::class, [ ':name' => self::class ] );
|
||||
$key = $lock->create( $data->get( 'key' ), self::LOCK_RELEASE_TIMEOUT );
|
||||
|
||||
if ( $key ) {
|
||||
make( \WPML_Media_Attachments_Duplication::class )->batch_scan_prepare( false );
|
||||
|
||||
return Right::of( [ 'key' => $key, ] );
|
||||
} else {
|
||||
return Left::of( [ 'key' => 'in-use', ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Media\Translate\Endpoint;
|
||||
|
||||
use WPML\Ajax\IHandler;
|
||||
use WPML\Collect\Support\Collection;
|
||||
use function WPML\Container\make;
|
||||
use WPML\FP\Right;
|
||||
|
||||
class TranslateExistingMedia implements IHandler {
|
||||
public function run( Collection $data ) {
|
||||
return Right::of(
|
||||
make( \WPML_Media_Attachments_Duplication::class )->batch_translate_media( false )
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user