first commit

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

View File

@@ -0,0 +1,130 @@
<?php
class WPML_Package_Admin_Lang_Switcher {
private $package;
private $args;
public function __construct( $package, $args ) {
$this->package = new WPML_Package( $package );
$this->args = $args;
add_action( 'wp_before_admin_bar_render', array( $this, 'admin_language_switcher' ) );
add_action( 'wp_after_admin_bar_render', array( $this, 'add_meta_box' ) );
}
function admin_language_switcher() {
global $wp_admin_bar, $wpdb, $sitepress;
$parent = 'WPML_PACKAGE_LANG';
$package_language = $this->package->get_package_language();
if ( ! $package_language ) {
$package_language = $sitepress->get_default_language();
}
$wpml_pt_meta = new WPML_Package_Translation_Metabox( $this->package, $wpdb, $sitepress, $this->args );
$package_language_name = $wpml_pt_meta->get_package_language_name();
$wp_admin_bar->add_menu(
array(
'parent' => false,
'id' => $parent,
'title' => '<img width="18" height="12" src="' . $sitepress->get_flag_url( $package_language ) . '"> ' . $package_language_name,
)
);
}
function add_meta_box() {
global $wpdb, $sitepress;
$metabox = '<div id="wpml-package-admin-bar-popup" class="wpml-package-popup">';
$wpml_pt_meta = new WPML_Package_Translation_Metabox( $this->package, $wpdb, $sitepress, $this->args );
$metabox .= $wpml_pt_meta->get_metabox();
$metabox .= '</div>';
$metabox .= $this->add_js();
// This is required when a new package is created but it doesn't have any translated content yet.
// https://onthegosystems.myjetbrains.com/youtrack/issue/wpmlst-556
WPML_Simple_Language_Selector::enqueue_scripts();
wp_enqueue_style( 'wpml-package-adminbar-popup', WPML_ST_URL . '/res/css/wpml-package-adminbar-popup.css', array(), ICL_SITEPRESS_VERSION );
echo $metabox;
}
function add_js() {
ob_start();
?>
<script type="text/javascript">
var WPML_Package_Translation = WPML_Package_Translation || {};
WPML_Package_Translation.AdminLanguageSwitcher = function () {
var self = this;
self.init = function () {
self.link = jQuery('#wp-admin-bar-WPML_PACKAGE_LANG').find('.ab-item');
self.link.hover(self.show_lang_box, self.hide_lang_box);
self.popup = jQuery('#wpml-package-admin-bar-popup');
self.popup.css('left', self.link.offset().left);
self.popup.hover(self.show_lang_box, self.hide_on_leave);
jQuery('#icl_package_language').off('wpml-package-language-changed');
jQuery('#icl_package_language').on('wpml-package-language-changed', self.package_language_changed);
};
self.show_lang_box = function() {
self.popup.css('top', self.link.offset().top + self.link.height() - window.scrollTop);
self.popup.show();
};
self.hide_lang_box = function() {
self.popup.hide();
};
self.hide_on_leave = function(e) {
// Make sure we are fully leaving the popup because this is sometimes
// triggered when we open the language select and then move the mouse.
var x = e.clientX;
var y = e.clientY;
var pos = self.popup.offset();
if ( x < pos.left || x > pos.left + self.popup.width() || y < pos.top || y > pos.top + self.popup.height()) {
self.popup.fadeOut(800);
}
};
self.package_language_changed = function( e, lang ) {
self.link.html( self.find_flag(lang) + ' ' + lang);
self.popup.hide();
};
self.find_flag = function( lang ) {
var flag = '';
jQuery('.js-simple-lang-selector option').each( function() {
if (jQuery(this).text().trim() == lang.trim()) {
flag = '<img width="18" height="12" src="' + jQuery(this).data('flag_url') + '">';
}
});
return flag;
};
self.init();
};
jQuery(document).ready(
function () {
WPML_Package_Translation.admin_language_switcher = new WPML_Package_Translation.AdminLanguageSwitcher();
}
);
</script>
<?php
return ob_get_clean();
}
}

View File

@@ -0,0 +1,4 @@
<?php
define( 'LINE', 0 );
define( 'AREA', 1 );
define( 'VISUAL', 2 );

View File

@@ -0,0 +1,42 @@
<?php
class WPML_ST_Package_Factory {
/** @var WPML_WP_Cache_Factory $cache_factory */
private $cache_factory;
public function __construct( WPML_WP_Cache_Factory $cache_factory = null ) {
$this->cache_factory = $cache_factory;
wp_cache_add_non_persistent_groups( __CLASS__ );
}
/**
* @param \stdClass|\WPML_Package|array|int $package_data
*
* @return WPML_Package
*/
public function create( $package_data ) {
$cache_item = $this->get_cache_item( $package_data );
if ( ! $cache_item->exists() ) {
$cache_item->set( new WPML_Package( $package_data ) );
}
return $cache_item->get();
}
/**
* @param array|WPML_Package $package_data
*
* @return WPML_WP_Cache_Item
*/
private function get_cache_item( $package_data ) {
if ( ! $this->cache_factory ) {
$this->cache_factory = new WPML_WP_Cache_Factory();
}
$package_key = md5( json_encode( $package_data ) );
return $this->cache_factory->create_cache_item( __CLASS__, $package_key );
}
}

View File

@@ -0,0 +1,9 @@
<?php
class WPML_Package_Exception extends Exception {
public $type;
public function __construct( $type = '', $message = '', $code = 0 ) {
parent::__construct( $message, $code );
$this->type = $type;
}
}

View File

@@ -0,0 +1,720 @@
<?php
class WPML_Package_Helper {
const PREFIX_BATCH_STRING = 'batch-string-';
private $default_language;
private $last_registered_string_id;
protected $registered_strings;
private $package_cleanup;
private $package_factory;
private $cache_group;
function __construct() {
$this->registered_strings = array();
$this->cache_group = 'string_package';
$this->package_cleanup = new WPML_ST_Package_Cleanup();
$this->package_factory = new WPML_ST_Package_Factory();
}
public function set_package_factory( WPML_ST_Package_Factory $factory ) {
$this->package_factory = $factory;
}
/**
* @param int $package_id
*/
protected function delete_package( $package_id ) {
// delete the strings and the translations
$this->delete_package_strings( $package_id );
$tm = new WPML_Package_TM( $this->package_factory->create( $package_id ) );
$tm->delete_translation_jobs();
$tm->delete_translations();
global $wpdb;
$delete_query = "DELETE FROM {$wpdb->prefix}icl_string_packages WHERE id=%d";
$delete_prepare = $wpdb->prepare( $delete_query, $package_id );
$wpdb->query( $delete_prepare );
}
/**
* @param int $package_id
*
* @return array
*/
protected function get_strings_ids_from_package_id( $package_id ) {
global $wpdb;
$string_ids_query = "SELECT id FROM {$wpdb->prefix}icl_strings WHERE string_package_id=%d";
$string_ids_prepare = $wpdb->prepare( $string_ids_query, $package_id );
$string_ids = $wpdb->get_col( $string_ids_prepare );
return $string_ids;
}
/**
* @param int $package_id
*/
protected function delete_package_strings( $package_id ) {
$strings = $this->get_strings_ids_from_package_id( $package_id );
foreach ( $strings as $string_id ) {
do_action( 'wpml_st_delete_all_string_data', $string_id );
}
}
protected function loaded() {
$this->default_language = icl_get_default_language();
}
/**
* @param string $string_value
* @param string $string_name
* @param array|WPML_Package $package
* @param string $string_title
* @param string $string_type
*/
final function register_string_action( $string_value, $string_name, $package, $string_title, $string_type ) {
$this->register_string_for_translation( $string_value, $string_name, $package, $string_title, $string_type );
return $this->last_registered_string_id;
}
/**
* @param int $default
* @param \stdClass|\WPML_Package|array|int $package
* @param string $string_name
* @param string $string_value
*
* @return bool|int|mixed
*/
function string_id_from_package_filter( $default, $package, $string_name, $string_value ) {
$string_id = $this->get_string_id_from_package( $package, $string_name, $string_value );
if ( ! $string_id ) {
return $default;
}
return $string_id;
}
function string_title_from_id_filter( $default, $string_id ) {
global $wpdb;
$string_title_query = 'SELECT title FROM ' . $wpdb->prefix . 'icl_strings WHERE id=%d';
$string_title_sql = $wpdb->prepare( $string_title_query, array( $string_id ) );
$string_title = $wpdb->get_var( $string_title_sql );
if ( ! $string_title ) {
$string_title = $default;
}
return $string_title;
}
/**
* @param string $string_value
* @param string $string_name
* @param array|WPML_Package $package
* @param string $string_title
* @param string $string_type
*
* @return string
*/
final public function register_string_for_translation( $string_value, $string_name, $package, $string_title, $string_type ) {
$package = $this->package_factory->create( $package );
$package_id = $package->ID;
if ( ! $package_id ) {
// Need to create a new record.
if ( $package->has_kind_and_name() ) {
$package_id = self::create_new_package( $package );
$package = $this->package_factory->create( $package );
}
}
if ( $package_id ) {
$this->maybe_update_package( $package );
$tm = new WPML_Package_TM( $package );
$tm->validate_translations();
$this->init_package_registered_strings( $package_id );
$string_name = $package->sanitize_string_name( $string_name );
$this->set_package_registered_strings( $package_id, $string_type, $string_title, $string_name, $string_value );
$this->last_registered_string_id = $this->register_string_with_wpml( $package, $string_name, $string_title, $string_type, $string_value );
$this->package_cleanup->record_register_string( $package, $this->last_registered_string_id );
}
return $string_value;
}
final function get_string_context_from_package( $package ) {
$package = $this->package_factory->create( $package );
return $package->get_string_context_from_package();
}
/**
* @param WPML_Package $package
* @param string $string_name
* @param string $string_title
* @param string $string_type
* @param string $string_value
*
* @return bool|int|mixed
*/
final function register_string_with_wpml( $package, $string_name, $string_title, $string_type, $string_value ) {
global $wpdb;
$string_id = $this->get_string_id_from_package( $package, $string_name, $string_value );
if ( $string_id ) {
$package_storage = new WPML_ST_Package_Storage( $package->ID, $wpdb );
$did_update = $package_storage->update( $string_title, $string_type, $string_value, $string_id );
if ( $did_update ) {
$this->flush_cache();
$package->flush_cache();
}
}
return $string_id;
}
final function translate_string( $string_value, $string_name, $package ) {
$result = $string_value;
if ( is_string( $string_value ) ) {
$package = $this->package_factory->create( $package );
if ( $package ) {
$sanitized_string_name = $package->sanitize_string_name( $string_name );
$result = $package->translate_string( $string_value, $sanitized_string_name );
}
}
return $result;
}
final function get_translated_strings( $strings, $package ) {
$package = $this->package_factory->create( $package );
return $package->get_translated_strings( $strings );
}
final function set_translated_strings( $translations, $package ) {
$package = $this->package_factory->create( $package );
$package->set_translated_strings( $translations );
}
final function get_translatable_types( $types ) {
global $wpdb;
$package_kinds = $wpdb->get_results( "SELECT kind, kind_slug FROM {$wpdb->prefix}icl_string_packages WHERE id>0" );
// Add any packages found to the $types array
foreach ( $package_kinds as $package_data ) {
$package_kind_slug = $package_data->kind_slug;
$package_kind = $package_data->kind;
$kinds_added = array_keys( $types );
if ( ! in_array( $package_kind_slug, $kinds_added ) ) {
$translatable_type = new stdClass();
$translatable_type->name = $package_kind_slug;
$translatable_type->label = $package_kind;
$translatable_type->prefix = 'package';
$translatable_type->labels = new stdClass();
$translatable_type->labels->singular_name = $package_kind;
$translatable_type->labels->name = $package_kind;
$translatable_type->external_type = 1;
$types[ $package_kind_slug ] = $translatable_type;
}
}
return $types;
}
/**
* @param WPML_Package $item
* @param int|WP_Post|WPML_Package $package
* @param string $type
*
* @return bool|WPML_Package
*/
final public function get_translatable_item( $item, $package, $type = 'package' ) {
if ( $type === 'package' || explode( '_', $type )[0] === 'package' ) {
$tm = new WPML_Package_TM( $item );
return $tm->get_translatable_item( $package );
}
return $item;
}
final function get_post_title( $title, $package_id ) {
$package = $this->package_factory->create( $package_id );
if ( $package ) {
$title = $package->kind . ' - ' . $package->title;
}
return $title;
}
final function get_editor_string_name( $name, $package ) {
$package = $this->package_factory->create( $package );
$package_id = $package->ID;
$title = $this->get_editor_string_element( $name, $package_id, 'title' );
if ( $title && $title != '' ) {
$name = $title;
} elseif (
\WPML\FP\Str::includes( self::PREFIX_BATCH_STRING, $name )
&& ( $string = $this->get_st_string_by_batch_name( $name ) )
) {
$name = $this->empty_if_md5( $string->get_name() )
?: ( $string->get_gettext_context() ?: ( $string->get_context() ?: $name ) );
}
return $name;
}
private function empty_if_md5( $str ) {
return preg_replace( '#^((.+)( - ))?([a-z0-9]{32})$#', '$2', $str );
}
/**
* @param string $batch_string_name
*
* @return WPML_ST_String|null
* @throws \WPML\Auryn\InjectionException
*/
private function get_st_string_by_batch_name( $batch_string_name ) {
$string_id = (int) \WPML\FP\Str::replace( self::PREFIX_BATCH_STRING, '', $batch_string_name );
if ( $string_id ) {
$string_factory = WPML\Container\make( WPML_ST_String_Factory::class );
return $string_factory->find_by_id( $string_id );
}
return null;
}
final function get_editor_string_style( $style, $field_type, $package ) {
$package = $this->package_factory->create( $package );
$package_id = $package->ID;
$element_style = $this->get_editor_string_element( $field_type, $package_id, 'type' );
if ( $element_style ) {
$style = 0;
if ( defined( $element_style ) ) {
$style = constant( $element_style );
}
}
return $style;
}
final public function get_element_id_from_package_filter( $default, $package_id ) {
global $wpdb;
$element_id_query = 'SELECT name FROM ' . $wpdb->prefix . 'icl_string_packages WHERE ID=%d';
$element_id_prepare = $wpdb->prepare( $element_id_query, $package_id );
$element_id = $wpdb->get_var( $element_id_prepare );
if ( ! $element_id ) {
$element_id = $default;
}
return $element_id;
}
final public function get_package_type( $type, $post_id ) {
$package = $this->package_factory->create( $post_id );
if ( $package ) {
return $this->get_package_context( $package );
} else {
return $type;
}
}
final public function get_package_type_prefix( $type, $post_id ) {
if ( $type == 'package' ) {
$package = $this->package_factory->create( $post_id );
if ( $package ) {
$type = $package->get_string_context_from_package();
}
}
return $type;
}
/**
* @param string $language_for_element
* @param \WPML_Package $current_document
*
* @return null|string
*/
final public function get_language_for_element( $language_for_element, $current_document ) {
if ( $this->is_a_package( $current_document ) ) {
global $sitepress;
$language_for_element = $sitepress->get_language_for_element( $current_document->ID, $current_document->get_translation_element_type() );
}
return $language_for_element;
}
final protected function get_package_context( $package ) {
$package = $this->package_factory->create( $package );
return $package->kind_slug . '-' . $package->name;
}
final function delete_packages_ajax() {
if ( ! $this->verify_ajax_call( 'wpml_package_nonce' ) ) {
die( 'verification failed' );
}
$packages_ids = $_POST['packages'];
$this->delete_packages( $packages_ids );
exit;
}
final function delete_package_action( $name, $kind ) {
$package_data['name'] = $name;
$package_data['kind'] = $kind;
$package = $this->package_factory->create( $package_data );
if ( $package && $package->ID && $this->is_a_package( $package ) ) {
$this->delete_package( $package->ID );
$this->flush_cache();
}
}
/** @param int $post_id */
final public function remove_post_packages( $post_id ) {
$packages = $this->get_post_string_packages( array(), $post_id );
foreach ( $packages as $package ) {
$this->delete_package( $package->ID );
}
}
final protected function delete_packages( $packages_ids ) {
$flush_cache = false;
foreach ( $packages_ids as $package_id ) {
$this->delete_package( $package_id );
$flush_cache = true;
}
if ( $flush_cache ) {
$this->flush_cache();
}
}
final function change_package_lang_ajax() {
global $wpdb, $sitepress;
if ( ! $this->verify_ajax_call( 'wpml_package_nonce' ) ) {
die( 'verification failed' );
}
$package_id = $_POST['package_id'];
$package = $this->package_factory->create( $package_id );
$package->set_strings_language( $_POST['package_lang'] );
$package_job = new WPML_Package_TM( $package );
$package_job->set_language_details( $_POST['package_lang'] );
$args = filter_var_array( json_decode( base64_decode( $_POST['args'] ) ), FILTER_SANITIZE_STRING );
$package_metabox = new WPML_Package_Translation_Metabox( $package, $wpdb, $sitepress, $args );
$response = array(
'metabox' => $package_metabox->get_metabox_status(),
'lang' => $package_metabox->get_package_language_name(),
);
wp_send_json( $response );
}
/**
* @param string $string_name
* @param int $package_id
* @param string $column
*
* @return string
*/
private function get_editor_string_element( $string_name, $package_id, $column ) {
global $wpdb;
$element_query = 'SELECT ' . $column . "
FROM {$wpdb->prefix}icl_strings
WHERE string_package_id=%d AND name=%s";
$element_prepared = $wpdb->prepare( $element_query, array( $package_id, $string_name ) );
$element = $wpdb->get_var( $element_prepared );
return $element;
}
private function flush_cache() {
// delete the cache key we use
wp_cache_delete( 'get_all_packages', $this->cache_group );
}
/**
* @param WPML_Package $package
*
* @return int
*/
final public static function create_new_package( WPML_Package $package ) {
$package_id = $package->create_new_package_record();
$tm = new WPML_Package_TM( $package );
$tm->update_package_translations( true );
return (int) $package_id;
}
/**
* @param int $package_id
*/
private function init_package_registered_strings( $package_id ) {
if ( ! isset( $this->registered_strings[ $package_id ] ) ) {
$this->registered_strings[ $package_id ] = array( 'strings' => array() );
}
}
/**
* @param int $package_id
* @param string $string_type
* @param string $string_title
* @param string $string_name
* @param string $string_value
*/
private function set_package_registered_strings( $package_id, $string_type, $string_title, $string_name, $string_value ) {
$this->registered_strings[ $package_id ]['strings'][ $string_name ] = array(
'title' => $string_title,
'kind' => $string_type,
'value' => $string_value,
);
}
/**
* @param \stdClass|\WPML_Package|array|int $package
* @param string $string_name
* @param string $string_value
*
* @return bool|int|mixed
*/
private function get_string_id_from_package( $package, $string_name, $string_value ) {
if ( ! $package instanceof WPML_Package ) {
$package = $this->package_factory->create( $package );
}
return $package->get_string_id_from_package( $string_name, $string_value );
}
final function get_external_id_from_package( $package ) {
return 'external_' . $package['kind_slug'] . '_' . $package['ID'];
}
final function get_string_context( $package ) {
return sanitize_title_with_dashes( $package['kind_slug'] . '-' . $package['name'] );
}
final function get_package_id( $package, $from_cache = true ) {
global $wpdb;
static $cache = array();
if ( $this->is_a_package( $package ) ) {
$package = object_to_array( $package );
}
$key = $this->get_string_context( $package );
if ( ! $from_cache || ! array_key_exists( $key, $cache ) ) {
$package_id_query = "SELECT ID FROM {$wpdb->prefix}icl_string_packages WHERE kind_slug = %s AND name = %s";
$package_id_prepare = $wpdb->prepare( $package_id_query, array( $package['kind_slug'], $package['name'] ) );
$package_id = $wpdb->get_var( $package_id_prepare );
if ( ! $package_id ) {
return false;
}
$cache[ $key ] = $package_id;
}
return $cache[ $key ];
}
final public function get_all_packages() {
global $wpdb;
$cache_key = 'get_all_packages';
$cache_found = false;
$all_packages = wp_cache_get( $cache_key, $this->cache_group, false, $cache_found );
if ( ! $cache_found ) {
$all_packages = array();
$all_packages_data_query = "SELECT * FROM {$wpdb->prefix}icl_string_packages";
$all_packages_data = $wpdb->get_results( $all_packages_data_query );
foreach ( $all_packages_data as $package_data ) {
$package = $this->package_factory->create( $package_data );
$all_packages[ $package->ID ] = $package;
}
if ( $all_packages ) {
wp_cache_set( $cache_key, $all_packages, $this->cache_group );
}
}
return $all_packages;
}
final protected function is_a_package( $element ) {
return is_a( $element, 'WPML_Package' );
}
protected function verify_ajax_call( $ajax_action ) {
return isset( $_POST['wpnonce'] ) && wp_verify_nonce( $_POST['wpnonce'], $ajax_action );
}
protected function sanitize_string_name( $string_name ) {
$string_name = preg_replace( '/[ \[\]]+/', '-', $string_name );
return $string_name;
}
public function refresh_packages() {
// TODO: deprecated.
// This is required to support Layouts 1.0
do_action( 'WPML_register_string_packages', 'layout', array() );
// TODO: END deprecated.
do_action( 'wpml_register_string_packages' );
}
/**
* @param WPML_Package $package
*/
private function maybe_update_package( $package ) {
if ( $package->new_title ) {
$package->title = $package->new_title;
$package->update_package_record();
}
}
public function change_language_of_strings( $strings, $lang ) {
global $wpdb;
$all_ok = true;
$strings_in = implode( ',', $strings );
$string_packages_query = "SELECT DISTINCT string_package_id FROM {$wpdb->prefix}icl_strings WHERE id IN ($strings_in)";
$package_ids = $wpdb->get_col( $string_packages_query );
foreach ( $package_ids as $package_id ) {
if ( $package_id ) {
$package = $this->package_factory->create( $package_id );
if ( ! $package->are_all_strings_included( $strings ) ) {
$all_ok = false;
break;
}
}
}
if ( $all_ok ) {
$this->set_packages_language( $package_ids, $lang );
}
$response = array();
$response['success'] = $all_ok;
if ( ! $all_ok ) {
$response['error'] = __( 'Some of the strings selected belong to packages. You can only change the language of these strings if all strings in the packages are selected.', 'wpml-string-translation' );
}
return $response;
}
public function change_language_of_strings_in_domain( $domain, $langs, $to_lang ) {
global $wpdb;
if ( ! empty( $langs ) ) {
foreach ( $langs as &$lang ) {
$lang = "'" . $lang . "'";
}
$langs = implode( ',', $langs );
$string_packages_query = "SELECT DISTINCT string_package_id FROM {$wpdb->prefix}icl_strings WHERE context='%s' AND language IN ($langs)";
$string_packages_query = $wpdb->prepare( $string_packages_query, $domain );
$package_ids = $wpdb->get_col( $string_packages_query );
$this->set_packages_language( $package_ids, $to_lang );
}
}
private function set_packages_language( $package_ids, $lang ) {
foreach ( $package_ids as $package_id ) {
if ( $package_id ) {
$package = $this->package_factory->create( $package_id );
$package->set_strings_language( $lang );
$package_job = new WPML_Package_TM( $package );
$package_job->set_language_details( $lang );
}
}
}
/**
* @param null|array $packages
* @param int $post_id
*
* @return WPML_Package[]
*/
public function get_post_string_packages( $packages, $post_id ) {
global $wpdb;
$query = $wpdb->prepare( "SELECT ID FROM {$wpdb->prefix}icl_string_packages WHERE post_id = %d", $post_id );
$package_ids = $wpdb->get_col( $query );
$packages = $packages ? $packages : array();
foreach ( $package_ids as $package_id ) {
$packages[ $package_id ] = $this->package_factory->create( $package_id );
}
return $packages;
}
/**
* @param int $string_id
* @param string $language
* @param string|null $value
* @param int|bool $status
* @param int|null $translator_id
* @param int|null $translation_service
* @param int|null $batch_id
*/
public function add_string_translation_action( $string_id, $language, $value = null, $status = false, $translator_id = null, $translation_service = null, $batch_id = null ) {
icl_add_string_translation( $string_id, $language, $value, $status, $translator_id, $translation_service, $batch_id );
}
/**
* @param mixed $package
* @param int $package_id
*
* @return WPML_Package
*/
public function get_string_package( $package, $package_id ) {
return $this->package_factory->create( $package_id );
}
public function start_string_package_registration_action( $package ) {
$this->package_cleanup->record_existing_strings( $this->package_factory->create( $package ) );
}
public function delete_unused_package_strings_action( $package ) {
$this->package_cleanup->delete_unused_strings( $this->package_factory->create( $package ) );
}
}

View File

@@ -0,0 +1,168 @@
<?php
class WPML_Package_Translation_HTML_Packages {
var $load_priority = 101;
public function __construct() {
add_action( 'WPML_PT_HTML', array( $this, 'loaded' ), $this->load_priority );
}
public function loaded() {
$this->set_admin_hooks();
}
private function set_admin_hooks() {
if ( is_admin() ) {
add_action( 'wpml_pt_package_table_columns', array( $this, 'render_package_table_columns' ), 10, 1 );
add_action( 'wpml_pt_package_table_options', array( $this, 'package_translation_menu_options' ), 10, 1 );
add_action( 'wpml_pt_package_table_body', array( $this, 'package_translation_menu_body' ), 10, 1 );
add_action( 'wpml_pt_package_status', array( $this, 'render_string_package_status' ), 10, 3 );
}
}
public static function package_translation_menu() {
$packages = apply_filters( 'wpml_pt_all_packages', array() );
$package_kinds = array();
if ( $packages ) {
foreach ( $packages as $package ) {
$kind_slugs = array_keys( $package_kinds );
if ( ! in_array( $package->kind_slug, $kind_slugs ) ) {
$package_kinds[ $package->kind_slug ] = $package->kind;
}
}
}
$table_title = __( 'Package Management', 'wpml-string-translation' );
$package_kind_label = __( 'Display packages for this kind:', 'wpml-string-translation' );
$package_kind_options[- 1] = __( 'Display packages for this kind:', 'wpml-string-translation' );
foreach ( $package_kinds as $kind_slug => $kind ) {
$package_kind_options[ $kind_slug ] = $kind;
}
?>
<h2><?php echo $table_title; ?></h2>
<p>
<label for="package_kind_filter"><?php echo $package_kind_label; ?></label>
<select id="package_kind_filter">
<?php do_action( 'wpml_pt_package_table_options', $package_kind_options ); ?>
</select>
</p>
<table id="icl_package_translations" class="widefat" cellspacing="0">
<thead>
<?php do_action( 'wpml_pt_package_table_columns', 'thead' ); ?>
</thead>
<tfoot>
<?php do_action( 'wpml_pt_package_table_columns', 'tfoot' ); ?>
</tfoot>
<tbody>
<?php do_action( 'wpml_pt_package_table_body', $packages ); ?>
</tbody>
</table>
<br/>
<input id="delete_packages" type="button" class="button-primary" value="<?php echo __( 'Delete Selected Packages', 'wpml-string-translation' ); ?>" disabled="disabled"/>
&nbsp;
<span class="spinner"></span>
<span style="display:none" class="js-delete-confirm-message"><?php echo __( "Are you sure you want to delete these packages?\nTheir strings and translations will be deleted too.", 'wpml-string-translation' ); ?></span>
<?php
wp_nonce_field( 'wpml_package_nonce', 'wpml_package_nonce' );
}
public function package_translation_menu_options( $package_kind_options ) {
foreach ( $package_kind_options as $option_value => $option_label ) {
?>
<option value="<?php echo esc_attr( $option_value ); ?>"><?php echo $option_label; ?></option>
<?php
}
}
/**
* @param array<\WPML_Package> $packages
*/
public function package_translation_menu_body( $packages ) {
if ( ! $packages ) {
$this->package_translation_menu_no_packages();
} else {
$this->package_translation_menu_items( $packages );
}
}
public function render_package_table_columns( $position ) {
?>
<tr>
<th scope="col" class="manage-column column-cb check-column">
<label for="select_all_package_<?php echo $position; ?>" style="display: none;">
<?php _e( 'Select All', 'wpml-string-translation' ); ?>
</label>
<input id="select_all_package_<?php echo $position; ?>" class="js_package_all_cb" type="checkbox"/>
</th>
<th scope="col"><?php echo __( 'Kind', 'wpml-string-translation' ); ?></th>
<th scope="col"><?php echo __( 'Name', 'wpml-string-translation' ); ?></th>
<th scope="col"><?php echo __( 'Info', 'wpml-string-translation' ); ?></th>
</tr>
<?php
}
public function render_string_package_status( $string_count, $translation_in_progress, $default_package_language ) {
$package_statuses[] = sprintf( __( 'Contains %s strings', 'wpml-string-translation' ), $string_count );
if ( $translation_in_progress ) {
$package_statuses[] = '(' . __( 'Translation is in progress', 'wpml-string-translation' ) . ')';
}
$package_statuses[] = __( 'Default package language', 'wpml-string-translation' ) . ': ' . $default_package_language;
echo implode( ' - ', $package_statuses );
}
private function package_translation_menu_no_packages() {
?>
<tr>
<td colspan="6" align="center">
<strong><?php echo __( 'No packages found', 'wpml-string-translation' ); ?></strong>
</td>
</tr>
<?php
}
/**
* @param array<\WPML_Package> $packages
*/
private function package_translation_menu_items( $packages ) {
global $wpdb, $sitepress;
foreach ( $packages as $package ) {
$package_language_code = $package->get_package_language();
$package_language = $sitepress->get_display_language_name( $package_language_code );
$tm = new WPML_Package_TM( $package );
$translation_in_progress = $tm->is_translation_in_progress();
$package_id = $package->ID;
$string_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}icl_strings WHERE string_package_id=%d", $package_id ) );
$disabled = disabled( $translation_in_progress, true, false );
?>
<tr id="row_<?php echo $package_id; ?>" class="js_package js_package_<?php echo esc_attr( $package->kind_slug ); ?>">
<td>
<input id="package_<?php echo $package_id; ?>" class="js_package_row_cb" type="checkbox" value="<?php echo $package_id; ?>" <?php echo $disabled; ?>/>
</td>
<td class="js-package-kind">
<?php echo $package->kind; ?>
</td>
<td>
<label for="package_<?php echo $package_id; ?>"><?php echo esc_html( $package->title ); ?></label>
</td>
<td>
<?php
do_action( 'wpml_pt_package_status', $string_count, $translation_in_progress, $package_language );
?>
</td>
</tr>
<?php
}
}
}

View File

@@ -0,0 +1,444 @@
<?php
class WPML_Package_Translation_Metabox {
private $args;
private $active_languages;
private $container_attributes_html;
private $dashboard_link;
private $strings_link;
private $default_language;
private $main_container_attributes;
private $show_description;
private $show_link;
private $show_status;
private $show_title;
private $status_container_attributes;
private $status_container_attributes_html;
private $status_container_tag;
private $status_element_tag;
private $title_tag;
public $metabox_data;
/**
* @var SitePress
*/
private $sitepress;
private $translation_statuses;
/**
* @var wpdb
*/
private $wpdb;
/**
* @var \WPML_Package
*/
private $package;
/**
* @var string
*/
private $package_language;
/**
* WPML_Package_Translation_Metabox constructor.
*
* @param stdClass|WPML_Package|array|int $package
* @param \wpdb $wpdb
* @param \SitePress $sitepress
* @param array<string,mixed> $args
*/
public function __construct( $package, $wpdb, $sitepress, $args = array() ) {
$this->wpdb = $wpdb;
$this->sitepress = $sitepress;
$this->package = new WPML_Package( $package );
$this->args = $args;
if ( $this->got_package() ) {
$this->dashboard_link = admin_url( 'admin.php?page=' . WPML_TM_FOLDER . '/menu/main.php&sm=dashboard&type=' . $this->package->kind_slug . '&lang=' . $this->package->get_package_language() );
$this->strings_link = admin_url( 'admin.php?page=' . WPML_ST_FOLDER . '/menu/string-translation.php&context=' . $this->package->get_string_context_from_package() );
}
$this->parse_arguments( $args );
$this->init_metabox_data();
}
private function init_metabox_data() {
$this->metabox_data = array();
$this->active_languages = $this->sitepress->get_active_languages();
$this->default_language = $this->sitepress->get_default_language();
$this->package_language = $this->package->get_package_language();
$this->package_language = $this->package_language ? $this->package_language : $this->default_language;
$this->metabox_data['title'] = __( 'WPML Translation', 'wpml-string-translation' );
if ( $this->is_package_language_active() ) {
$this->metabox_data['translate_title'] = __( 'Send to translation', 'wpml-string-translation' );
} else {
$this->metabox_data['translate_title'] = __( 'Translate strings', 'wpml-string-translation' );
}
if ( $this->got_package() ) {
$this->metabox_data['statuses_title'] = __( 'Translation status:', 'wpml-string-translation' );
$this->init_translation_statuses();
$this->metabox_data['package_language_title'] = sprintf( __( 'Language of this %1$s is %2$s', 'wpml-string-translation' ), $this->package->kind, $this->get_lang_selector() );
} else {
$this->metabox_data['package_language_title'] = '';
$this->metabox_data['statuses_title'] = __( 'There is nothing to translate.', 'wpml-string-translation' );
}
}
private function get_lang_selector() {
$disable = $this->check_if_language_change_is_ok() ? '' : 'disabled="disabled" ';
ob_start();
$languages = $this->active_languages;
if ( ! $this->is_package_language_active() ) {
$languages = array_merge( array( $this->sitepress->get_language_details( $this->package_language ) ), $languages );
} else {
$languages = $this->active_languages;
}
$selector = new WPML_Simple_Language_Selector( $this->sitepress );
$selector->render(
array(
'id' => 'icl_package_language',
'name' => 'icl_package_language',
'show_please_select' => false,
'languages' => $languages,
'selected' => $this->package_language,
'disabled' => ! $this->check_if_language_change_is_ok(),
'echo' => true,
)
);
?>
<span class="spinner"></span>
<?php
return ob_get_clean();
}
public function get_package_language_name() {
if ( $this->is_package_language_active() ) {
return $this->active_languages[ $this->package_language ]['display_name'];
} else {
$all_languages = $this->sitepress->get_languages();
return $all_languages[ $this->package_language ]['display_name'];
}
}
private function get_lang_switcher_js() {
ob_start();
?>
<script type="text/javascript">
var WPML_Package_Translation = WPML_Package_Translation || {};
WPML_Package_Translation.MetaBox = function () {
var self = this;
self.init = function () {
jQuery('#icl_package_language').off('change');
jQuery('#icl_package_language').on('change', self.switch_lang);
};
self.switch_lang = function() {
self.disable_controls(true);
var data = {
action: 'wpml_change_package_lang',
wpnonce: jQuery('#wpml_package_nonce').val(),
package_id: jQuery('#wpml_package_id').val(),
args: jQuery('#wpml_package_args').val(),
package_lang: jQuery(this).val()
};
jQuery.ajax(
{
url: ajaxurl,
type: 'post',
data: data,
dataType: 'json',
success: function (response) {
var position = jQuery('#wpml_package_status').prev();
jQuery('#wpml_package_status').remove();
jQuery(response.metabox).insertAfter(position);
jQuery('#icl_package_language').trigger('wpml-package-language-changed', [response.lang]);
self.disable_controls(false);
}
});
};
self.disable_controls = function(state) {
var lang_switcher = jQuery('#icl_package_language');
if (state) {
lang_switcher.next('.spinner').show();
lang_switcher.prop('disabled', true);
lang_switcher.closest('div').find('a').prop('disabled', true);
} else {
lang_switcher.next('.spinner').hide();
lang_switcher.prop('disabled', false);
lang_switcher.closest('div').find('a').prop('disabled', false);
}
};
self.init();
};
jQuery(document).ready(
function () {
WPML_Package_Translation.meta_box = new WPML_Package_Translation.MetaBox();
}
);
</script>
<?php
return ob_get_clean();
}
function get_metabox() {
$result = '';
$result .= '<div ' . $this->container_attributes_html . '>';
if ( $this->show_title ) {
if ( $this->title_tag ) {
$result .= $this->get_tag( $this->title_tag );
}
$result .= $this->metabox_data['title'];
if ( $this->title_tag ) {
$result .= $this->get_tag( $this->title_tag, 'closed' );
}
}
if ( $this->show_description ) {
$result .= '<div>' . $this->metabox_data['package_language_title'] . '</div>';
}
if ( $this->show_status ) {
$result .= '<p>' . $this->metabox_data['statuses_title'] . '</p>';
}
$result .= $this->get_metabox_status();
$result .= '</div>';
$result .= wp_nonce_field( 'wpml_package_nonce', 'wpml_package_nonce', true, false );
$result .= '<input type="hidden" id="wpml_package_id" value="' . $this->package->ID . '" />';
$result .= '<input type="hidden" id="wpml_package_args" value="' . base64_encode( wp_json_encode( $this->args ) ) . '" />';
if ( ! defined( 'DOING_AJAX' ) ) {
$result .= $this->get_lang_switcher_js();
}
return $result;
}
public function get_metabox_status() {
$result = '';
if ( $this->got_package() ) {
$result .= '<div id="wpml_package_status">';
if ( $this->show_status && $this->metabox_data['statuses'] ) {
if ( $this->status_container_tag ) {
$result .= $this->get_tag( $this->status_container_tag . ' ' . $this->status_container_attributes_html );
}
foreach ( $this->metabox_data['statuses'] as $code => $status ) {
$result .= $this->get_tag( $this->status_element_tag );
$result .= '<img width="18" height="12" src="' . $this->sitepress->get_flag_url( $code ) . '"> ' . $status['name'] . ' : ' . $status['status'];
$result .= $this->get_tag( $this->status_element_tag, 'closed' );
}
if ( $this->status_container_tag ) {
$result .= $this->get_tag( $this->status_container_tag, 'closed' );
}
}
if ( $this->show_link ) {
if ( $this->is_package_language_active() ) {
$result .= '<p><a style="float:right" class="button-secondary" href="' . $this->dashboard_link . '" target="_blank">' . $this->metabox_data['translate_title'] . '</a></p>';
} else {
$result .= '<p><a style="float:right" class="button-secondary" href="' . $this->strings_link . '" target="_blank">' . $this->metabox_data['translate_title'] . '</a></p>';
}
}
$result .= '<br /><br /></div>';
}
return $result;
}
private function check_if_language_change_is_ok() {
$ok = true;
foreach ( $this->translation_statuses as $status ) {
if ( isset( $status->status_code ) && $status->status_code != 0 ) {
$ok = false;
break;
}
}
if ( $ok ) {
$translations = $this->package->get_translated_strings( array() );
foreach ( $translations as $string ) {
foreach ( $string as $lang => $data ) {
if ( $data['status'] == ICL_STRING_TRANSLATION_COMPLETE ) {
$ok = false;
break;
}
}
if ( ! $ok ) {
break;
}
}
}
return $ok;
}
/**
* @param array<string,mixed> $attributes
*
* @return string
*/
private function attributes_to_string( $attributes ) {
$result = '';
foreach ( $attributes as $key => $value ) {
if ( $result ) {
$result .= ' ';
}
$result .= esc_html( $key ) . '="' . esc_attr( $value ) . '"';
}
return $result;
}
function get_post_translations() {
$element_type = $this->package->get_package_element_type();
$trid = $this->sitepress->get_element_trid( $this->package->ID, $element_type );
return $this->sitepress->get_element_translations( $trid, $element_type );
}
private function get_tag( $tag, $closed = false ) {
$result = '<';
if ( $closed ) {
$result .= '/';
}
$result .= $tag . '>';
return $result;
}
/**
* @param array<string,string|array<string,mixed> > $args
*/
private function parse_arguments( $args ) {
$default_args = array(
'show_title' => true,
'show_description' => true,
'show_status' => true,
'show_link' => true,
'title_tag' => 'h2',
'status_container_tag' => 'ul',
'status_element_tag' => 'li',
'main_container_attributes' => array(),
'status_container_attributes' => array( 'style' => 'padding-left: 10px' ),
);
$args = array_merge( $default_args, $args );
$this->show_title = $args['show_title'];
$this->show_description = $args['show_description'];
$this->show_status = $args['show_status'];
$this->show_link = $args['show_link'];
$this->title_tag = $args['title_tag'];
$this->status_container_tag = $args['status_container_tag'];
$this->status_element_tag = $args['status_element_tag'];
$this->main_container_attributes = $args['main_container_attributes'];
$this->status_container_attributes = $args['status_container_attributes'];
$this->container_attributes_html = $this->attributes_to_string( $this->main_container_attributes );
$this->status_container_attributes_html = $this->attributes_to_string( $this->status_container_attributes );
}
/**
* @return bool
*/
private function got_package() {
return $this->package && $this->package->ID;
}
private function get_translation_statuses() {
$post_translations = $this->get_post_translations();
$status = array();
foreach ( $post_translations as $language => $translation ) {
$res_query = "SELECT status as status_code, needs_update FROM {$this->wpdb->prefix}icl_translation_status WHERE translation_id=%d";
$res_args = array( $translation->translation_id );
$res_prepare = $this->wpdb->prepare( $res_query, $res_args );
/** @var \stdClass $res */
$res = $this->wpdb->get_row( $res_prepare );
if ( $res ) {
$res->status = $res->status_code;
switch ( $res->status ) {
case ICL_TM_WAITING_FOR_TRANSLATOR:
$res->status = __( 'Waiting for translator', 'wpml-string-translation' );
break;
case ICL_TM_IN_PROGRESS:
$res->status = __( 'In progress', 'wpml-string-translation' );
break;
case ICL_TM_NEEDS_UPDATE:
$res->status = '';
break;
case ICL_TM_COMPLETE:
$res->status = __( 'Complete', 'wpml-string-translation' );
break;
default:
$res->status = __( 'Not translated', 'wpml-string-translation' );
break;
}
if ( $res->needs_update ) {
if ( $res->status ) {
$res->status .= ' - ';
}
$res->status .= __( 'Needs update', 'wpml-string-translation' );
}
$status[ $language ] = $res;
}
}
return $status;
}
private function init_translation_statuses() {
$this->metabox_data['statuses'] = array();
$this->translation_statuses = $this->get_translation_statuses();
foreach ( $this->active_languages as $language_data ) {
if ( $language_data['code'] != $this->package_language ) {
$display_name = $language_data['display_name'];
$this->metabox_data['statuses'][ $language_data['code'] ] = array(
'name' => $display_name,
'status' => $this->get_status_value( $language_data ),
);
}
}
}
private function get_status_value( $language_data ) {
if ( isset( $this->translation_statuses[ $language_data['code'] ] ) ) {
$status_value = $this->translation_statuses[ $language_data['code'] ]->status;
} else {
$tm = new WPML_Package_TM( $this->package );
if ( $tm->is_in_basket( $language_data['code'] ) ) {
$status_value = __( 'In translation basket', 'wpml-string-translation' );
} else {
$status_value = __( 'Not translated', 'wpml-string-translation' );
}
}
return $status_value;
}
private function is_package_language_active() {
return in_array( $this->package_language, array_keys( $this->active_languages ) );
}
}

View File

@@ -0,0 +1,183 @@
<?php
class WPML_Package_Translation_Schema {
const OPTION_NAME = 'wpml-package-translation-db-updates-run';
const REQUIRED_VERSION = '0.0.2';
private static $table_name;
static function run_update() {
$updates_run = get_option( self::OPTION_NAME, array() );
if ( defined( 'WPML_PT_VERSION_DEV' ) ) {
delete_option( 'wpml-package-translation-string-packages-table-updated' );
if ( ( $key = array_search( WPML_PT_VERSION_DEV, $updates_run ) ) !== false ) {
unset( $updates_run[ $key ] );
}
}
if ( ! in_array( self::REQUIRED_VERSION, $updates_run ) ) {
// We need to make sure we build everything for 0.0.2 because users may
// only be updating the string translation plugin and may not do an
// activation.
self::build_icl_string_packages_table();
self::build_icl_string_packages_columns_if_required();
self::fix_icl_string_packages_ID_column();
self::build_icl_strings_columns_if_required();
$updates_run[] = self::REQUIRED_VERSION;
update_option( self::OPTION_NAME, $updates_run );
}
}
private static function current_table_has_column( $column ) {
global $wpdb;
$cols = $wpdb->get_results( 'SHOW COLUMNS FROM `' . self::$table_name . '`' );
$found = false;
foreach ( $cols as $col ) {
if ( $col->Field == $column ) {
$found = true;
break;
}
}
return $found;
}
private static function add_string_package_id_to_icl_strings() {
global $wpdb;
$sql = 'ALTER TABLE `' . self::$table_name . '`
ADD `string_package_id` BIGINT unsigned NULL AFTER value,
ADD INDEX (`string_package_id`)';
return $wpdb->query( $sql );
}
private static function add_type_to_icl_strings() {
global $wpdb;
$sql = 'ALTER TABLE `' . self::$table_name . "` ADD `type` VARCHAR(40) NOT NULL DEFAULT 'LINE' AFTER string_package_id";
return $wpdb->query( $sql );
}
private static function add_title_to_icl_strings() {
global $wpdb;
$sql = 'ALTER TABLE `' . self::$table_name . '` ADD `title` VARCHAR(160) NULL AFTER type';
return $wpdb->query( $sql );
}
public static function build_icl_strings_columns_if_required() {
global $wpdb;
if ( ! get_option( 'wpml-package-translation-string-table-updated' ) ) {
self::$table_name = $wpdb->prefix . 'icl_strings';
if ( $wpdb->get_var( "SHOW TABLES LIKE '" . self::$table_name . "'" ) == self::$table_name ) {
if ( ! self::current_table_has_column( 'string_package_id' ) ) {
self::add_string_package_id_to_icl_strings();
}
if ( ! self::current_table_has_column( 'type' ) ) {
self::add_type_to_icl_strings();
}
if ( ! self::current_table_has_column( 'title' ) ) {
self::add_title_to_icl_strings();
}
update_option( 'wpml-package-translation-string-table-updated', true, 'no' );
}
}
}
private static function build_icl_string_packages_columns_if_required() {
global $wpdb;
if ( get_option( 'wpml-package-translation-string-packages-table-updated' ) != '0.0.2' ) {
self::$table_name = $wpdb->prefix . 'icl_string_packages';
if ( $wpdb->get_var( "SHOW TABLES LIKE '" . self::$table_name . "'" ) == self::$table_name ) {
if ( ! self::current_table_has_column( 'kind_slug' ) ) {
self::add_kind_slug_to_icl_string_packages();
}
self::update_kind_slug();
if ( ! self::current_table_has_column( 'view_link' ) ) {
self::add_view_link_to_icl_string_packages();
}
update_option( 'wpml-package-translation-string-packages-table-updated', '0.0.2', 'no' );
}
}
}
private static function add_kind_slug_to_icl_string_packages() {
global $wpdb;
$sql = 'ALTER TABLE `' . self::$table_name . "` ADD `kind_slug` varchar(160) DEFAULT '' NOT NULL AFTER `ID`";
$result = $wpdb->query( $sql );
return $result;
}
private static function add_view_link_to_icl_string_packages() {
global $wpdb;
$sql = 'ALTER TABLE `' . self::$table_name . '` ADD `view_link` TEXT NOT NULL AFTER `edit_link`';
return $wpdb->query( $sql );
}
private static function fix_icl_string_packages_ID_column() {
global $wpdb;
self::$table_name = $wpdb->prefix . 'icl_string_packages';
if ( self::current_table_has_column( 'id' ) ) {
$sql = 'ALTER TABLE `' . self::$table_name . '` CHANGE id ID BIGINT UNSIGNED NOT NULL auto_increment;';
$wpdb->query( $sql );
}
}
private static function build_icl_string_packages_table() {
global $wpdb;
$charset_collate = SitePress_Setup::get_charset_collate();
self::$table_name = $wpdb->prefix . 'icl_string_packages';
$sql = '
CREATE TABLE IF NOT EXISTS `' . self::$table_name . '` (
`ID` bigint(20) unsigned NOT NULL auto_increment,
`kind_slug` varchar(160) NOT NULL,
`kind` varchar(160) NOT NULL,
`name` varchar(160) NOT NULL,
`title` varchar(160) NOT NULL,
`edit_link` TEXT NOT NULL,
`view_link` TEXT NOT NULL,
`post_id` INTEGER DEFAULT NULL,
`word_count` VARCHAR(2000) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ' . $charset_collate . '';
if ( $wpdb->query( $sql ) === false ) {
throw new Exception( $wpdb->last_error );
}
}
private static function update_kind_slug() {
global $wpdb;
$sql = 'SELECT kind FROM ' . self::$table_name . " WHERE IFNULL(kind_slug,'')='' GROUP BY kind";
$kinds = $wpdb->get_col( $sql );
$result = ( count( $kinds ) == 0 );
foreach ( $kinds as $kind ) {
$kind_slug = sanitize_title_with_dashes( $kind );
$result = $wpdb->update( self::$table_name, array( 'kind_slug' => $kind_slug ), array( 'kind' => $kind ) );
if ( ! $result ) {
break;
}
}
return $result;
}
}

View File

@@ -0,0 +1,29 @@
<?php
class WPML_Package_ST {
public function get_string_element( $string_id, $column = false ) {
global $wpdb;
$package_query = "SELECT * FROM {$wpdb->prefix}icl_strings WHERE id=%d";
$package_prepare = $wpdb->prepare( $package_query, array( $string_id ) );
$result = $wpdb->get_row( $package_prepare );
if ( $result && $column && isset( $result[ $column ] ) ) {
$result = $result[ $column ];
}
return $result;
}
public function get_string_title( $title, $string_details ) {
$string_title = $this->get_string_element( $string_details['string_id'], 'title' );
if ( $string_title ) {
return $string_title;
} else {
return $title;
}
}
}

View File

@@ -0,0 +1,215 @@
<?php
class WPML_Package_TM_Jobs {
/**
* @var WPML_Package
*/
protected $package;
protected function __construct( $package ) {
$this->package = $package;
}
final public function validate_translations( $create_if_missing = true ) {
$trid = $this->get_trid( $create_if_missing );
return $trid != false;
}
final protected function get_trid( $create_if_missing = true ) {
global $sitepress;
$package = $this->package;
$post_trid = $sitepress->get_element_trid( $package->ID, $package->get_translation_element_type() );
if ( ! $post_trid && $create_if_missing ) {
$this->set_language_details();
$post_trid = $sitepress->get_element_trid( $package->ID, $package->get_translation_element_type() );
}
return $post_trid;
}
final public function set_language_details( $language_code = null ) {
global $sitepress;
$package = $this->package;
$post_id = $package->ID;
$post = $this->get_translatable_item( $post_id );
$post_id = $post->ID;
$element_type = $package->get_translation_element_type();
if ( ! $language_code ) {
$language_code = icl_get_default_language();
}
$sitepress->set_element_language_details( $post_id, $element_type, false, $language_code, null, false );
}
final public function get_translatable_item( $package ) {
// for TranslationManagement::send_jobs
if ( ! is_a( $package, 'WPML_Package' ) ) {
$package = new WPML_Package( $package );
}
return $package;
}
final public function delete_translation_jobs() {
global $wpdb;
$post_translations = $this->get_post_translations();
foreach ( $post_translations as $lang => $translation ) {
$rid_query = "SELECT rid FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d";
$rid_prepare = $wpdb->prepare( $rid_query, array( $translation->translation_id ) );
$rid = $wpdb->get_var( $rid_prepare );
if ( $rid ) {
$job_id_query = "SELECT job_id FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d";
$job_id_prepare = $wpdb->prepare( $job_id_query, array( $rid ) );
$job_id = $wpdb->get_var( $job_id_prepare );
if ( $job_id ) {
$wpdb->delete( $wpdb->prefix . 'icl_translate_job', array( 'job_id' => $job_id ) );
$wpdb->delete( $wpdb->prefix . 'icl_translate', array( 'job_id' => $job_id ) );
}
}
}
}
final public function delete_translations() {
global $sitepress;
$sitepress->delete_element_translation(
$this->get_trid(),
$this->package->get_translation_element_type()
);
}
final public function get_post_translations() {
global $sitepress;
$package = $this->package;
$translation_element_type = $package->get_translation_element_type();
$trid = $this->get_trid();
return $sitepress->get_element_translations( $trid, $translation_element_type );
}
final protected function update_translation_job_needs_update( $job_id ) {
global $wpdb;
$update_data = array( 'translated' => 0 );
$update_where = array( 'job_id' => $job_id );
$wpdb->update( "{$wpdb->prefix}icl_translate_job", $update_data, $update_where );
}
final function update_translation_job( $rid, $post ) {
$updated = $this->update_translation_job_fields( $rid, $post );
$deleted = $this->delete_translation_job_fields( $rid, $post );
return ( $updated || $deleted );
}
private function delete_translation_job_fields( $rid, $post ) {
$deleted = false;
$job_id = $this->get_translation_job_id( $rid );
$translation_fields = $this->get_translations_job_fields( $job_id );
foreach ( $translation_fields as $field_type => $el ) {
// delete fields that are no longer present
if ( $el->field_translate && ! isset( $post->string_data[ $field_type ] ) ) {
$this->delete_translation_field( $el->tid );
if ( ! $deleted ) {
$deleted = true;
}
}
}
return $deleted;
}
/**
* @param int $rid
* @param WPML_Package $post
*
* @return bool
*/
private function update_translation_job_fields( $rid, $post ) {
$updated_any = false;
$job_id = $this->get_translation_job_id( $rid );
$translation_fields = $this->get_translations_job_fields( $job_id );
if ( isset( $post->string_data ) && is_array( $post->string_data ) ) {
foreach ( $post->string_data as $field_type => $field_value ) {
$updated = $this->insert_update_translation_job_field( $field_value, $translation_fields, $field_type, $job_id );
if ( ! $updated_any && $updated ) {
$updated_any = true;
}
}
}
return $updated_any;
}
protected function get_translation_job_id( $rid ) {
global $wpdb;
$job_id_query = "SELECT MAX(job_id) FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d GROUP BY rid";
$job_id_prepare = $wpdb->prepare( $job_id_query, $rid );
$job_id = $wpdb->get_var( $job_id_prepare );
return $job_id;
}
private function get_translations_job_fields( $job_id ) {
global $wpdb;
$translation_fields_query = "SELECT field_type, field_data, tid, field_translate
FROM {$wpdb->prefix}icl_translate
WHERE job_id=%d";
$translation_fields_query = $wpdb->prepare( $translation_fields_query, $job_id );
$translation_fields = $wpdb->get_results( $translation_fields_query, OBJECT_K );
return $translation_fields;
}
private function delete_translation_field( $tid ) {
global $wpdb;
$wpdb->delete( $wpdb->prefix . 'icl_translate', array( 'tid' => $tid ), array( '%d' ) );
}
private function insert_update_translation_job_field( $field_value, $translation_fields, $field_type, $job_id ) {
$updated = false;
$field_data = base64_encode( $field_value );
if ( ! isset( $translation_fields[ $field_type ] ) ) {
$this->insert_translation_field( $job_id, $field_type, $field_data );
$updated = true;
} elseif ( $translation_fields[ $field_type ]->field_data != $field_data ) {
$this->update_translation_field( $field_data, $translation_fields, $field_type );
$updated = true;
}
return $updated;
}
private function update_translation_field( $field_data, $translation_fields, $field_type ) {
global $wpdb;
$wpdb->update(
$wpdb->prefix . 'icl_translate',
array(
'field_data' => $field_data,
'field_finished' => 0,
),
array( 'tid' => $translation_fields[ $field_type ]->tid )
);
}
private function insert_translation_field( $job_id, $field_type, $field_data ) {
global $wpdb;
$data = array(
'job_id' => $job_id,
'content_id' => 0,
'field_type' => $field_type,
'field_format' => 'base64',
'field_translate' => 1,
'field_data' => $field_data,
'field_data_translated' => 0,
'field_finished' => 0,
);
$wpdb->insert( $wpdb->prefix . 'icl_translate', $data );
}
}

View File

@@ -0,0 +1,380 @@
<?php
class WPML_Package_TM extends WPML_Package_TM_Jobs {
public function __construct( $package ) {
parent::__construct( $package );
}
public function get_translation_statuses() {
global $sitepress;
$package = $this->package;
$post_trid = $this->get_trid();
$items = array();
if ( $post_trid ) {
$translation_element_type = $package->get_translation_element_type();
$post_translations = $sitepress->get_element_translations( $post_trid, $translation_element_type );
foreach ( $post_translations as $lang => $translation ) {
$translation->trid = $post_trid;
$item[] = $this->set_translation_status( $package, $translation, $lang );
}
} else {
$items[] = $package;
}
return $items;
}
/**
* @param \WPML_Package $package
* @param \stdClass $translation
* @param string $lang
*
* @return \WPML_Package
*/
private function set_translation_status( $package, $translation, $lang ) {
global $wpdb;
if ( ! $package->trid ) {
$package->trid = $translation->trid;
}
$res_query = "SELECT status, needs_update, md5 FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d";
$res_args = array( $translation->translation_id );
$res_prepare = $wpdb->prepare( $res_query, $res_args );
$res = $wpdb->get_row( $res_prepare );
$_suffix = str_replace( '-', '_', $lang );
$status = ICL_TM_NOT_TRANSLATED;
if ( $res ) {
$status = $res->status;
$index = 'needs_update_' . $_suffix;
$package->$index = $res->needs_update;
}
$index = 'status_' . $_suffix;
$package->$index = apply_filters( 'wpml_translation_status', $status, $translation->trid, $lang, 'package' );
return $package;
}
public function is_translation_in_progress() {
global $wpdb;
$post_translations = $this->get_post_translations();
foreach ( $post_translations as $lang => $translation ) {
$res_query = "SELECT status, needs_update, md5
FROM {$wpdb->prefix}icl_translation_status
WHERE translation_id=%d";
$res_prepared = $wpdb->prepare( $res_query, array( $translation->translation_id ) );
$res = $wpdb->get_row( $res_prepared );
if ( $res && $res->status == ICL_TM_IN_PROGRESS ) {
return true;
}
}
return false;
}
/**
* Update translations
*
* @param bool $is_new_package
* @param bool $needs_update - when deleting single field we do not need to change the translation status of the form
*
* @return bool
*/
public function update_package_translations( $is_new_package, $needs_update = true ) {
global $iclTranslationManagement;
$updated = false;
$package = $this->package;
$trid = $this->get_trid();
if ( $is_new_package ) {
$this->set_language_details();
return true;
}
$item_md5_translations = $this->get_item_md5_translations( $trid );
if ( $item_md5_translations ) {
$md5 = $iclTranslationManagement->post_md5( $this->package );
if ( $md5 != $item_md5_translations[0]->md5 ) { // all translations need update
$translation_package = $iclTranslationManagement->create_translation_package( $this->package );
foreach ( $item_md5_translations as $translation ) {
$translation_id = $translation->translation_id;
$previous_state = $this->get_translation_state( $translation );
$data = array();
if ( ! empty( $previous_state ) ) {
$data['previous_state'] = serialize( $previous_state );
}
$data = array(
'translation_id' => $translation_id,
'translation_package' => serialize( $translation_package ),
'md5' => $md5,
);
if ( $needs_update ) {
$data['needs_update'] = 1;
}
$update_result = $iclTranslationManagement->update_translation_status( $data );
$rid = $update_result[0];
$this->update_translation_job( $rid, $this->package );
// change job status only when needs update
if ( $needs_update ) {
$job_id = $this->get_translation_job_id( $rid );
if ( $job_id ) {
$this->update_translation_job_needs_update( $job_id );
$updated = true;
}
}
}
}
}
return $updated;
}
private function get_item_md5_translations( $trid ) {
global $wpdb;
$item_md5_translations_query = "
SELECT t.translation_id, s.md5
FROM {$wpdb->prefix}icl_translations t
NATURAL JOIN {$wpdb->prefix}icl_translation_status s
WHERE t.trid=%d
AND t.source_language_code IS NOT NULL";
$item_md5_translations_prepare = $wpdb->prepare( $item_md5_translations_query, $trid );
$item_md5_translations = $wpdb->get_results( $item_md5_translations_prepare );
return $item_md5_translations;
}
private function get_translation_state( $translation ) {
global $wpdb;
$previous_state_query = "
SELECT status, translator_id, needs_update, md5, translation_service, translation_package, timestamp, links_fixed
FROM {$wpdb->prefix}icl_translation_status
WHERE translation_id = %d
";
$previous_state_prepare = $wpdb->prepare( $previous_state_query, $translation->translation_id );
$previous_state = $wpdb->get_row( $previous_state_prepare, ARRAY_A );
return $previous_state;
}
public function add_package_to_basket( $translation_action, $source_language, $target_language ) {
if ( ! $this->validate_basket_package_item( $translation_action, $source_language ) ) {
return false;
}
if ( $this->is_duplicate_or_do_nothing( $translation_action ) ) {
$this->duplicate_or_do_nothing( $translation_action, $target_language );
} elseif ( $translation_action == 1 ) {
$this->send_package_to_basket( $source_language, $target_language );
}
return true;
}
private function duplicate_package( $package_id ) {
// TODO: [WPML 3.3] duplication to be done
// $this->make_duplicate( $package_id, $language_code );
}
/**
* @param int $translation_action
* @param string $source_language
*
* @return bool
*/
private function validate_basket_package_item( $translation_action, $source_language ) {
ICL_AdminNotifier::remove_message( 'the_basket_items_notification' );
$package = $this->package;
$package_id = $package->ID;
$basket = TranslationProxy_Basket::get_basket();
$package_is_valid = true;
$basket_source_language = TranslationProxy_Basket::get_source_language();
if ( $basket && $basket_source_language ) {
if ( $source_language != $basket_source_language ) {
TranslationProxy_Basket::add_message(
array(
'type' => 'update',
'text' => __(
'You cannot add packages in this language to the basket since it already contains posts, packages or strings of another source language!
Either submit the current basket and then add the post or delete the posts of differing language in the current basket',
'wpml-string-translation'
),
)
);
TranslationProxy_Basket::update_basket();
$package_is_valid = false;
}
}
$select_one_lang_message = __( 'Please select at least one language to translate into.', 'wpml-string-translation' );
if ( ! $translation_action ) {
TranslationProxy_Basket::add_message(
array(
'type' => 'error',
'text' => $select_one_lang_message,
)
);
$package_is_valid = false;
} else {
TranslationProxy_Basket::remove_message( $select_one_lang_message );
}
if ( ! $package_id ) {
TranslationProxy_Basket::add_message(
array(
'type' => 'error',
'text' => __( 'Please select at least one document to translate.', 'wpml-string-translation' ),
)
);
$package_is_valid = false;
return $package_is_valid;
}
return $package_is_valid;
}
private function is_duplicate_or_do_nothing( $translation_action ) {
return $translation_action == 0 || $translation_action == 2;
}
private function duplicate_or_do_nothing( $translation_action, $target_language ) {
$basket = TranslationProxy_Basket::get_basket();
$package = $this->package;
$package_id = $package->ID;
// iterate posts ids, check if they are in wp_options
// if they are set to translate for this particular language
// end then remove it
// check if we have this post in wp_options
// end remove
if ( isset( $basket['package'][ $package_id ]['to_langs'][ $target_language ] ) ) {
unset( $basket['package'][ $package_id ]['to_langs'][ $target_language ] );
TranslationProxy_Basket::update_basket( $basket );
}
// if user want to duplicate this post, lets do this
if ( $translation_action == 2 ) {
$this->duplicate_package( $package_id );
}
}
/**
* @param string $source_language
* @param string $target_language
*
* @throws WPML_Package_Exception
*/
public function send_package_to_basket( $source_language, $target_language ) {
global $sitepress, $iclTranslationManagement;
$package = $this->package;
$package_id = $package->ID;
$basket = TranslationProxy_Basket::get_basket();
$language_name = $sitepress->get_display_language_name( $target_language );
$send_to_basket = true;
$package_helper = new WPML_Package_Helper();
$post = $package_helper->get_translatable_item( null, $package_id );
$post_title = esc_html( $post->title );
$element_type = $package->get_element_type_prefix() . '_' . $post->kind_slug;
$trid = $sitepress->get_element_trid( $package_id, $element_type );
$job_id = $iclTranslationManagement->get_translation_job_id( $trid, $target_language );
if ( $job_id ) {
$job_details = $iclTranslationManagement->get_translation_job( $job_id );
$send_to_basket = $this->validate_package_status( $job_details, $post_title, $language_name );
}
if ( $send_to_basket ) {
$basket['package'][ $package_id ]['from_lang'] = $source_language;
$basket['package'][ $package_id ]['to_langs'][ $target_language ] = 1;
// set basket language if not already set
if ( ! isset( $basket['source_language'] ) ) {
$basket['source_language'] = $source_language;
}
}
TranslationProxy_Basket::update_basket( $basket );
}
/**
* @param \stdClass $job_details
* @param string $post_title
* @param string $language_name
*
* @return bool
*/
private function validate_package_status( $job_details, $post_title, $language_name ) {
$send_to_basket = true;
$message_args = array();
if ( ! $job_details->needs_update ) {
if ( $job_details->status == ICL_TM_IN_PROGRESS ) {
$message_args = array(
'type' => 'update',
'text' => sprintf(
__(
'Post "%1$s" will be ignored for %2$s, because translation is already in progress.',
'wpml-string-translation'
),
$post_title,
$language_name
),
);
$send_to_basket = false;
} elseif ( $job_details->status == ICL_TM_WAITING_FOR_TRANSLATOR ) {
$message_args = array(
'type' => 'update',
'text' => sprintf(
__(
'Post "%1$s" will be ignored for %2$s, because translation is already waiting for translator.',
'wpml-string-translation'
),
$post_title,
$language_name
),
);
$send_to_basket = false;
}
}
if ( ! $send_to_basket ) {
TranslationProxy_Basket::add_message( $message_args );
TranslationProxy_Basket::update_basket();
}
return $send_to_basket;
}
public function is_in_basket( $target_lang ) {
if ( class_exists( 'TranslationProxy_Basket' ) ) {
$basket = TranslationProxy_Basket::get_basket();
return isset( $basket['package'][ $this->package->ID ]['to_langs'][ $target_lang ] );
} else {
return false;
}
}
}

View File

@@ -0,0 +1,87 @@
<?php
class WPML_Package_Translation_UI {
var $load_priority = 101;
private $menu_root = '';
const MENU_SLUG = 'wpml-package-management';
public function __construct() {
add_action( 'wpml_loaded', array( $this, 'loaded' ), $this->load_priority );
}
public function loaded() {
if ( $this->passed_dependencies() ) {
$this->set_admin_hooks();
do_action( 'WPML_PT_HTML' );
}
}
private function passed_dependencies() {
return defined( 'ICL_SITEPRESS_VERSION' )
&& defined( 'WPML_ST_VERSION' )
&& defined( 'WPML_TM_VERSION' );
}
private function set_admin_hooks() {
if ( is_admin() ) {
add_action( 'wpml_admin_menu_configure', array( $this, 'menu' ) );
add_action( 'wpml_admin_menu_root_configured', array( $this, 'main_menu_configured' ), 10, 2 );
add_action( 'admin_register_scripts', array( $this, 'admin_register_scripts' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
}
}
public function main_menu_configured( $menu_id, $root_slug ) {
if ( 'WPML' === $menu_id ) {
$this->menu_root = $root_slug;
}
}
/**
* @param string $menu_id
*/
public function menu( $menu_id ) {
if ( 'WPML' !== $menu_id || ! defined( 'ICL_PLUGIN_PATH' ) ) {
return;
}
global $sitepress;
if ( ! isset( $sitepress ) || ( method_exists( $sitepress, 'get_setting' ) && ! $sitepress->get_setting( 'setup_complete' ) ) ) {
return;
}
global $sitepress_settings;
if ( ! isset( $sitepress_settings['existing_content_language_verified'] ) || ! $sitepress_settings['existing_content_language_verified'] ) {
return;
}
if ( current_user_can( 'wpml_manage_string_translation' ) ) {
$menu = array();
$menu['order'] = 1300;
$menu['page_title'] = __( 'Packages', 'wpml-string-translation' );
$menu['menu_title'] = __( 'Packages', 'wpml-string-translation' );
$menu['capability'] = 'wpml_manage_string_translation';
$menu['menu_slug'] = self::MENU_SLUG;
$menu['function'] = array(
'WPML_Package_Translation_HTML_Packages',
'package_translation_menu',
);
do_action( 'wpml_admin_menu_register_item', $menu );
$this->admin_register_scripts();
}
}
function admin_register_scripts() {
wp_register_script( 'wpml-package-trans-man-script', WPML_PACKAGE_TRANSLATION_URL . '/resources/js/wpml_package_management.js', array( 'jquery' ) );
}
function admin_enqueue_scripts( $hook ) {
if ( get_plugin_page_hookname( self::MENU_SLUG, $this->menu_root ) === $hook ) {
wp_enqueue_script( 'wpml-package-trans-man-script' );
}
}
}

View File

@@ -0,0 +1,806 @@
<?php
class WPML_Package_Translation extends WPML_Package_Helper {
var $load_priority = 100;
var $package_translation_active;
var $admin_lang_switcher = null;
function __construct() {
parent::__construct();
add_action( 'wpml_loaded', array( $this, 'loaded' ), $this->load_priority, 1 );
}
function loaded( SitePress $sitepress = null ) {
parent::loaded();
if ( null === $sitepress ) {
global $sitepress;
}
$is_setup_complete = (bool) $sitepress->get_setting( 'setup_complete', false );
if ( $is_setup_complete ) {
$this->run_db_update();
}
if ( $this->passed_dependencies() && $is_setup_complete ) {
$this->add_admin_hooks();
$this->add_global_hooks();
if ( is_admin() ) {
if ( $this->is_refresh_required() ) {
add_action( 'init', array( $this, 'refresh_packages' ), 999, 0 );
$this->set_refresh_not_required();
}
}
}
}
private function add_admin_hooks() {
if ( is_admin() || $this->is_doing_xmlrpc() || wpml_is_rest_request() ) {
add_action( 'wp_ajax_wpml_delete_packages', array( $this, 'delete_packages_ajax' ) );
add_action( 'wp_ajax_wpml_change_package_lang', array( $this, 'change_package_lang_ajax' ) );
/* Core hooks */
add_filter( 'wpml_pt_all_packages', array( $this, 'get_all_packages' ) );
/* Translation hooks for other plugins to use */
add_filter( 'wpml_tm_element_type', array( $this, 'get_element_type' ), 10, 2 );
add_filter( 'wpml_tm_dashboard_title_locations', array( $this, 'add_title_db_location' ), 10, 2 );
add_filter( 'wpml_string_title_from_id', array( $this, 'string_title_from_id_filter' ), 10, 2 );
// TODO: deprecated, use the 'wpml_register_string' action
add_filter( 'WPML_register_string', array( $this, 'register_string_for_translation' ), 10, 5 );
add_action( 'wpml_add_string_translation', array( $this, 'add_string_translation_action' ), 10, 7 );
// TODO: These 3 hooks are deprecated. They are needed for Layouts 1.0. Consider removing them after Layouts 1.2 is released
add_filter( 'WPML_get_translated_strings', array( $this, 'get_translated_strings' ), 10, 2 );
add_action( 'WPML_set_translated_strings', array( $this, 'set_translated_strings' ), 10, 2 );
add_action( 'WPML_show_package_language_ui', array( $this, 'show_language_selector' ), 10, 2 );
add_filter( 'wpml_get_translated_strings', array( $this, 'get_translated_strings' ), 10, 2 );
add_action( 'wpml_set_translated_strings', array( $this, 'set_translated_strings' ), 10, 2 );
add_action( 'wpml_show_package_language_ui', array( $this, 'show_language_selector' ), 10, 2 );
add_action( 'wpml_show_package_language_admin_bar', array( $this, 'show_admin_bar_language_selector' ), 10, 2 );
/* WPML hooks */
add_filter( 'wpml_get_translatable_types', array( $this, 'get_translatable_types' ), 10, 1 );
add_filter( 'wpml_get_translatable_item', array( $this, 'get_translatable_item' ), 10, 3 );
add_filter( 'wpml_external_item_url', array( $this, 'get_package_edit_url' ), 10, 2 );
add_filter( 'wpml_external_item_link', array( $this, 'get_package_edit_link' ), 10, 3 );
add_filter( 'wpml_get_external_item_title', array( $this, 'get_package_title' ), 10, 3 );
add_filter( 'wpml_element_id_from_package', array( $this, 'get_element_id_from_package_filter' ), 10, 2 );
add_filter( 'wpml_get_package_type', array( $this, 'get_package_type' ), 10, 2 );
add_filter( 'wpml_get_package_type_prefix', array( $this, 'get_package_type_prefix' ), 10, 2 );
add_filter( 'wpml_language_for_element', array( $this, 'get_language_for_element' ), 10, 2 );
add_filter( 'wpml_st_get_string_package', array( $this, 'get_string_package' ), 10, 2 );
add_action( 'wpml_save_external', [ $this, 'save_package_translations' ], 10, 3 );
/* Translation queue hooks */
add_filter( 'wpml_tm_external_translation_job_title', array( $this, 'get_post_title' ), 10, 2 );
add_filter( 'wpml_tm_add_to_basket', array( $this, 'add_to_basket' ), 10, 2 );
add_filter( 'wpml_tm_translation_jobs_basket', array( $this, 'update_translation_jobs_basket' ), 10, 3 );
add_filter( 'wpml_tm_basket_items_types', array( $this, 'basket_items_types' ), 10, 2 );
/*
TM Hooks */
// This is called by \TranslationManagement::send_all_jobs - The hook is dynamically built.
add_filter( 'wpml_tm_dashboard_sql', array( $this, 'tm_dashboard_sql_filter' ), 10, 1 );
/* Translation editor hooks */
add_filter( 'wpml_tm_editor_string_name', array( $this, 'get_editor_string_name' ), 10, 2 );
add_filter( 'wpml_tm_editor_string_style', array( $this, 'get_editor_string_style' ), 10, 3 );
/*
API Hooks */
// @deprecated @since 3.2 Use 'wpml_delete_package'
add_action( 'wpml_delete_package_action', array( $this, 'delete_package_action' ), 10, 2 );
add_action( 'deleted_post', array( $this, 'remove_post_packages' ) );
}
}
private function is_doing_xmlrpc() {
return ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST );
}
private function add_global_hooks() {
// TODO: deprecated, use the 'wpml_translate_string' filter
add_filter( 'WPML_translate_string', array( $this, 'translate_string' ), 10, 3 );
add_filter( 'wpml_translate_string', array( $this, 'translate_string' ), 10, 3 );
add_action( 'wpml_register_string', array( $this, 'register_string_action' ), 10, 5 );
add_action( 'wpml_start_string_package_registration', array( $this, 'start_string_package_registration_action' ), 10, 1 );
add_action( 'wpml_delete_unused_package_strings', array( $this, 'delete_unused_package_strings_action' ), 10, 1 );
add_action( 'wpml_delete_package', array( $this, 'delete_package_action' ), 10, 2 );
add_filter( 'wpml_st_get_post_string_packages', array( $this, 'get_post_string_packages' ), 10, 2 );
add_filter( 'wpml_string_id_from_package', array( $this, 'string_id_from_package_filter' ), 10, 4 );
/* API Hooks */
add_filter( 'wpml_is_external', array( $this, 'is_external' ), 10, 2 );
}
private function run_db_update() {
if ( is_admin() ) {
WPML_Package_Translation_Schema::run_update();
}
}
/**
* @return bool
*/
private function passed_dependencies() {
return defined( 'ICL_SITEPRESS_VERSION' )
&& defined( 'WPML_ST_VERSION' )
&& defined( 'WPML_TM_VERSION' );
}
public function add_title_db_location( $locations ) {
global $wpdb;
$locations[ $wpdb->prefix . 'icl_string_packages' ] = array(
'id_column' => 'ID',
'title_column' => 'title',
'element_type_prefix' => 'package',
'date_column' => false,
);
return $locations;
}
function get_package_edit_url( $url, $post_id ) {
$package = new WPML_Package( $post_id );
if ( ! $package ) {
return false;
} //not ours
if ( isset( $package->edit_link ) ) {
$url = $package->edit_link;
}
return $url;
}
public function get_package_title( $title, $kind, $id ) {
$package = new WPML_Package( $id );
if ( ! $package ) {
return $title;
} //not ours
if ( isset( $package->title ) ) {
$title = $package->title;
}
return $title;
}
function get_package_view_link( $link, $post_id, $hide_if_missing_link = false ) {
$package = new WPML_Package( $post_id );
if ( ! $package ) {
return $link;
} //not ours
return $this->build_package_link( $package->view_link, $package->title, $hide_if_missing_link );
}
function get_package_edit_link( $link, $post_id, $hide_if_missing_link = false ) {
$package = new WPML_Package( $post_id );
if ( ! $package ) {
return $link;
} //not ours
return $this->build_package_link( $package->edit_link, esc_html( $package->title ), $hide_if_missing_link );
}
private function build_package_link( $url, $title, $hide_if_missing_link = false ) {
$link = '<a href="' . $url . '">' . $title . '</a>';
if ( false === $hide_if_missing_link ) {
if ( ! $url ) {
$link = $title;
}
} elseif ( ! $url ) {
$link = '';
}
return $link;
}
/**
* @param stdClass|WPML_Package|array|int $package
* @param array<string,mixed> $args
*/
function show_language_selector( $package, $args = array() ) {
global $wpdb, $sitepress;
$wpml_pt_meta = new WPML_Package_Translation_Metabox( $package, $wpdb, $sitepress, $args );
echo $wpml_pt_meta->get_metabox();
}
/**
* @param stdClass|WPML_Package|array|int $package
* @param array<string,mixed> $args
*/
function show_admin_bar_language_selector( $package, $args = array() ) {
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-admin-lang-switcher.class.php';
$this->admin_lang_switcher = new WPML_Package_Admin_Lang_Switcher( $package, $args );
}
function cleanup_translation_jobs_basket_packages( $translation_jobs_basket ) {
if ( empty( $translation_jobs_basket['packages'] ) ) {
return;
}
foreach ( $translation_jobs_basket['packages'] as $id => $data ) {
if ( ! new WPML_Package( $id ) ) {
TranslationProxy_Basket::delete_item_from_basket( $id );
}
}
}
public function update_translation_jobs_basket( $translation_jobs_cart, $translation_jobs_basket, $item_type ) {
if ( $item_type == 'package' ) {
if ( ! isset( $translation_jobs_basket[ $item_type ] ) ) {
return false;
}
$packages = $translation_jobs_basket[ $item_type ];
if ( empty( $packages ) ) {
return false;
}
$this->cleanup_translation_jobs_basket_packages( $translation_jobs_basket );
global $sitepress;
$packages_ids = array_keys( $packages );
foreach ( $packages_ids as $package_id ) {
$package = new WPML_Package( $package_id );
if ( $package ) {
if ( ! isset( $package->ID ) || ! $package->ID ) {
TranslationProxy_Basket::delete_item_from_basket( $package_id, 'package' );
continue;
}
$package_source_language = $packages[ $package_id ]['from_lang'];
$package_target_languages = $packages[ $package_id ]['to_langs'];
$language_names = $this->languages_to_csv( $package_target_languages );
$final_post = array();
$final_post['post_title'] = $package->title;
$final_post['post_notes'] = get_post_meta( $package->ID, '_icl_translator_note', true );
$final_post['post_type'] = $package->kind;
if ( isset( $package->post_status ) ) {
$final_post['post_status'] = $package->post_status;
}
if ( isset( $package->post_date ) ) {
$final_post['post_date'] = $package->post_date;
}
$final_post['from_lang'] = $package_source_language;
$final_post['from_lang_string'] = ucfirst( $sitepress->get_display_language_name( $package_source_language, $sitepress->get_admin_language() ) );
$final_post['to_langs'] = $package_target_languages;
$final_post['to_langs_string'] = implode( ', ', $language_names );
$translation_jobs_cart[ $package_id ] = $final_post;
}
}
}
return $translation_jobs_cart;
}
public function basket_items_types( $item_types ) {
$item_types['package'] = 'custom';
return $item_types;
}
/**
* @param array<string,string> $package_target_languages
*
* @return array<string>
*/
private function languages_to_csv( $package_target_languages ) {
global $sitepress;
$language_names = array();
foreach ( $package_target_languages as $language_code => $value ) {
$language_names[] = ucfirst( $sitepress->get_display_language_name( $language_code, $sitepress->get_admin_language() ) );
}
return $language_names;
}
function is_external( $result, $type ) {
return $result || is_a( $type, 'WPML_Package' ) || $type == 'package';
}
public function get_element_type( $type, $element ) {
if ( $this->is_a_package( $element ) ) {
$type = 'package';
}
return $type;
}
/**
* @param array<string,string> $attributes
*
* @return string
*/
public function attributes_to_string( $attributes ) {
$result = '';
foreach ( $attributes as $key => $value ) {
if ( $result ) {
$result .= ' ';
}
$result .= esc_html( $key ) . '="' . esc_attr( $value ) . '"';
}
return $result;
}
/**
* @param string $kind_slug
*
* @return string
*/
public static function get_package_element_type( $kind_slug ) {
if ( is_object( $kind_slug ) ) {
$kind_slug = $kind_slug->kind_slug;
}
if ( is_array( $kind_slug ) ) {
$kind_slug = $kind_slug['kind_slug'];
}
return 'package_' . $kind_slug;
}
/**
* @param array<string,string> $package
*
* @return bool
*/
public function package_has_kind( $package ) {
return isset( $package['kind'] ) && $package['kind'];
}
/**
* @param array<string,string> $package
*
* @return bool
*/
public function package_has_name( $package ) {
return isset( $package['name'] ) && $package['name'];
}
/**
* @param array<string,string> $package
*
* @return bool
*/
public function package_has_title( $package ) {
return isset( $package['title'] ) && $package['title'];
}
/**
* @param array<string,string> $package
*
* @return bool
*/
public function package_has_kind_and_name( $package ) {
return $this->package_has_kind( $package ) && $this->package_has_name( $package );
}
/**
* @param string $string_name
*
* @return mixed
*/
public function sanitize_string_with_underscores( $string_name ) {
return preg_replace( '/[ \[\]]+/', '_', $string_name );
}
function new_external_item( $type, $package_item, $get_string_data = false ) {
// create a new external item for the Translation Dashboard or for translation jobs
$package_id = $package_item['ID'];
$item = new stdClass();
$item->external_type = true;
$item->type = $type;
$item->ID = $package_id;
$item->post_type = $type;
$item->post_id = 'external_' . $item->post_type . '_' . $package_item['ID'];
$item->post_date = '';
$item->post_status = __( 'Active', 'wpml-string-translation' );
$item->post_title = $package_item['title'];
$item->is_translation = false;
if ( $get_string_data ) {
$item->string_data = $this->_get_package_strings( $package_item );
}
return $item;
}
function get_package_from_external_id( $post_id ) {
global $wpdb;
$packages = $wpdb->get_col( "SELECT ID FROM {$wpdb->prefix}icl_string_packages WHERE ID>0" );
foreach ( $packages as $package_id ) {
$package = new WPML_Package( $package_id );
$test = $this->get_external_id_from_package( $package );
if ( is_string( $post_id ) && $post_id == $test ) {
return $package;
}
}
return false; // not a package type
}
function _get_package_strings( $package_item ) {
global $wpdb;
$strings = array();
$package_item_id = $package_item['ID'];
$results = $wpdb->get_results( $wpdb->prepare( "SELECT name, value FROM {$wpdb->prefix}icl_strings WHERE string_package_id=%d", $package_item_id ) );
foreach ( $results as $result ) {
$string_name = (bool) $package_item_id === true && strpos(
$result->name,
(string) $package_item_id
) === 0
? substr( $result->name, strlen( $package_item_id ) + 1 ) : $result->name;
$strings[ $string_name ] = $result->value;
}
// Add/update any registered strings
if ( isset( $this->registered_strings[ $package_item_id ]['strings'] ) ) {
foreach ( $this->registered_strings[ $package_item_id ]['strings'] as $id => $string_data ) {
$strings[ $id ] = $string_data['value'];
}
}
return $strings;
}
function get_link( $item, $package_item, $anchor, $hide_empty ) {
if ( $item == '' ) {
$package_item = $this->get_package_from_external_id( $package_item );
if ( ! $package_item ) {
return '';
}
$has_link = isset( $package_item->edit_link ) && $package_item->edit_link;
if ( false === $anchor ) {
if ( $has_link ) {
$anchor = '<a href="' . $package_item->edit_link . '">' . $package_item['title'] . '</a>';
} elseif ( ! $hide_empty ) {
$anchor = $package_item['title'];
}
} else {
if ( $has_link ) {
$anchor = '<a href="' . $package_item['edit_link'] . '">' . $anchor . '</a>';
}
}
$item = $anchor;
}
return $item;
}
/**
* Update translations
*
* @param int $package_id
* @param bool $is_new - set to true for newly created form (first save without fields)
* @param bool $needs_update - when deleting single field we do not need to change the translation status of the form
*
* @internal param array $item - package information
*/
function update_package_translations( $package_id, $is_new, $needs_update = true ) {
global $sitepress, $wpdb, $iclTranslationManagement;
$item = $this->get_package_details( $package_id );
$post_id = $this->get_external_id_from_package( new WPML_Package( $package_id ) );
$post = $this->get_translatable_item( null, $post_id );
if ( ! $post ) {
return;
}
$default_lang = $sitepress->get_default_language();
$icl_el_type = $this->get_package_element_type( $item );
$trid = $sitepress->get_element_trid( $item['ID'], $icl_el_type );
if ( $is_new ) {
$sitepress->set_element_language_details( $post->ID, $icl_el_type, false, $default_lang, null, false );
// for new package nothing more to do
return;
}
$sql = "
SELECT t.translation_id, s.md5
FROM {$wpdb->prefix}icl_translations t
NATURAL JOIN {$wpdb->prefix}icl_translation_status s
WHERE t.trid=%d
AND t.source_language_code IS NOT NULL
";
$element_translations = $wpdb->get_results( $wpdb->prepare( $sql, $trid ) );
if ( ! empty( $element_translations ) ) {
$md5 = $iclTranslationManagement->post_md5( $post );
if ( $md5 != $element_translations[0]->md5 ) { // all translations need update
$translation_package = $iclTranslationManagement->create_translation_package( $post );
foreach ( $element_translations as $trans ) {
$_prevstate = $wpdb->get_row(
$wpdb->prepare(
"
SELECT status, translator_id, needs_update, md5, translation_service, translation_package, timestamp, links_fixed
FROM {$wpdb->prefix}icl_translation_status
WHERE translation_id = %d
",
$trans->translation_id
),
ARRAY_A
);
if ( ! empty( $_prevstate ) ) {
$data['_prevstate'] = serialize( $_prevstate );
}
$data = array(
'translation_id' => $trans->translation_id,
'translation_package' => serialize( $translation_package ),
'md5' => $md5,
);
// update only when something changed (we do not need to change status when deleting a field)
if ( $needs_update ) {
$data['needs_update'] = 1;
}
$update_result = $iclTranslationManagement->update_translation_status( $data );
$rid = $update_result[0];
$this->update_icl_translate( $rid, $post );
// change job status only when needs update
if ( $needs_update ) {
$job_id = $wpdb->get_var( $wpdb->prepare( "SELECT MAX(job_id) FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d GROUP BY rid", $rid ) );
if ( $job_id ) {
$wpdb->update( "{$wpdb->prefix}icl_translate_job", array( 'translated' => 0 ), array( 'job_id' => $job_id ), array( '%d' ), array( '%d' ) );
}
}
}
}
}
}
/**
* Functions to update translations when packages are modified in admin
*
* @param int $rid
* @param \stdClass $post
*/
function update_icl_translate( $rid, $post ) {
global $wpdb;
$job_id = $wpdb->get_var( $wpdb->prepare( "SELECT MAX(job_id) FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d GROUP BY rid", $rid ) );
$elements = $wpdb->get_results(
$wpdb->prepare(
"SELECT field_type, field_data, tid, field_translate FROM {$wpdb->prefix}icl_translate
WHERE job_id=%d",
$job_id
),
OBJECT_K
);
foreach ( $post->string_data as $field_type => $field_value ) {
$field_data = base64_encode( $field_value );
if ( ! isset( $elements[ $field_type ] ) ) {
// insert new field
$data = array(
'job_id' => $job_id,
'content_id' => 0,
'field_type' => $field_type,
'field_format' => 'base64',
'field_translate' => 1,
'field_data' => $field_data,
'field_data_translated' => 0,
'field_finished' => 0,
);
$wpdb->insert( $wpdb->prefix . 'icl_translate', $data );
} elseif ( $elements[ $field_type ]->field_data != $field_data ) {
// update field value
$wpdb->update(
$wpdb->prefix . 'icl_translate',
array(
'field_data' => $field_data,
'field_finished' => 0,
),
array( 'tid' => $elements[ $field_type ]->tid )
);
}
}
foreach ( $elements as $field_type => $el ) {
// delete fields that are no longer present
if ( $el->field_translate && ! isset( $post->string_data[ $field_type ] ) ) {
$wpdb->delete( $wpdb->prefix . 'icl_translate', array( 'tid' => $el->tid ), array( '%d' ) );
}
}
}
private function get_package_details( $package_id ) {
global $wpdb;
static $cache = array();
if ( ! isset( $cache[ $package_id ] ) ) {
$item = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}icl_string_packages WHERE ID=%d", $package_id ), ARRAY_A );
$cache[ $package_id ] = $item;
}
return $cache[ $package_id ];
}
function get_string_context_title( $context, $string_details ) {
global $wpdb;
static $cache = array();
if ( ! isset( $cache[ $context ] ) ) {
$package_id = $wpdb->get_var( $wpdb->prepare( "SELECT string_package_id FROM {$wpdb->prefix}icl_strings WHERE id=%d", $string_details['string_id'] ) );
if ( $package_id ) {
$package_details = $this->get_package_details( $package_id );
if ( $package_details ) {
$cache[ $context ] = $package_details->kind . ' - ' . $package_details->title;
} else {
$cache[ $context ] = $context;
}
} else {
$cache[ $context ] = $context;
}
}
return $cache[ $context ];
}
function get_string_title( $title, $string_details ) {
global $wpdb;
$string_title = $wpdb->get_var( $wpdb->prepare( "SELECT title FROM {$wpdb->prefix}icl_strings WHERE id=%d", $string_details['string_id'] ) );
if ( $string_title ) {
return $string_title;
} else {
return $title;
}
}
function _get_post_translations( $package ) {
global $sitepress;
if ( is_object( $package ) ) {
$package = get_object_vars( $package );
}
$element_type = $this->get_package_element_type( $package['kind_slug'] );
$trid = $sitepress->get_element_trid( $package['ID'], $element_type );
return $sitepress->get_element_translations( $trid, $element_type );
}
function _is_translation_in_progress( $package ) {
global $wpdb;
$post_translations = self::_get_post_translations( $package );
foreach ( $post_translations as $lang => $translation ) {
$res = $wpdb->get_row( $wpdb->prepare( "SELECT status, needs_update, md5 FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d", $translation->translation_id ) );
if ( $res && $res->status == ICL_TM_IN_PROGRESS ) {
return true;
}
}
return false;
}
function _delete_translation_job( $package_id ) {
global $wpdb;
$package = $this->get_package_details( $package_id );
$post_translations = $this->_get_post_translations( $package );
foreach ( $post_translations as $lang => $translation ) {
$rid = $wpdb->get_var( $wpdb->prepare( "SELECT rid FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d", $translation->translation_id ) );
if ( $rid ) {
$job_id = $wpdb->get_var( $wpdb->prepare( "SELECT job_id FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d", $rid ) );
if ( $job_id ) {
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}icl_translate_job WHERE job_id=%d", $job_id ) );
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}icl_translate WHERE job_id=%d", $job_id ) );
}
}
}
}
public function add_to_basket( $data ) {
if ( isset( $data['tr_action'] ) ) {
$posts_ids = TranslationProxy_Basket::get_elements_ids( $data, 'package' );
foreach ( $posts_ids as $id ) {
$post_id = $id;
$source_language = $data['translate_from'];
$target_languages = $data['tr_action'];
foreach ( $target_languages as $translate_to => $translation_action ) {
$package = new WPML_Package( $post_id );
$tm = new WPML_Package_TM( $package );
$tm->add_package_to_basket( $translation_action, $source_language, $translate_to );
}
}
}
}
function _no_wpml_warning() {
?>
<div class="message error">
<p>
<?php printf( __( 'WPML Package Translation is enabled but not effective. It requires <a href="%s">WPML</a>, String Translation and Translation Management in order to work.', 'wpml-string-translation' ), 'http://wpml.org/' ); ?>
</p>
</div>
<?php
}
public function tm_dashboard_sql_filter( $sql ) {
global $wpdb;
$sql .= " AND i.element_id NOT IN ( SELECT ID FROM {$wpdb->prefix}icl_string_packages WHERE post_id IS NOT NULL AND element_type = 'package_layout' )";
return $sql;
}
/**
* @return bool
*/
private function is_refresh_required() {
$refresh_required = get_option( 'wpml-package-translation-refresh-required', 'yes' );
return 'yes' === $refresh_required || '1' === $refresh_required;
}
private function set_refresh_not_required() {
update_option( 'wpml-package-translation-refresh-required', 'no', false );
}
public function save_package_translations( $element_type_prefix, $job, $decoder ) {
if ( $element_type_prefix === 'package' ) {
$element_type_prefix = $this->get_package_type_prefix( $element_type_prefix, $job->original_doc_id );
foreach ( $job->elements as $field ) {
if ( $field->field_translate ) {
$string_id = icl_st_is_registered_string( $element_type_prefix, $field->field_type );
if ( ! $string_id ) {
icl_register_string( $element_type_prefix, $field->field_type, $decoder( $field->field_data, $field->field_format ) );
$string_id = icl_st_is_registered_string( $element_type_prefix, $field->field_type );
}
if ( $string_id ) {
icl_add_string_translation( $string_id, $job->language_code, $decoder( $field->field_data_translated, $field->field_format ), ICL_TM_COMPLETE );
}
}
}
}
}
}

View File

@@ -0,0 +1,537 @@
<?php
class WPML_Package {
const CACHE_GROUP = 'WPML_Package';
public $ID;
public $view_link;
public $edit_link;
public $is_translation;
public $string_data;
public $title;
public $new_title;
public $kind_slug;
public $kind;
public $trid;
public $name;
public $translation_element_type;
public $post_id;
private $element_type_prefix;
/**
* @param stdClass|WPML_Package|array|int $data_item
*/
function __construct( $data_item ) {
$this->element_type_prefix = 'package';
$this->view_link = '';
$this->edit_link = '';
$this->post_id = null;
if ( $data_item ) {
if ( is_object( $data_item ) ) {
$data_item = get_object_vars( $data_item );
}
if ( is_numeric( $data_item ) ) {
$data_item = $this->init_from_id( $data_item, ARRAY_A );
}
if ( isset( $data_item['title'] ) ) {
$this->new_title = $data_item['title'];
}
if ( $data_item && is_array( $data_item ) ) {
$this->init_from_array( $data_item );
}
$this->new_title = $this->new_title != $this->title ? $this->new_title : null;
}
}
private function init_from_id( $id, $output = OBJECT ) {
global $wpdb;
$packages_query = "SELECT * FROM {$wpdb->prefix}icl_string_packages WHERE id=%s";
$packages_prepared = $wpdb->prepare( $packages_query, $id );
$package = $wpdb->get_row( $packages_prepared, $output );
return $package;
}
public function __get( $property ) {
if ( $property == 'id' ) {
_deprecated_argument( 'id', '0.0.2', "Property 'id' is deprecated. Please use 'ID'." );
return $this->ID;
}
if ( $property == 'post_id' ) {
return $this->ID;
}
if ( $property == 'post_title' ) {
return $this->title;
}
if ( $property == 'post_type' ) {
return $this->kind_slug;
}
return null;
}
public function __set( $property, $value ) {
if ( $property == 'id' ) {
_deprecated_argument( 'id', '0.0.2', "Property 'id' is deprecated. Please use 'ID'." );
$this->ID = $value;
} else {
$this->$property = $value;
}
}
public function __isset( $property ) {
if ( $property == 'id' ) {
return isset( $this->ID );
}
return false;
}
public function __unset( $property ) {
if ( $property == 'id' ) {
unset( $this->$property );
}
}
public function get_translation_element_type() {
return $this->translation_element_type;
}
public function get_package_post_id() {
return $this->get_element_type_prefix() . '_' . $this->kind_slug . '_' . $this->ID;
}
public function get_element_type_prefix() {
return $this->element_type_prefix;
}
public function set_package_post_data() {
$this->translation_element_type = $this->element_type_prefix . '_' . $this->kind_slug;
$this->update_strings_data();
}
public function update_strings_data() {
$strings = [];
$package_id = $this->ID;
if ( $package_id ) {
$results = $this->get_package_strings();
foreach ( $results as $result ) {
$string_name = $this->get_package_string_name_from_st_name( $result );
$strings[ $string_name ] = $result->value;
}
$this->string_data = $strings;
}
}
/**
* @param bool $refresh
*
* @return mixed
*/
public function get_package_strings( $refresh = false ) {
global $wpdb;
$package_id = $this->ID;
$results = false;
if ( $package_id ) {
$cache = new WPML_WP_Cache( self::CACHE_GROUP );
$cache_key = 'strings:' . $package_id;
$found = false;
$results = $cache->get( $cache_key, $found );
if ( ! $found || $refresh ) {
$results_query = "
SELECT id, name, value, wrap_tag, type, title
FROM {$wpdb->prefix}icl_strings
WHERE string_package_id=%d
ORDER BY location, id ASC";
$results_prepare = $wpdb->prepare( $results_query, $package_id );
$results = $wpdb->get_results( $results_prepare );
$cache->set( $cache_key, $results );
}
}
return $results;
}
public function set_strings_language( $language_code ) {
global $wpdb;
$package_id = $this->ID;
if ( $package_id ) {
$update_query = "UPDATE {$wpdb->prefix}icl_strings SET language=%s WHERE string_package_id=%d";
$update_prepare = $wpdb->prepare( $update_query, $language_code, $package_id );
$wpdb->query( $update_prepare );
}
}
/**
* @param \stdClass $result
*
* @return string
*/
private function get_package_string_name_from_st_name( $result ) {
// package string name is the same as the string name.
return $result->name;
}
private function sanitize_attributes() {
if ( isset( $this->name ) ) {
$this->name = $this->sanitize_string_name( $this->name );
}
if ( ( ! isset( $this->title ) || $this->title === '' ) && isset( $this->name ) ) {
$this->title = $this->name;
}
if ( ! isset( $this->edit_link ) ) {
$this->edit_link = '';
}
$this->sanitize_kind();
}
public function create_new_package_record() {
$this->sanitize_attributes();
$package_id = $this->package_exists();
if ( ! $package_id ) {
global $wpdb;
$data = array(
'kind_slug' => $this->kind_slug,
'kind' => $this->kind,
'name' => $this->name,
'title' => $this->title,
'edit_link' => $this->edit_link,
'view_link' => $this->view_link,
'post_id' => $this->post_id,
);
$wpdb->insert( $wpdb->prefix . 'icl_string_packages', $data );
$package_id = $wpdb->insert_id;
$this->ID = $package_id;
}
return $package_id;
}
public function update_package_record() {
$result = false;
if ( $this->ID ) {
global $wpdb;
$update_data = array(
'kind_slug' => $this->kind_slug,
'kind' => $this->kind,
'name' => $this->name,
'title' => $this->title,
'edit_link' => $this->edit_link,
'view_link' => $this->view_link,
);
$update_where = array(
'ID' => $this->ID,
);
$result = $wpdb->update( $wpdb->prefix . 'icl_string_packages', $update_data, $update_where );
}
return $result;
}
public function get_package_id() {
return $this->ID;
}
public function sanitize_string_name( $string_name ) {
$string_name = preg_replace( '/[ \[\]]+/', '-', $string_name );
return $string_name;
}
function translate_string( $string_value, $sanitized_string_name ) {
$package_id = $this->get_package_id();
if ( $package_id ) {
$sanitized_string_name = $this->sanitize_string_name( $sanitized_string_name );
$string_context = $this->get_string_context_from_package();
$string_name = $sanitized_string_name;
return icl_translate( $string_context, $string_name, $string_value );
} else {
return $string_value;
}
}
function get_string_context_from_package() {
return $this->kind_slug . '-' . $this->name;
}
public function get_string_id_from_package( $string_name, $string_value ) {
$package_id = $this->get_package_id();
$string_context = $this->get_string_context_from_package();
$string_data = array(
'context' => $string_context,
'name' => $string_name,
);
/**
* @param int|null $default
* @param array $string_data {
*
* @type string $context
* @type string $name Optional
* }
*/
$string_id = apply_filters( 'wpml_string_id', null, $string_data );
if ( ! $string_id ) {
$string_id = icl_register_string( $string_context, $string_name, $string_value, null, $this->get_package_language() );
}
return $string_id;
}
function get_translated_strings( $strings ) {
$package_id = $this->get_package_id();
if ( $package_id ) {
$results = $this->get_package_strings();
foreach ( $results as $result ) {
$translations = icl_get_string_translations_by_id( $result->id );
if ( ! empty( $translations ) ) {
$string_name = $this->get_package_string_name_from_st_name( $result );
$strings[ $string_name ] = $translations;
}
}
}
return $strings;
}
function set_translated_strings( $translations ) {
global $wpdb;
$this->sanitize_attributes();
$package_id = $this->get_package_id();
if ( $package_id ) {
foreach ( $translations as $string_name => $languages ) {
$string_id_query = "SELECT id FROM {$wpdb->prefix}icl_strings WHERE name='%s'";
$string_id_prepare = $wpdb->prepare( $string_id_query, $string_name );
$string_id = $wpdb->get_var( $string_id_prepare );
foreach ( $languages as $language_code => $language_data ) {
icl_add_string_translation( $string_id, $language_code, $language_data['value'], $language_data['status'] );
}
}
}
}
private function init_from_array( $args ) {
foreach ( $args as $key => $value ) {
if ( 'id' == $key ) {
$key = 'ID';
}
$this->$key = $value;
}
$this->sanitize_attributes();
if ( $this->package_id_exists() || $this->package_name_and_kind_exists() ) {
$this->set_package_from_db();
}
$this->set_package_post_data();
}
public function has_kind_and_name() {
return ( isset( $this->kind ) && isset( $this->name ) && $this->kind && $this->name );
}
private function set_package_from_db() {
$package = false;
if ( $this->package_id_exists() ) {
$package = $this->get_package_from_id();
} elseif ( $this->package_name_and_kind_exists() ) {
$package = $this->get_package_from_name_and_kind();
}
if ( $package ) {
$this->object_to_package( $package );
}
$this->sanitize_kind();
}
private function get_package_from_id() {
$result = false;
if ( $this->has_id() ) {
global $wpdb;
$package_query = "SELECT * FROM {$wpdb->prefix}icl_string_packages WHERE ID=%d";
$package_prepared = $wpdb->prepare( $package_query, array( $this->ID ) );
$result = $wpdb->get_row( $package_prepared );
}
return $result;
}
private function get_package_from_name_and_kind() {
global $wpdb;
$cache = new WPML_WP_Cache( self::CACHE_GROUP );
$cache_key = 'name-kind:' . $this->kind_slug . $this->name;
$found = false;
$result = $cache->get( $cache_key, $found );
if ( ! $found ) {
$package_query = "SELECT * FROM {$wpdb->prefix}icl_string_packages WHERE kind_slug=%s AND name=%s";
$package_prepared = $wpdb->prepare( $package_query, array( $this->kind_slug, $this->name ) );
$result = $wpdb->get_row( $package_prepared );
if ( $result ) {
$cache->set( $cache_key, $result );
}
}
return $result;
}
private function package_name_and_kind_exists() {
$result = false;
if ( $this->has_kind_and_name() ) {
$result = (bool) $this->get_package_from_name_and_kind();
}
return $result;
}
private function package_id_exists() {
$result = false;
if ( $this->has_id() ) {
global $wpdb;
$package_query = "SELECT ID FROM {$wpdb->prefix}icl_string_packages WHERE ID=%d";
$package_prepared = $wpdb->prepare( $package_query, array( $this->ID ) );
$result = $wpdb->get_var( $package_prepared );
}
return $result;
}
/**
* @return bool|mixed
*/
protected function package_exists() {
$existing_package = false;
if ( $this->has_id() ) {
$existing_package = $this->package_id_exists();
} elseif ( $this->has_kind_and_name() ) {
$existing_package = $this->package_name_and_kind_exists();
}
return $existing_package;
}
/**
* @return bool
*/
private function has_id() {
return isset( $this->ID ) && $this->ID;
}
/**
* @param \stdClass $package
*/
private function object_to_package( $package ) {
$this->ID = $package->ID;
$this->kind_slug = $package->kind_slug;
$this->kind = $package->kind;
$this->name = $package->name;
$this->title = $package->title;
$this->edit_link = $package->edit_link;
$this->view_link = $package->view_link;
}
private function get_kind_from_slug() {
global $wpdb;
if ( $this->kind_slug ) {
$kinds_query = "SELECT kind FROM {$wpdb->prefix}icl_string_packages WHERE kind_slug=%s GROUP BY kind";
$kinds_prepared = $wpdb->prepare( $kinds_query, $this->kind_slug );
$kinds = $wpdb->get_col( $kinds_prepared );
if ( count( $kinds ) > 1 ) {
throw new WPML_Package_Exception( 'error', 'Package contains multiple kinds' );
}
if ( $kinds ) {
return $kinds[0];
}
}
return null;
}
private function sanitize_kind() {
if ( isset( $this->kind ) && ( ! isset( $this->kind_slug ) || trim( $this->kind_slug ) === '' ) ) {
$this->kind_slug = sanitize_title_with_dashes( $this->kind );
}
if ( $this->kind == $this->kind_slug ) {
$this->kind = $this->get_kind_from_slug();
}
}
public function get_package_element_type() {
return 'package_' . $this->kind_slug;
}
/**
* @return string|null
*/
public function get_package_language() {
global $sitepress;
if ( $this->post_id ) {
$details = null;
$post = get_post( $this->post_id );
if ( $post ) {
$details = $sitepress->get_element_language_details( $this->post_id, 'post_' . $post->post_type );
}
} else {
$element_type = $this->get_package_element_type();
$details = $sitepress->get_element_language_details( $this->ID, $element_type );
}
if ( $details ) {
return $details->language_code;
} else {
return null;
}
}
public function are_all_strings_included( $strings ) {
// check to see if all the strings in this package are present in $strings
$package_strings = $this->get_package_strings();
if ( is_array( $package_strings ) ) {
foreach ( $package_strings as $string ) {
if ( ! in_array( $string->id, $strings ) ) {
return false;
}
}
}
return true;
}
public function flush_cache() {
$cache = new WPML_WP_Cache( self::CACHE_GROUP );
$cache->flush_group_cache();
}
}

View File

@@ -0,0 +1,113 @@
/*globals jQuery, ajaxurl*/
/*jshint browser:true, devel:true*/
var WPML_Package_Translation = WPML_Package_Translation || {};
(function () {
"use strict";
WPML_Package_Translation.ManagementPage = function () {
var self = this;
self.init = function () {
jQuery('.js_package_all_cb').on('change', self.check_uncheck_all);
jQuery('.js_package_row_cb').on('change', self.enable_disable_delete);
jQuery('#delete_packages').on('click', self.delete_selected_packages);
jQuery('#package_kind_filter').on('change', self.filter_by_kind);
};
self.check_uncheck_all = function () {
var package_all_cb = jQuery('.js_package_all_cb').first();
var checked = package_all_cb.prop('checked');
jQuery('.js_package_row_cb').each(
function () {
if (!jQuery(this).is(':disabled')) {
jQuery(this).prop('checked', checked);
}
}
);
self.enable_disable_delete();
};
self.enable_disable_delete = function () {
var enable = jQuery('.js_package_row_cb:checked:visible').length !== 0;
jQuery('#delete_packages').prop('disabled', !enable);
};
self.delete_selected_packages = function () {
if (confirm(jQuery('.js-delete-confirm-message').html())) {
jQuery('#delete_packages').prop('disabled', true);
jQuery('.spinner').css( 'float', 'none' ).addClass( 'is-active' );
var selected = jQuery('.js_package_row_cb:checked:visible');
var packages = [];
selected.each(
function () {
packages.push(jQuery(this).val());
}
);
var data = {
action: 'wpml_delete_packages',
wpnonce: jQuery('#wpml_package_nonce').attr('value'),
packages: packages
};
jQuery.ajax(
{
url: ajaxurl,
type: 'post',
data: data,
success: function () {
selected.each(
function () {
var package_row = jQuery(this).closest('.js_package');
package_row.fadeOut(
1000, function () {
jQuery(this).remove();
}
);
}
);
jQuery('.spinner').removeClass( 'is-active' );
}
}
);
}
};
self.all_selected = function () {
var kind_slug = jQuery('#package_kind_filter').val();
return kind_slug === '-1';
};
self.filter_by_kind = function () {
var kind_slug = jQuery('#package_kind_filter').val();
var icl_package_translations = jQuery('#icl_package_translations');
var icl_package_translations_body = icl_package_translations.find('tbody');
if (self.all_selected()) {
icl_package_translations_body.find('tr').show();
} else {
icl_package_translations_body.find('tr').hide();
icl_package_translations_body.find('tr.js_package.js_package_' + kind_slug).show();
}
self.enable_disable_delete();
};
self.init();
};
jQuery(
function () {
WPML_Package_Translation.management_page = new WPML_Package_Translation.ManagementPage();
}
);
}());

View File

@@ -0,0 +1,30 @@
<?php
/*
WPML Package Translation
This is now part of String Translation.
*/
if ( defined( 'WPML_PACKAGE_TRANSLATION' ) ) {
return;
}
define( 'WPML_PACKAGE_TRANSLATION', '0.0.2' );
define( 'WPML_PACKAGE_TRANSLATION_PATH', dirname( __FILE__ ) );
define( 'WPML_PACKAGE_TRANSLATION_URL', WPML_ST_URL . '/inc/' . basename( WPML_PACKAGE_TRANSLATION_PATH ) );
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-constants.php';
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-exception.class.php';
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-helper.class.php';
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-ui.class.php';
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-html-packages.class.php';
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-metabox.class.php';
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-st.class.php';
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-tm-jobs.class.php';
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation-tm.class.php';
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package.class.php';
require WPML_PACKAGE_TRANSLATION_PATH . '/inc/wpml-package-translation.class.php';
$WPML_package_translation = new WPML_Package_Translation();
$WPML_Package_Translation_UI = new WPML_Package_Translation_UI();
$WPML_Package_Translation_HTML_Packages = new WPML_Package_Translation_HTML_Packages();